diff --git a/.env.dev b/.env.dev index ab9444b6..24329a0f 100644 --- a/.env.dev +++ b/.env.dev @@ -1,4 +1,5 @@ KEEN_PROJECT_ID="5b6d8594c9e77c0001e7c578" KEEN_WRITE_KEY="07C0249B9640D2DD31A8BBB7281D319122C4A5AB37E7731EA6090C43526EC76CB79000C7CC2E5420B6AFB9B00444C21FE91C35932BAEA53DF02A84C1B0BA30E477192920F03DE51F116861313700BDF9323E0C16B3A74933A4B04D24A78EEBCA" KEEN_READ_KEY="86A450B303F3E14661589C48EAD1D54997D0166F8B5F9D9774034BE6165FCB5FB69D6A62D739E1B5F57AAA42FC83E8832549C738268612C90A228124D31E5F406E0E8CF73B770ED120132D422031466F2AB25965A437D61D7275499C0EEA67A6" -NOMICS_API_KEY="c13b3d7a7c837cab121a749c7824b162" \ No newline at end of file +NOMICS_API_KEY="c13b3d7a7c837cab121a749c7824b162" +CRYPTO_KITTIES_API_KEY="jM7HYCDKABweBJlWNE29QSkDyD4-HK4ypx__2Qw7xzg" \ No newline at end of file diff --git a/.env.prod b/.env.prod index ab9444b6..24329a0f 100644 --- a/.env.prod +++ b/.env.prod @@ -1,4 +1,5 @@ KEEN_PROJECT_ID="5b6d8594c9e77c0001e7c578" KEEN_WRITE_KEY="07C0249B9640D2DD31A8BBB7281D319122C4A5AB37E7731EA6090C43526EC76CB79000C7CC2E5420B6AFB9B00444C21FE91C35932BAEA53DF02A84C1B0BA30E477192920F03DE51F116861313700BDF9323E0C16B3A74933A4B04D24A78EEBCA" KEEN_READ_KEY="86A450B303F3E14661589C48EAD1D54997D0166F8B5F9D9774034BE6165FCB5FB69D6A62D739E1B5F57AAA42FC83E8832549C738268612C90A228124D31E5F406E0E8CF73B770ED120132D422031466F2AB25965A437D61D7275499C0EEA67A6" -NOMICS_API_KEY="c13b3d7a7c837cab121a749c7824b162" \ No newline at end of file +NOMICS_API_KEY="c13b3d7a7c837cab121a749c7824b162" +CRYPTO_KITTIES_API_KEY="jM7HYCDKABweBJlWNE29QSkDyD4-HK4ypx__2Qw7xzg" \ No newline at end of file diff --git a/__tests__/__snapshots__/SidePanel.unit.test.js.snap b/__tests__/__snapshots__/SidePanel.unit.test.js.snap index b34158ea..5f364d11 100644 --- a/__tests__/__snapshots__/SidePanel.unit.test.js.snap +++ b/__tests__/__snapshots__/SidePanel.unit.test.js.snap @@ -142,6 +142,46 @@ exports[`SidePanel is correctly rendered 1`] = ` +
  • + + + Automate + + + + + +
  • +
  • + + + Automate Zapier + + + + + +
  • +
  • + + * Some data provided by Nomics.com + + + Cryptocurrency Market Data API + + +
  • + ); + } + + if (tokenName) { + return ( + + {tokenName} (NFT-ERC721) with id: {collectibleId} + + ); + } + + return NFT-ERC721 with id: {collectibleId}; + } +} + +CollectibleDisplay.propTypes = { + collectibleId: PropTypes.any, + onlyText: PropTypes.any, + tokenAddress: PropTypes.any, + tokenHelper: PropTypes.any, + tokenName: PropTypes.any +}; + +export default CollectibleDisplay; diff --git a/app/components/Header/Header.js b/app/components/Header/Header.js index b6b93904..e8cf2492 100644 --- a/app/components/Header/Header.js +++ b/app/components/Header/Header.js @@ -99,17 +99,14 @@ class Header extends Component { Transferred: - + {eacStore.totalEthTransferred !== null ? ( `${eacStore.totalEthTransferred} ETH` ) : ( )} {eacStore.totalUsdTransferred !== null && - ` (${eacStore.getFormattedUSDTranferred()})`} + ` (${eacStore.getFormattedUSDTranferred()}*)`}
    diff --git a/app/components/ScheduleWizard/ConfirmSettings.js b/app/components/ScheduleWizard/ConfirmSettings.js index 59eb6525..f9635606 100644 --- a/app/components/ScheduleWizard/ConfirmSettings.js +++ b/app/components/ScheduleWizard/ConfirmSettings.js @@ -3,7 +3,11 @@ import PropTypes from 'prop-types'; import { action } from 'mobx'; import { inject, observer } from 'mobx-react'; import Alert from '../Common/Alert'; +import CollectibleDisplay from '../Common/CollectibleDisplay'; +const EMPTY_FIELD_SIGN = '-'; + +@inject('tokenHelper') @inject('scheduleStore') @inject('eacService') @inject('web3Service') @@ -100,6 +104,45 @@ class ConfirmSettings extends Component { this._mounted = false; } + isCollectibleTransfer() { + const { scheduleStore, tokenHelper } = this.props; + + return scheduleStore && tokenHelper.isCollectible(scheduleStore.toAddress); + } + + getAmountToSendDisplay() { + const { scheduleStore } = this.props; + + if (scheduleStore.isTokenTransfer) { + if (this.isCollectibleTransfer() && scheduleStore.collectibleIdToTransfer) { + return ( + + + + ); + } + + return ( + + {scheduleStore.tokenToSend + ? scheduleStore.tokenToSend + ' ' + scheduleStore.tokenSymbol + : EMPTY_FIELD_SIGN} + + ); + } + + return ( + + {scheduleStore.amountToSend ? scheduleStore.amountToSend + ' ETH' : EMPTY_FIELD_SIGN} + + ); + } + render() { const Tabs = { info: ' INFORMATION', @@ -108,7 +151,6 @@ class ConfirmSettings extends Component { block: ' DATE & TIME' }; const { scheduleStore } = this.props; - const emptyFieldSign = '-'; let errMsg = []; Object.keys(this.state.errors).map(section => { this.state.errors[section] ? errMsg.push(section) : null; @@ -164,7 +206,7 @@ class ConfirmSettings extends Component { {scheduleStore.toAddress} ) : ( - emptyFieldSign + EMPTY_FIELD_SIGN )} @@ -190,20 +232,7 @@ class ConfirmSettings extends Component { Amount to Send - {!scheduleStore.isTokenTransfer && ( - - {scheduleStore.amountToSend - ? scheduleStore.amountToSend + ' ETH' - : emptyFieldSign} - - )} - {scheduleStore.isTokenTransfer && ( - - {scheduleStore.tokenToSend - ? scheduleStore.tokenToSend + ' ' + scheduleStore.tokenSymbol - : emptyFieldSign} - - )} + {this.getAmountToSendDisplay()} Data @@ -212,7 +241,7 @@ class ConfirmSettings extends Component { className="d-inline-block col-6 col-lg-8 data-field" title={scheduleStore.tokenData} > - {scheduleStore.yourData ? scheduleStore.yourData : emptyFieldSign} + {scheduleStore.yourData ? scheduleStore.yourData : EMPTY_FIELD_SIGN} )} {scheduleStore.isTokenTransfer && ( @@ -230,7 +259,7 @@ class ConfirmSettings extends Component { Window Size - {this.executionWindow || emptyFieldSign} + {this.executionWindow || EMPTY_FIELD_SIGN} @@ -248,31 +277,33 @@ class ConfirmSettings extends Component { Gas Amount - {scheduleStore.gasAmount ? scheduleStore.gasAmount : emptyFieldSign} + {scheduleStore.gasAmount ? scheduleStore.gasAmount : EMPTY_FIELD_SIGN} Gas Price - {scheduleStore.gasPrice ? scheduleStore.gasPrice + ' Gwei' : emptyFieldSign} + {scheduleStore.gasPrice ? scheduleStore.gasPrice + ' Gwei' : EMPTY_FIELD_SIGN} Fee - {scheduleStore.fee ? scheduleStore.fee : emptyFieldSign} + {scheduleStore.fee ? scheduleStore.fee : EMPTY_FIELD_SIGN} Time Bounty - {scheduleStore.timeBounty ? scheduleStore.timeBounty + ' ETH' : emptyFieldSign} + {scheduleStore.timeBounty + ? scheduleStore.timeBounty + ' ETH' + : EMPTY_FIELD_SIGN} Deposit - {scheduleStore.deposit ? scheduleStore.deposit + ' ETH' : emptyFieldSign} + {scheduleStore.deposit ? scheduleStore.deposit + ' ETH' : EMPTY_FIELD_SIGN} @@ -289,6 +320,7 @@ class ConfirmSettings extends Component { ConfirmSettings.propTypes = { scheduleStore: PropTypes.any, + tokenHelper: PropTypes.any, web3Service: PropTypes.any, eacService: PropTypes.any, isWeb3Usable: PropTypes.any, diff --git a/app/components/ScheduleWizard/InfoSettings.js b/app/components/ScheduleWizard/InfoSettings.js index 52b5d005..fefed248 100644 --- a/app/components/ScheduleWizard/InfoSettings.js +++ b/app/components/ScheduleWizard/InfoSettings.js @@ -4,8 +4,9 @@ import Bb from 'bluebird'; import Switch from 'react-switch'; import AbstractSetting from './AbstractSetting'; import Alert from '../Common/Alert'; -import { TOKEN_ADDRESSES, PREDEFINED_TOKENS_FOR_NETWORK } from '../../config/web3Config'; +import { TOKEN_ADDRESSES } from '../../config/web3Config'; import Select from '../Common/Select'; +import CollectibleDisplay from '../Common/CollectibleDisplay'; @inject('tokenHelper') @inject('scheduleStore') @@ -18,7 +19,8 @@ class InfoSettings extends AbstractSetting { this.state = { account: '', minGas: 21000, - token: {} + token: {}, + tokensOfOwner: [] }; const { _validations, _validationsErrors } = this.props; this._validations = _validations.InfoSettings; @@ -95,7 +97,7 @@ class InfoSettings extends AbstractSetting { return estimate; } - async calculateTokenTransferMinimumGasandData() { + async calculateTokenTransferMinimumGasAndData() { const { web3Service: { web3 }, scheduleStore, @@ -110,18 +112,37 @@ class InfoSettings extends AbstractSetting { isAddress(scheduleStore.receiverAddress, web3) == 0 ) { try { - estimate = await tokenHelper.estimateTokenTransfer( - scheduleStore.toAddress, - scheduleStore.receiverAddress, - scheduleStore.tokenToSend * 10 ** this.state.token.decimals - ); - estimate = estimate + 20000; - scheduleStore.tokenData = await tokenHelper.getTokenTransferData( - scheduleStore.toAddress, - scheduleStore.receiverAddress, - scheduleStore.tokenToSend * 10 ** this.state.token.decimals - ); + const isCollectibleTransfer = this.isCollectibleTransfer(); + + if (isCollectibleTransfer) { + estimate = await tokenHelper.estimateERC721Transfer( + scheduleStore.toAddress, + null, + scheduleStore.receiverAddress, + scheduleStore.collectibleIdToTransfer + ); + estimate = estimate + 20000; + scheduleStore.tokenData = await tokenHelper.getERC721TransferData( + scheduleStore.toAddress, + null, + scheduleStore.receiverAddress, + scheduleStore.collectibleIdToTransfer + ); + } else { + estimate = await tokenHelper.estimateTokenTransfer( + scheduleStore.toAddress, + scheduleStore.receiverAddress, + scheduleStore.tokenToSend * 10 ** this.state.token.decimals + ); + estimate = estimate + 20000; + scheduleStore.tokenData = await tokenHelper.getTokenTransferData( + scheduleStore.toAddress, + scheduleStore.receiverAddress, + scheduleStore.tokenToSend * 10 ** this.state.token.decimals + ); + } } catch (e) { + console.error('Error in function calculateTokenTransferMinimumGasAndData', e); scheduleStore.tokenData = ''; return; } @@ -136,6 +157,7 @@ class InfoSettings extends AbstractSetting { if (!this._mounted) { return; } + const { web3Service, web3Service: { web3 }, @@ -149,10 +171,12 @@ class InfoSettings extends AbstractSetting { ) { return; } + this.setState({ account: web3Service.accounts[0] }); + if (scheduleStore.isTokenTransfer && isAddress(scheduleStore.toAddress, web3) === 0) { await this.getTokenDetails(true); - await this.calculateTokenTransferMinimumGasandData(); + await this.calculateTokenTransferMinimumGasAndData(); } } @@ -162,6 +186,7 @@ class InfoSettings extends AbstractSetting { const tokenDetails = await tokenHelper.fetchTokenDetails(scheduleStore.toAddress); this.setState({ token: tokenDetails }); scheduleStore.tokenSymbol = tokenDetails.symbol; + scheduleStore.tokenName = tokenDetails.name; } let _balance = await tokenHelper.fetchTokenBalance(scheduleStore.toAddress); _balance = _balance == '-' ? _balance : Number(_balance / 10 ** this.state.token.decimals); @@ -171,6 +196,13 @@ class InfoSettings extends AbstractSetting { 1 / 10 ** this.state.token.decimals, balance ); + + const tokensOfOwner = await tokenHelper.getTokensOfOwner(scheduleStore.toAddress); + + this.setState({ + tokensOfOwner + }); + this.checkAmountValidation(); this.forceUpdate(); } @@ -205,19 +237,27 @@ class InfoSettings extends AbstractSetting { this.validators.tokenToSend = this.decimalValidator(); return; } + if (property === 'toAddress') { await this.getTokenDetails(); } - await this.calculateTokenTransferMinimumGasandData(); + + await this.calculateTokenTransferMinimumGasAndData(); this.forceUpdate(); } + async chooseCollectible(tokenId) { + this.props.scheduleStore.collectibleIdToTransfer = tokenId; + + await this.calculateTokenTransferMinimumGasAndData(); + } + onChangeCheck = property => async event => { let { target: { value } } = event; const { scheduleStore } = this.props; - this.onChange(property)({ target: { value: value } }); + this.onChange(property)({ target: { value } }); if (scheduleStore.isTokenTransfer) { await this.tokenChangeCheck(property); @@ -229,11 +269,18 @@ class InfoSettings extends AbstractSetting { }; async useToken(tokenSymbol) { + const { scheduleStore, web3Service } = this.props; + if (tokenSymbol && tokenSymbol !== 'PLACEHOLDER') { - this.props.scheduleStore.toAddress = - TOKEN_ADDRESSES[tokenSymbol][this.props.web3Service.network.id]; + const tokenInfo = TOKEN_ADDRESSES[tokenSymbol][web3Service.network.id]; + scheduleStore.toAddress = tokenInfo.address; + + if (tokenInfo.type === 'erc721') { + scheduleStore.tokenToSend = 1; + } } else { - this.props.scheduleStore.toAddress = ''; + scheduleStore.toAddress = ''; + scheduleStore.tokenToSend = null; } await this.revalidateToAddress(); @@ -265,13 +312,24 @@ class InfoSettings extends AbstractSetting { this._mounted = false; } + isCollectibleTransfer() { + const { tokenHelper } = this.props; + const { token } = this.state; + + return token && tokenHelper.isCollectible(token.address); + } + render() { - const { scheduleStore, web3Service } = this.props; + const { scheduleStore, tokenHelper } = this.props; const { _validations, _validationsErrors } = this; - this.validators.gasAmount = this.integerValidator(this.state.minGas); + const { minGas, token, tokensOfOwner } = this.state; + const { collectibleIdToTransfer } = scheduleStore; + + this.validators.gasAmount = this.integerValidator(minGas); + + const predefinedTokensSymbols = tokenHelper.getPredefinedTokenSymbols(); - const predefinedTokens = - web3Service.network && PREDEFINED_TOKENS_FOR_NETWORK[web3Service.network.id]; + const isCollectibleTransfer = this.isCollectibleTransfer(); return (
    @@ -310,9 +368,9 @@ class InfoSettings extends AbstractSetting { {scheduleStore.isTokenTransfer && - predefinedTokens && + predefinedTokensSymbols && (!scheduleStore.toAddress || - predefinedTokens.includes(this.state.token.symbol)) ? ( + predefinedTokensSymbols.includes(token.symbol)) ? (
    ) : ( - this.state.token.name + token.name )}
    -
    - - {this.state.token.decimals} -
    + {!isCollectibleTransfer && ( +
    + + {token.decimals} +
    + )}
    - {this.state.token.balance} + {token.balance}
    @@ -399,7 +459,7 @@ class InfoSettings extends AbstractSetting {
    - {scheduleStore.isTokenTransfer && ( + {scheduleStore.isTokenTransfer && !isCollectibleTransfer && (
    )} + {scheduleStore.isTokenTransfer && tokensOfOwner.length > 0 && isCollectibleTransfer && ( + +
    +
    +
    + Choose collectible you'd like to transfer: +
    +
    +
    + {tokensOfOwner.map((collectibleId, index) => ( +
    this.chooseCollectible(collectibleId.toString())} + > + +
    {collectibleId.toString()}
    +
    + ))} +
    +
    +
    +
    +
    +
    + )}
    ); } diff --git a/app/components/SidePanel/SidePanel.js b/app/components/SidePanel/SidePanel.js index 01b62dfb..35122377 100644 --- a/app/components/SidePanel/SidePanel.js +++ b/app/components/SidePanel/SidePanel.js @@ -185,6 +185,30 @@ class SidePanel extends Component { +
  • + + Automate + + + + +
  • +
  • + + Automate Zapier + + + + +
  • {!isElectron && (
  • Transferred
    -
    +
    {eacStore.totalEthTransferred !== null ? ( `${eacStore.totalEthTransferred} ETH` ) : ( )} {eacStore.totalUsdTransferred !== null && - ` (${eacStore.getFormattedUSDTranferred()})`} + ` (${eacStore.getFormattedUSDTranferred()}*)`}
  • @@ -289,6 +310,18 @@ class SidePanel extends Component { {loaderIfNull(efficiency)} %
    +
  • + + * Some data provided by Nomics.com{' '} + + Cryptocurrency Market Data API + + +
  • diff --git a/app/components/TransactionScanner/TransactionDetails.js b/app/components/TransactionScanner/TransactionDetails.js index 68ce24e5..bc7dcc70 100644 --- a/app/components/TransactionScanner/TransactionDetails.js +++ b/app/components/TransactionScanner/TransactionDetails.js @@ -9,19 +9,21 @@ import moment from 'moment'; import { ValueDisplay } from '../Common/ValueDisplay'; import * as ethUtil from 'ethereumjs-util'; import { BeatLoader } from 'react-spinners'; - import CancelSection from './TransactionDetails/CancelSection'; import ProxySection from './TransactionDetails/ProxySection'; +import CollectibleDisplay from '../Common/CollectibleDisplay'; const INITIAL_STATE = { callData: '', customProxyData: '', executedAt: '', + isCollectibleTransfer: false, isTokenTransfer: false, isFrozen: '', proxyDataCheckBox: false, status: '', token: {}, + tokenTransferApproved: false, tokenTransferDetails: [] }; @@ -79,11 +81,22 @@ class TransactionDetails extends Component { target.innerHTML = 'Approving...'; try { - const approvalTx = await tokenHelper.approveTokenTransfer( - toAddress, - address, - this.state.token.info.value - ); + let approvalTx; + + if (this.state.isCollectibleTransfer) { + approvalTx = await tokenHelper.approveERC721Transfer( + toAddress, + address, + this.state.token.info.value + ); + } else { + approvalTx = await tokenHelper.approveTokenTransfer( + toAddress, + address, + this.state.token.info.value + ); + } + if (approvalTx) { showNotification(`Token Transfer approval sent in tx: ${approvalTx}`, 'info', 0); target.innerHTML = 'Approval sent. Waiting...'; @@ -189,7 +202,9 @@ class TransactionDetails extends Component { } } - this.setState({ executedAt }); + if (this._isMounted) { + this.setState({ executedAt }); + } } async fetchTokenTransferEvents() { @@ -232,10 +247,13 @@ class TransactionDetails extends Component { async fetchTokenTransferInfo() { const { tokenHelper, transaction } = this.props; - const { toAddress } = transaction; - const tokenDetails = await tokenHelper.fetchTokenDetails(toAddress); - this.setState({ token: tokenDetails }); + const tokenDetails = await tokenHelper.fetchTokenDetails(transaction.toAddress); + tokenDetails.info = await tokenHelper.getTokenTransferInfoFromData(this.state.callData); + + if (this._isMounted) { + this.setState({ token: tokenDetails }); + } } getExecutedEvents(requestLib, fromBlock = 0) { @@ -352,39 +370,75 @@ class TransactionDetails extends Component { async testToken() { const { tokenHelper, transaction } = this.props; - const { address, toAddress } = transaction; + const { callData, status } = this.state; + const { address, owner, toAddress } = transaction; let tokenTransferApproved; - const isTokenTransfer = tokenHelper.isTokenTransferTransaction(this.state.callData); + const isTokenTransfer = tokenHelper.isTokenTransferTransaction(callData); if (isTokenTransfer) { await this.fetchTokenTransferInfo(); - const info = await tokenHelper.getTokenTransferInfoFromData(this.state.callData); - this.setState({ token: Object.assign(this.state.token, { info }) }); + const { + ERC721: isCollectibleTransfer, + getApproved: getApprovedSupported + } = await tokenHelper.isERC721(toAddress); - const checkTransferApproved = async () => { - const previouslyApproved = this.state.tokenTransferApproved; - const tokenTransferApproved = await tokenHelper.isTokenTransferApproved( - toAddress, - address, - this.state.token.info.value - ); + this.setState({ + isCollectibleTransfer + }); - if (tokenTransferApproved) { - if (previouslyApproved === false) { - showNotification(`Token transfer approved.`, 'success', 0); - } - clearInterval(this.tokenCheckInterval); + if (status === TRANSACTION_STATUS.SCHEDULED) { + let checkTransferApproved; + + if (isCollectibleTransfer) { + checkTransferApproved = async () => { + const previouslyApproved = this.state.tokenTransferApproved; + const tokenTransferApproved = await tokenHelper.isERC721TransferApproved( + toAddress, + address, + this.state.token.info.value, + getApprovedSupported + ); + + if (this.state.tokenTransferApproved) { + if (previouslyApproved === false) { + showNotification(`Token transfer approved.`, 'success', 0); + } + clearInterval(this.tokenCheckInterval); + } + + this.setState({ isTokenTransfer, tokenTransferApproved }); + }; + } else { + checkTransferApproved = async () => { + const previouslyApproved = this.state.tokenTransferApproved; + const tokenTransferApproved = await tokenHelper.isTokenTransferApproved( + toAddress, + owner, + address, + this.state.token.info.value + ); + + if (this.state.tokenTransferApproved) { + if (previouslyApproved === false) { + showNotification(`Token transfer approved.`, 'success', 0); + } + clearInterval(this.tokenCheckInterval); + } + + this.setState({ isTokenTransfer, tokenTransferApproved }); + }; } - this.setState({ isTokenTransfer, tokenTransferApproved }); - }; - - if (!tokenTransferApproved) { - this.tokenCheckInterval = setInterval(checkTransferApproved, 1000); + if (!tokenTransferApproved) { + this.tokenCheckInterval = setInterval(checkTransferApproved, 1000); + } + } else { + tokenTransferApproved = true; } } + this.setState({ isTokenTransfer, tokenTransferApproved }); } @@ -439,6 +493,7 @@ class TransactionDetails extends Component { getTokenNotificationSection() { const { status, + isCollectibleTransfer, isFrozen, isTokenTransfer, tokenTransferApproved, @@ -460,17 +515,25 @@ class TransactionDetails extends Component { isTokenTransfer && (isFrozen || status === TRANSACTION_STATUS.SCHEDULED) ) { + let message; + + if (isCollectibleTransfer) { + message = `This transaction schedules a collectible transfer. This transaction has to be approved.`; + } else { + message = `This transaction schedules a token transfer. A minimum allowance of ${this.state + .token.info.value / + 10 ** this.state.token.decimals} ${ + this.state.token.symbol + } tokens is required to be approved to complete the scheduling.`; + } + return ( ); @@ -479,13 +542,32 @@ class TransactionDetails extends Component { return null; } + getValueDisplay() { + if (this.state.isTokenTransfer) { + if (this.state.isCollectibleTransfer) { + return ( + + ); + } + + return `${this.state.token.info.value / 10 ** this.state.token.decimals} ${ + this.state.token.symbol + }`; + } + + return ; + } + render() { const { transaction, transactionMissingData } = this.props; const { callData, executedAt, isFrozen, status, tokenTransferApproved } = this.state; const { bounty, callGas, - callValue, fee, gasPrice, owner, @@ -534,7 +616,7 @@ class TransactionDetails extends Component { )} - {this.state.isTokenTransfer && ( + {this.state.isTokenTransfer && status === TRANSACTION_STATUS.SCHEDULED && ( Approval status @@ -574,15 +656,7 @@ class TransactionDetails extends Component { )} Value/Amount - - {!this.state.isTokenTransfer ? ( - - ) : ( - `${this.state.token.info.value / 10 ** this.state.token.decimals} ${ - this.state.token.symbol - }` - )} - + {this.getValueDisplay()} Data diff --git a/app/config/web3Config.js b/app/config/web3Config.js index d43cddbb..8d1221ee 100644 --- a/app/config/web3Config.js +++ b/app/config/web3Config.js @@ -16,6 +16,8 @@ export const requestFactoryStartBlocks = { [KOVAN_NETWORK_ID]: 5555500 }; +const CRYPTO_KITTIES_API_KEY = process.env.CRYPTO_KITTIES_API_KEY; + export const PROVIDER_URLS = { MAINNET: { QUIKNODE: { @@ -111,13 +113,96 @@ const Networks = { const CUSTOM_PROVIDER_NET_ID = 9999; const TOKEN_ADDRESSES = { + EGG: { + [MAIN_NETWORK_ID]: { + address: '0xfcad2859f3e602d4cfb9aca35465a618f9009f7b', + type: 'erc721', + imagePath: 'https://api.dragonereum.io/images/eggs/small/{TOKEN_ID}.png', + imageHeight: '140px', + supportedMethods: { + getApproved: true, + safeTransferFrom: true + } + } + }, + CK: { + [MAIN_NETWORK_ID]: { + address: '0x06012c8cf97bead5deae237070f9587f8e7a266d', + type: 'erc721', + imagePath: + 'https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/{TOKEN_ID}.png', + imageHeight: '140px', + async customGetTokensForOwner(address) { + const URL = `https://public.api.cryptokitties.co/v1/kitties?owner_wallet_address=${address}&limit=400`; + + const response = await fetch(URL, { + headers: { + 'x-api-token': CRYPTO_KITTIES_API_KEY + } + }); + + const json = await response.json(); + + if (!json.kitties || !json.kitties.length) { + return []; + } + + return json.kitties.map(kittie => kittie.id.toString()); + }, + supportedMethods: { + getApproved: false, + safeTransferFrom: false + } + }, + [KOVAN_NETWORK_ID]: { + address: '0x9382c0b652f505a88a4c5bad05084df26a4a2f54', + type: 'erc721', + imagePath: + 'https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/{TOKEN_ID}.png', + imageHeight: '140px', + supportedMethods: { + getApproved: false, + safeTransferFrom: false + } + } + }, DAI: { - [MAIN_NETWORK_ID]: '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', - [KOVAN_NETWORK_ID]: '0xc4375b7de8af5a38a93548eb8453a498222c4ff2' + [MAIN_NETWORK_ID]: { + address: '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359' + }, + [KOVAN_NETWORK_ID]: { + address: '0xc4375b7de8af5a38a93548eb8453a498222c4ff2' + } }, DAY: { - [MAIN_NETWORK_ID]: '0xE814aeE960a85208C3dB542C53E7D4a6C8D5f60F', - [KOVAN_NETWORK_ID]: '0x5a6b5c6387196bd4ea264f627792af9d09096876' + [MAIN_NETWORK_ID]: { + address: '0xE814aeE960a85208C3dB542C53E7D4a6C8D5f60F' + }, + [KOVAN_NETWORK_ID]: { + address: '0x5a6b5c6387196bd4ea264f627792af9d09096876' + } + }, + DRAGON: { + [MAIN_NETWORK_ID]: { + address: '0x960f401aed58668ef476ef02b2a2d43b83c261d8', + type: 'erc721', + imagePath: 'https://api.dragonereum.io/images/dragons/small/{TOKEN_ID}.png', + imageHeight: '140px', + supportedMethods: { + getApproved: true, + safeTransferFrom: true + } + }, + [KOVAN_NETWORK_ID]: { + address: '0x6823cac086c70858b9bec21770520a672481a96b', + type: 'erc721', + imagePath: 'https://api.dragonereum.io/images/dragons/small/{TOKEN_ID}.png', + imageHeight: '140px', + supportedMethods: { + getApproved: true, + safeTransferFrom: true + } + } } }; @@ -132,7 +217,12 @@ const PREDEFINED_TOKENS_FOR_NETWORK = { for (let token of Object.keys(TOKEN_ADDRESSES)) { for (let network of Object.keys(TOKEN_ADDRESSES[token])) { - PREDEFINED_TOKENS_FOR_NETWORK[network].push(token); + TOKEN_ADDRESSES[token][network].symbol = token; + PREDEFINED_TOKENS_FOR_NETWORK[network].push( + Object.assign(TOKEN_ADDRESSES[token][network], { + symbol: token + }) + ); } } diff --git a/app/index.html b/app/index.html index a9e99d23..b2bf47db 100644 --- a/app/index.html +++ b/app/index.html @@ -19,9 +19,8 @@ <%= htmlWebpackPlugin.options.gtmNoScript %> -
    - + \ No newline at end of file diff --git a/app/lib/signature.js b/app/lib/signature.js index 3d3722f3..adee5fa2 100644 --- a/app/lib/signature.js +++ b/app/lib/signature.js @@ -85,4 +85,4 @@ function isMyCryptoSigValid(signature, timeNodeAddress) { return stripHexPrefixAndLower(address) === pubToAddress(pubKey).toString('hex'); } -export { parseSig, isSignatureValid, isMyCryptoSigValid, SIGNATURE_ERRORS }; +export { parseSig, isSignatureValid, isMyCryptoSigValid, SIGNATURE_ERRORS, stripHexPrefixAndLower }; diff --git a/app/scss/style.scss b/app/scss/style.scss index 51060701..a5076e97 100644 --- a/app/scss/style.scss +++ b/app/scss/style.scss @@ -423,6 +423,12 @@ hr { display: none; } +.sidebar-bottom-item { + position: absolute; + bottom: 0; + padding: 15px !important; +} + .sidebar-additional-item { display: none !important; @@ -483,3 +489,42 @@ hr { } } } + +.collectibles { + display: flex; + flex-wrap: wrap; + + &_item { + width: 180px; + height: 180px; + text-align: center; + border: 1px solid rgba(0, 0, 0, 0.07); + cursor: pointer; + margin-top: 5px; + + &-selected { + background: rgba(0, 0, 0, 0.07); + border: 1px solid #000000; + } + + $root: &; + + &:hover { + background: #ededed; + + #{$root}_image { + width: 160px; + height: 160px; + } + } + + &:not(:first-child) { + margin-left: 5px; + } + + &_image { + width: 140px; + height: 140px; + } + } +} \ No newline at end of file diff --git a/app/services/token-helper.js b/app/services/token-helper.js index 9f4bd51d..e87860db 100644 --- a/app/services/token-helper.js +++ b/app/services/token-helper.js @@ -1,6 +1,9 @@ /*eslint no-control-regex: "off"*/ import Bb from 'bluebird'; import standardTokenAbi from '../abi/standardToken'; +import cryptoKittiesTokenAbi from '../abi/cryptoKittiesToken'; +import ERC721Abi from '../abi/ERC721'; +import { PREDEFINED_TOKENS_FOR_NETWORK } from '../config/web3Config'; const cleanAsciiText = text => text && text.replace(/[\x00-\x09\x0b-\x1F]/g, '').trim(); @@ -17,7 +20,15 @@ export default class TokenHelper { const contract = this._web3.eth.contract(standardTokenAbi).at(token); return await Bb.fromCallback(callback => - contract.approve(receiver, amount, { from: this.defaultAccount }, callback) + contract.approve(receiver, amount, { from: this._defaultAccount }, callback) + ); + } + + async approveERC721Transfer(token, spender, collectibleId) { + const contract = this._web3.eth.contract(ERC721Abi).at(token); + + return await Bb.fromCallback(callback => + contract.approve(spender, collectibleId, { from: this._firstAccount }, callback) ); } @@ -26,22 +37,44 @@ export default class TokenHelper { return false; } - const functionName = 'transferFrom(address,address,uint256)'; - const encodedFunction = this._encodeFunctionName(functionName); + const encodedTransferFrom = this._encodeFunctionName('transferFrom(address,address,uint256)'); + const encodedSafeTransferFrom = this._encodeFunctionName( + 'safeTransferFrom(address,address,uint256)' + ); - return new RegExp(encodedFunction).test(callData); + return new RegExp(`${encodedTransferFrom}|${encodedSafeTransferFrom}`).test(callData); } - async isTokenTransferApproved(token, sender, value) { + async isTokenTransferApproved(token, owner, spender, value) { const contract = this._web3.eth.contract(standardTokenAbi).at(token); const allowance = await Bb.fromCallback(callback => - contract.allowance(this._firstAccount, sender, callback) + contract.allowance(owner, spender, callback) ); return Number(allowance) >= Number(value); } + async isERC721TransferApproved(address, scheduledTxAddress, tokenId, supportsGetApproved) { + let approved = false; + + if (supportsGetApproved) { + const contract = this._web3.eth.contract(ERC721Abi).at(address); + + approved = (await Bb.fromCallback(callback => { + return contract.getApproved.call(tokenId, callback); + })).valueOf(); + } else { + const contract = this._web3.eth.contract(cryptoKittiesTokenAbi).at(address); + + approved = (await Bb.fromCallback(callback => { + return contract.kittyIndexToApproved.call(tokenId, callback); + })).valueOf(); + } + + return approved === scheduledTxAddress; + } + async getTokenTransferInfoFromData(callData) { const functionName = 'transferFrom'; const params = [ @@ -75,15 +108,134 @@ export default class TokenHelper { ); } + async estimateERC721Transfer(tokenAddress, from, to, tokenId) { + if (!from) { + from = this._firstAccount; + } + + if (!tokenId) { + return 0; + } + + const contract = this._web3.eth.contract(ERC721Abi).at(tokenAddress); + + const config = this.getTokenConfig(tokenAddress); + + if (config && config.supportedMethods && config.supportedMethods.safeTransferFrom) { + return await Bb.fromCallback(callback => + contract.safeTransferFrom.estimateGas(from, to, tokenId, callback) + ); + } + + try { + return await Bb.fromCallback(callback => + contract.transferFrom.estimateGas(from, to, tokenId, callback) + ); + } catch (error) { + const cryptoKittiesContract = this._web3.eth.contract(cryptoKittiesTokenAbi).at(tokenAddress); + console.error( + 'Error when estimating gas cost for ERC721 transferFrom. Falling back to estimation for transfer.', + error + ); + return await Bb.fromCallback(callback => + cryptoKittiesContract.transfer.estimateGas(to, tokenId, callback) + ); + } + } + + async isERC721(address) { + const config = this.getTokenConfig(address); + + if (config && config.supportedMethods) { + return { + ERC721: config.type === 'erc721', + getApproved: config.supportedMethods.getApproved, + safeTransferFrom: config.supportedMethods.safeTransferFrom + }; + } + + const supportsEIP165 = await this._web3Service.supportsEIP165(address); + + if (!supportsEIP165) { + return false; + } + + const INTERFACE_ERC_721 = '0x80ac58cd'; // ERC721 with safeTransferFrom and getApproved + + const supportsFullERC721 = await this._web3Service.supportsInterface( + address, + INTERFACE_ERC_721 + ); + + if (supportsFullERC721) { + return { + ERC721: true, + safeTransferFrom: true, + getApproved: true + }; + } + + const INTERFACE_ERC_721_INCOMPLETE = '0x9a20483d'; + // NO safeTransferFrom and getApproved + + const supportsIncompleteERC721 = await this._web3Service.supportsInterface( + address, + INTERFACE_ERC_721_INCOMPLETE + ); + + if (supportsIncompleteERC721) { + return { + ERC721: true, + safeTransferFrom: false, + getApproved: false + }; + } + + return { + ERC721: false, + safeTransferFrom: false, + getApproved: false + }; + } + + async getERC721TransferData(tokenAddress, from, to, tokenId) { + if (!from) { + from = this._firstAccount; + } + + const contract = this._web3.eth.contract(ERC721Abi).at(tokenAddress); + + const config = this.getTokenConfig(tokenAddress); + + if (config && config.supportedMethods && config.supportedMethods.safeTransferFrom) { + return contract.safeTransferFrom.getData(from, to, tokenId); + } + + return contract.transferFrom.getData(from, to, tokenId); + } + async fetchTokenDetails(address) { const contract = this._web3.eth.contract(standardTokenAbi).at(address); - return { + const details = { address, name: await this.getTokenName(address), - symbol: await this.getTokenSymbol(address), - decimals: (await Bb.fromCallback(callback => contract.decimals.call(callback))).valueOf() + symbol: await this.getTokenSymbol(address) }; + + try { + details.decimals = (await Bb.fromCallback(callback => + contract.decimals.call(callback) + )).valueOf(); + } catch (error) { + console.error( + 'Trying to call token decimals() function failed. Falling back to decimals: 0.', + error + ); + details.decimals = 0; + } + + return details; } async getTokenSymbol(address) { @@ -136,6 +288,62 @@ export default class TokenHelper { return this._firstAccount ? await this.getTokenBalanceOf(address, this._firstAccount) : '-'; } + /** + * Helper method for contracts such as CryptoKitties + */ + async getTokensOfOwner(tokenAddress, addressToCheck = this._firstAccount) { + const contract = this._web3.eth.contract(cryptoKittiesTokenAbi).at(tokenAddress); + + const tokenConfig = this.getTokenConfig(tokenAddress); + + if (tokenConfig && tokenConfig.customGetTokensForOwner) { + return tokenConfig.customGetTokensForOwner(addressToCheck); + } + + return (await Bb.fromCallback(callback => { + return contract.tokensOfOwner.call(addressToCheck, callback); + })).valueOf(); + } + + getTokenConfig(address) { + if (!address) { + return; + } + + const networkTokens = PREDEFINED_TOKENS_FOR_NETWORK[this._web3Service.network.id]; + + address = address.toLowerCase(); + + if (networkTokens) { + return networkTokens.find(t => t.address.toLowerCase() === address); + } + } + + getTokenImagePath(token, tokenId) { + if (!token || !tokenId || !token.imagePath) { + return; + } + + return token.imagePath.replace('{TOKEN_ID}', tokenId); + } + + getPredefinedTokenSymbols() { + const predefinedTokens = + this._web3Service.network && PREDEFINED_TOKENS_FOR_NETWORK[this._web3Service.network.id]; + + return predefinedTokens && predefinedTokens.map(t => t.symbol); + } + + isCollectible(tokenAddress) { + if (!tokenAddress) { + return false; + } + + const config = this.getTokenConfig(tokenAddress); + + return config && config.type === 'erc721'; + } + /** * @private * diff --git a/app/services/web3.js b/app/services/web3.js index 7dfe5fce..44dd5625 100644 --- a/app/services/web3.js +++ b/app/services/web3.js @@ -7,9 +7,12 @@ import { MAIN_NETWORK_ID } from '../config/web3Config.js'; import { W3Util } from '@ethereum-alarm-clock/timenode-core'; +import { stripHexPrefixAndLower } from '../lib/signature.js'; let instance = null; +const SUPPORTS_INTERFACE_CALL_DATA = '0x01ffc9a7'; // bytes4(keccak256('supportsInterface(bytes4)')); + export default class Web3Service { web3 = null; tokenInstance = null; @@ -228,6 +231,29 @@ export default class Web3Service { return web3.eth.filter(options); } + toBoolean(hexString) { + return this.web3.toBigNumber(hexString).toString() === '1'; + } + + supportsEIP165(address) { + return this.supportsInterface(address, SUPPORTS_INTERFACE_CALL_DATA); + } + + // checks using EIP165 if contract supports certain interface + supportsInterface(address, interfaceToCheckFor) { + return new Promise(resolve => { + this.web3.eth.call( + { + to: address, + data: SUPPORTS_INTERFACE_CALL_DATA + stripHexPrefixAndLower(interfaceToCheckFor) + }, + (error, result) => { + resolve(this.toBoolean(result)); + } + ); + }); + } + /** * @private */ diff --git a/app/stores/ScheduleStore.js b/app/stores/ScheduleStore.js index 3c36a33a..e6bb532c 100644 --- a/app/stores/ScheduleStore.js +++ b/app/stores/ScheduleStore.js @@ -32,6 +32,8 @@ export default class ScheduleStore { @observable tokenToSend; @observable tokenData; @observable tokenSymbol; + @observable tokenName; + @observable collectibleIdToTransfer; @observable isUsingTime; @observable isTokenTransfer; @@ -46,8 +48,8 @@ export default class ScheduleStore { } /* - * Currently MobX doesn't have a more elegant - * way to reset to defaults. + * Currently MobX doesn't have a more elegant + * way to reset to defaults. */ @action reset = () => { @@ -76,6 +78,8 @@ export default class ScheduleStore { this.tokenToSend = ''; this.tokenData = ''; this.tokenSymbol = ''; + this.tokenName = ''; + this.collectibleIdToTransfer = null; this.isUsingTime = true; this.isTokenTransfer = false; diff --git a/package-lock.json b/package-lock.json index 61c69a84..c10542ad 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "eth-alarm-clock-dapp", - "version": "1.2.3", + "version": "1.3.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -1053,7 +1053,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, "requires": { "ms": "2.0.0" } @@ -1093,8 +1092,7 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "utf8": { "version": "2.1.1", @@ -1138,8 +1136,19 @@ "dev": true, "requires": { "underscore": "1.8.3", - "web3-core-helpers": "1.0.0-beta.36", - "websocket": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2" + "web3-core-helpers": "1.0.0-beta.36" + }, + "dependencies": { + "websocket": { + "version": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", + "from": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", + "requires": { + "debug": "^2.2.0", + "nan": "^2.3.3", + "typedarray-to-buffer": "^3.1.2", + "yaeti": "^0.0.6" + } + } } }, "web3-utils": { @@ -1168,7 +1177,6 @@ "websocket": { "version": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", "from": "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible", - "dev": true, "requires": { "debug": "^2.2.0", "nan": "^2.3.3", @@ -1433,8 +1441,7 @@ "acorn": { "version": "5.7.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", - "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", - "dev": true + "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==" }, "acorn-dynamic-import": { "version": "4.0.0", @@ -1676,7 +1683,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "requires": { "color-convert": "^1.9.0" } @@ -3328,8 +3334,7 @@ "bindings": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.3.1.tgz", - "integrity": "sha512-i47mqjF9UbjxJhxGf+pZ6kSxrnI3wBLlnGI2ArWJ4r0VrvDS7ZYXkprq/pLaBWYq4GM0r4zdHY+NNRqEMU7uew==", - "dev": true + "integrity": "sha512-i47mqjF9UbjxJhxGf+pZ6kSxrnI3wBLlnGI2ArWJ4r0VrvDS7ZYXkprq/pLaBWYq4GM0r4zdHY+NNRqEMU7uew==" }, "bip39": { "version": "2.5.0", @@ -3348,7 +3353,6 @@ "version": "1.1.5", "resolved": "https://registry.npmjs.org/bip66/-/bip66-1.1.5.tgz", "integrity": "sha1-AfqHSHhcpwlV1QESF9GzE5lpyiI=", - "dev": true, "requires": { "safe-buffer": "^5.0.1" } @@ -3388,8 +3392,7 @@ "bn.js": { "version": "4.11.8", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", - "dev": true + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" }, "body-parser": { "version": "1.18.3", @@ -3562,8 +3565,7 @@ "brorand": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", - "dev": true + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" }, "browser-icons": { "version": "0.0.1", @@ -3794,7 +3796,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", - "dev": true, "requires": { "buffer-xor": "^1.0.3", "cipher-base": "^1.0.0", @@ -4026,8 +4027,7 @@ "buffer-xor": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", - "dev": true + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" }, "buffers": { "version": "0.1.1", @@ -4295,7 +4295,6 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -4434,7 +4433,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", - "dev": true, "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -4613,7 +4611,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "requires": { "color-name": "1.1.3" } @@ -4621,8 +4618,7 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "colors": { "version": "1.3.3", @@ -5418,7 +5414,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "dev": true, "requires": { "cipher-base": "^1.0.1", "inherits": "^2.0.1", @@ -5431,7 +5426,6 @@ "version": "1.1.7", "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "dev": true, "requires": { "cipher-base": "^1.0.3", "create-hash": "^1.1.0", @@ -6376,11 +6370,20 @@ } }, "dotenv": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-5.0.1.tgz", - "integrity": "sha512-4As8uPrjfwb7VXC+WnLCbXK7y+Ueb2B3zgNCePYfhxS1PYeaO1YTeplffTEcbfLhvFNGLAz90VvJs9yomG7bow==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.2.0.tgz", + "integrity": "sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w==", "dev": true }, + "dotenv-defaults": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/dotenv-defaults/-/dotenv-defaults-1.0.2.tgz", + "integrity": "sha512-iXFvHtXl/hZPiFj++1hBg4lbKwGM+t/GlvELDnRtOFdjXyWP7mubkVr+eZGWG62kdsbulXAef6v/j6kiWc/xGA==", + "dev": true, + "requires": { + "dotenv": "^6.2.0" + } + }, "dotenv-expand": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-4.2.0.tgz", @@ -6388,20 +6391,18 @@ "dev": true }, "dotenv-webpack": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/dotenv-webpack/-/dotenv-webpack-1.6.0.tgz", - "integrity": "sha512-jTbHXmcVw3KMVhTdgthYNLWWHRGtucrADpZWwVCdiP+pCvuWvxLcUadwEnmz8Wqv/d2UAJxJhp1jrxGlMYCetg==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/dotenv-webpack/-/dotenv-webpack-1.7.0.tgz", + "integrity": "sha512-wwNtOBW/6gLQSkb8p43y0Wts970A3xtNiG/mpwj9MLUhtPCQG6i+/DSXXoNN7fbPCU/vQ7JjwGmgOeGZSSZnsw==", "dev": true, "requires": { - "dotenv": "^5.0.1", - "dotenv-expand": "^4.0.1" + "dotenv-defaults": "^1.0.2" } }, "drbg.js": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/drbg.js/-/drbg.js-1.0.1.tgz", "integrity": "sha1-Pja2xCs3BDgjzbwzLVjzHiRFSAs=", - "dev": true, "requires": { "browserify-aes": "^1.0.6", "create-hash": "^1.1.2", @@ -7017,7 +7018,6 @@ "version": "6.4.1", "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz", "integrity": "sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==", - "dev": true, "requires": { "bn.js": "^4.4.0", "brorand": "^1.0.1", @@ -7235,8 +7235,7 @@ "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "escodegen": { "version": "1.11.0", @@ -7796,14 +7795,12 @@ "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", "dev": true, "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", "ethereumjs-util": "^5.1.1" }, "dependencies": { "ethereumjs-abi": { "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", - "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", - "dev": true, + "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", "requires": { "bn.js": "^4.10.0", "ethereumjs-util": "^5.0.0" @@ -8013,7 +8010,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", - "dev": true, "requires": { "bn.js": "^4.11.0", "create-hash": "^1.1.2", @@ -8203,7 +8199,6 @@ "version": "0.1.6", "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", - "dev": true, "requires": { "is-hex-prefixed": "1.0.0", "strip-hex-prefix": "1.0.0" @@ -8234,7 +8229,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", - "dev": true, "requires": { "md5.js": "^1.3.4", "safe-buffer": "^5.1.1" @@ -10384,8 +10378,7 @@ "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, "has-symbol-support-x": { "version": "1.4.2", @@ -10478,7 +10471,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", - "dev": true, "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -10488,7 +10480,6 @@ "version": "1.1.7", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "dev": true, "requires": { "inherits": "^2.0.3", "minimalistic-assert": "^1.0.1" @@ -10538,7 +10529,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "dev": true, "requires": { "hash.js": "^1.0.3", "minimalistic-assert": "^1.0.0", @@ -11498,8 +11488,7 @@ "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, "ini": { "version": "1.3.5", @@ -11847,8 +11836,7 @@ "is-hex-prefixed": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz", - "integrity": "sha1-fY035q135dEnFIkTxXPggtd39VQ=", - "dev": true + "integrity": "sha1-fY035q135dEnFIkTxXPggtd39VQ=" }, "is-installed-globally": { "version": "0.1.0", @@ -12030,8 +12018,7 @@ "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, "is-url": { "version": "1.2.4", @@ -13230,7 +13217,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/keccak/-/keccak-1.4.0.tgz", "integrity": "sha512-eZVaCpblK5formjPjeTBik7TAg+pqnDrMHIffSvi9Lh7PQgM1+hSzakUeZFCk9DVVG0dacZJuaz2ntwlzZUIBw==", - "dev": true, "requires": { "bindings": "^1.2.1", "inherits": "^2.0.3", @@ -14439,7 +14425,6 @@ "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "dev": true, "requires": { "hash-base": "^3.0.0", "inherits": "^2.0.1", @@ -14650,14 +14635,12 @@ "minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" }, "minimalistic-crypto-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", - "dev": true + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" }, "minimatch": { "version": "3.0.4", @@ -14671,8 +14654,7 @@ "minimist": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" }, "mississippi": { "version": "3.0.0", @@ -15048,8 +15030,7 @@ "nan": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", - "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==", - "dev": true + "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==" }, "nano-json-stream-parser": { "version": "0.1.2", @@ -15918,8 +15899,7 @@ "os-homedir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" }, "os-locale": { "version": "1.4.0", @@ -18483,7 +18463,6 @@ "integrity": "sha512-tcbhmjLyWb+2s2gdiSmROEoD/OQPFeKC9xBnKgs0H+umY8CaVrVPGFdr1y1qovm7HxUbdk/BKqi94GQDc5XB3A==", "dev": true, "requires": { - "buble": "github:pemrouz/buble#4e639aeeb64712ac95dc30a52750d1ee4432c9c8", "express": "^4.14.0", "lru_map": "^0.3.3", "platform": "^1.3.4", @@ -18495,7 +18474,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", - "dev": true, "requires": { "acorn": "^3.0.4" }, @@ -18503,8 +18481,7 @@ "acorn": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", - "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", - "dev": true + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=" } } }, @@ -18512,15 +18489,13 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/acorn5-object-spread/-/acorn5-object-spread-4.0.0.tgz", "integrity": "sha1-1XWAge7ZcSGrC+R+Mcqu8qo5lpc=", - "dev": true, "requires": { "acorn": "^5.1.2" } }, "buble": { "version": "github:pemrouz/buble#4e639aeeb64712ac95dc30a52750d1ee4432c9c8", - "from": "github:pemrouz/buble", - "dev": true, + "from": "github:pemrouz/buble#4e639aeeb64712ac95dc30a52750d1ee4432c9c8", "requires": { "acorn": "^5.1.2", "acorn-jsx": "^3.0.1", @@ -18536,7 +18511,6 @@ "version": "0.22.5", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.22.5.tgz", "integrity": "sha512-oreip9rJZkzvA8Qzk9HFs8fZGF/u7H/gtrE8EN6RjKJ9kh2HlC+yQ2QezifqTZfGyiuAV0dRv5a+y/8gBb1m9w==", - "dev": true, "requires": { "vlq": "^0.2.2" } @@ -18556,7 +18530,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "dev": true, "requires": { "hash-base": "^3.0.0", "inherits": "^2.0.1" @@ -18566,7 +18539,6 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.1.tgz", "integrity": "sha512-nqB/qy+YjXdp/zj1CjCiDwfLMBPv/XFDol0ir/7O/+Ix90++rvi+QoK1CDJcn8JoqCu2WrPPeRucu4qyIDzALg==", - "dev": true, "requires": { "safe-buffer": "^5.1.1" } @@ -18635,8 +18607,7 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "safe-event-emitter": { "version": "1.0.1", @@ -19166,7 +19137,6 @@ "version": "3.6.1", "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-3.6.1.tgz", "integrity": "sha512-utLpWv4P4agEw7hakR73wlWX0NBmC5t/vkJ0TAfTyvETAUzo0tm6aFKPYetVYRaVubxMeWm5Ekv9ETwOgcDCqw==", - "dev": true, "requires": { "bindings": "^1.2.1", "bip66": "^1.1.3", @@ -19413,7 +19383,6 @@ "version": "2.4.11", "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "dev": true, "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -20484,7 +20453,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz", "integrity": "sha1-DF8VX+8RUTczd96du1iNoFUA428=", - "dev": true, "requires": { "is-hex-prefixed": "1.0.0" } @@ -20565,7 +20533,6 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, "requires": { "has-flag": "^3.0.0" } @@ -21368,7 +21335,6 @@ "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, "requires": { "is-typedarray": "^1.0.0" } @@ -22004,8 +21970,7 @@ "vlq": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.3.tgz", - "integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==", - "dev": true + "integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==" }, "vm-browserify": { "version": "0.0.4", @@ -22482,7 +22447,6 @@ "integrity": "sha1-PpcwauAk+yThCj11yIQwJWIhUSA=", "dev": true, "requires": { - "bignumber.js": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934", "crypto-js": "^3.1.4", "utf8": "^2.1.1", "xhr2": "*", @@ -22491,8 +22455,7 @@ "dependencies": { "bignumber.js": { "version": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934", - "from": "git+https://github.com/frozeman/bignumber.js-nolookahead.git", - "dev": true + "from": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934" }, "crypto-js": { "version": "3.1.8", @@ -22576,7 +22539,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, "requires": { "ms": "2.0.0" } @@ -22584,8 +22546,7 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "web3-providers-ws": { "version": "1.0.0-beta.35", @@ -22594,14 +22555,24 @@ "dev": true, "requires": { "underscore": "1.8.3", - "web3-core-helpers": "1.0.0-beta.35", - "websocket": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2" + "web3-core-helpers": "1.0.0-beta.35" + }, + "dependencies": { + "websocket": { + "version": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", + "from": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", + "requires": { + "debug": "^2.2.0", + "nan": "^2.3.3", + "typedarray-to-buffer": "^3.1.2", + "yaeti": "^0.0.6" + } + } } }, "websocket": { "version": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", "from": "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible", - "dev": true, "requires": { "debug": "^2.2.0", "nan": "^2.3.3", @@ -22834,8 +22805,7 @@ "dev": true, "requires": { "underscore": "1.8.3", - "web3-core-helpers": "1.0.0-beta.37", - "websocket": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2" + "web3-core-helpers": "1.0.0-beta.37" }, "dependencies": { "bn.js": { @@ -22848,7 +22818,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, "requires": { "ms": "2.0.0" } @@ -22856,8 +22825,7 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "utf8": { "version": "2.1.1", @@ -22903,8 +22871,7 @@ }, "websocket": { "version": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", - "from": "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible", - "dev": true, + "from": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", "requires": { "debug": "^2.2.0", "nan": "^2.3.3", @@ -24665,8 +24632,7 @@ "yaeti": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", - "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=", - "dev": true + "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=" }, "yallist": { "version": "2.1.2", diff --git a/package.json b/package.json index e938dff6..4e833ca1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eth-alarm-clock-dapp", - "version": "1.2.3", + "version": "1.3.0", "main": "main.js", "description": "", "scripts": { @@ -71,7 +71,7 @@ "crypto-js": "3.1.9-1", "css-loader": "1.0.1", "debug": "4.1.1", - "dotenv-webpack": "1.6.0", + "dotenv-webpack": "1.7.0", "eac-counter": "0.1.2", "eac.js-lib": "2.5.1", "electron": "3.0.11",