Commit fe19f9ea authored by Uciel's avatar Uciel

major code refactor and cleanup

parent 22845601
import React, { Component } from 'react'; import React, { Component } from 'react';
// web3
import Web3 from 'web3'; import Web3 from 'web3';
import cookie from 'react-cookies'
import Head from './components/Head'
import NetworkStatus from './components/NetworkStatus'
import ConnectionHelper from './components/ConnectionHelper'
import Transactions from './components/Transactions'
// import SelectToken from './components/SelectToken'
import './App.css';
// enter the react refactor
import About from './components/About';
import Links from './components/Links';
import Swap from './components/Swap';
import Order from './components/Order';
import OrderContainer from './containers/OrderContainer';
import RateAndFee from './components/RateAndFee';
import { exchangeABI } from './helpers/exchangeABI.js' import { exchangeABI } from './helpers/exchangeABI.js'
import { tokenABI } from './helpers/tokenABI.js' import { tokenABI } from './helpers/tokenABI.js'
import { factoryABI } from './helpers/factoryABI.js' import { factoryABI } from './helpers/factoryABI.js'
// React Components
import UniHead from './components/UniHead'
import Header from './components/Header';
import ConnectionHelper from './components/ConnectionHelper'
import Exchange from './components/Exchange';
import RateAndFee from './components/RateAndFee';
import Purchase from './components/Purchase';
import About from './components/About';
import Links from './components/Links';
import Transactions from './components/Transactions';
import SelectToken from './components/SelectToken'
// enter redux // enter redux
import { bindActionCreators } from 'redux' import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import {
web3ConnectionSuccessful,
web3ConnectionUnsuccessful,
setCurrentMaskAddress,
metamaskLocked,
metamaskUnlocked,
setInteractionState,
factoryContractReady,
setNetworkMessage,
setBlockTimestamp,
setExchangeType,
initializeGlobalWeb3
} from './actions/web3-actions';
import {
uniExchangeContractReady,
swtExchangeContractReady
} from './actions/exchangeContract-actions';
import {
uniTokenContractReady,
swtTokenContractReady
} from './actions/tokenContract-actions';
import {
setInputBalance,
setOutputBalance,
setInputToken,
setOutputToken,
setInvariant1,
setInvariant2,
setMarketEth1,
setMarketEth2,
setMarketTokens1,
setMarketTokens2,
setAllowanceApprovalState,
setExchangeInputValue,
setExchangeOutputValue,
setExchangeRate,
setExchangeFee
} from './actions/exchange-actions';
// redux-subscribe
import { subscribe } from 'redux-subscriber'; import { subscribe } from 'redux-subscriber';
// redux actions
// enter d3 import { initializeGlobalWeb3 } from './actions/global-actions';
import { uniExchangeContractReady, swtExchangeContractReady } from './actions/exchangeContract-actions';
import { uniTokenContractReady, swtTokenContractReady } from './actions/tokenContract-actions';
import { setWeb3ConnectionStatus, setCurrentMaskAddress, metamaskLocked, metamaskUnlocked, setInteractionState, factoryContractReady, toggleAbout } from './actions/web3-actions';
import { setInputBalance, setOutputBalance, setInvariant1, setInvariant2, setMarketEth1, setMarketEth2, setMarketTokens1, setMarketTokens2, setAllowanceApprovalState } from './actions/exchange-actions';
// enter d3 & misc. tools
import './App.css';
import cookie from 'react-cookies'
import scrollToComponent from 'react-scroll-to-component';
// import Candlesticks from './components/Candlesticks' // import Candlesticks from './components/Candlesticks'
var localweb3; // this isn't even in state var localweb3; // this isn't even in state
...@@ -95,7 +54,7 @@ class App extends Component { ...@@ -95,7 +54,7 @@ class App extends Component {
componentWillMount() { componentWillMount() {
console.log('props', this.props); console.log('props', this.props);
if(localweb3 === 'undefined') { if(localweb3 === 'undefined') {
this.props.web3ConnectionUnsuccessful(); this.props.setWeb3ConnectionStatus(false);
} else { } else {
this.setState({ this.setState({
firstRun: cookie.load('firstRun') || true, firstRun: cookie.load('firstRun') || true,
...@@ -106,7 +65,6 @@ class App extends Component { ...@@ -106,7 +65,6 @@ class App extends Component {
// we're working with asynchronous redux // we're working with asynchronous redux
this.props.initializeGlobalWeb3(localweb3) this.props.initializeGlobalWeb3(localweb3)
this.getInfoFirstTime(); this.getInfoFirstTime();
this.checkNetwork();
} }
} }
...@@ -117,11 +75,11 @@ class App extends Component { ...@@ -117,11 +75,11 @@ class App extends Component {
if(state.web3Store.connected === true && !state.web3Store.metamaskLocked) { if(state.web3Store.connected === true && !state.web3Store.metamaskLocked) {
console.log('successfully connected to metamask', state.web3Store.currentMaskAddress); console.log('successfully connected to metamask', state.web3Store.currentMaskAddress);
setInterval(this.getMarketInfo, 15000); setInterval(this.getMarketInfo, 15000);
setInterval(this.getAccountInfo, 15000); // setInterval(this.getAccountInfo, 15000);
setInterval(this.getUserAddress, 10000); // setInterval(this.getUserAddress, 10000);
} else { } else {
console.log('web3 not connected, getting user address') console.log('web3 not connected, getting user address')
setInterval(this.getUserAddress, 500); // setInterval(this.getUserAddress, 500);
} }
}) })
} }
...@@ -136,11 +94,11 @@ class App extends Component { ...@@ -136,11 +94,11 @@ class App extends Component {
if(result.length > 0){ if(result.length > 0){
this.props.setCurrentMaskAddress(result[0]); this.props.setCurrentMaskAddress(result[0]);
this.props.metamaskUnlocked(); this.props.metamaskUnlocked();
this.props.web3ConnectionSuccessful(); this.props.setWeb3ConnectionStatus(true)
this.getContracts(); this.getContracts();
} else { } else {
this.props.metamaskLocked(); this.props.metamaskLocked();
this.props.web3ConnectionUnsuccessful(); this.props.setWeb3ConnectionStatus(false)
this.props.setInteractionState('locked'); this.props.setInteractionState('locked');
} }
}) })
...@@ -151,57 +109,15 @@ class App extends Component { ...@@ -151,57 +109,15 @@ class App extends Component {
if (result.length > 0) { if (result.length > 0) {
this.props.setCurrentMaskAddress(result[0]); this.props.setCurrentMaskAddress(result[0]);
this.props.metamaskUnlocked(); this.props.metamaskUnlocked();
this.props.web3ConnectionSuccessful(); this.props.setWeb3ConnectionStatus(true);
} }
else { else {
this.props.metamaskLocked(); this.props.metamaskLocked();
this.props.web3ConnectionUnsuccessful(); this.props.setWeb3ConnectionStatus(false);
this.props.setInteractionState('locked'); this.props.setInteractionState('locked');
} }
}) })
} }
checkNetwork = () => {
localweb3.eth.net.getNetworkType((err, networkId) => {
console.log("Connected to " + networkId)
switch (networkId) {
case "main":
this.props.setNetworkMessage('Ethereum Mainet');
this.props.web3ConnectionUnsuccessful();
this.props.setInteractionState('disconnected');
break;
case "morden":
this.props.setNetworkMessage('Morden testnet');
this.props.web3ConnectionUnsuccessful();
this.props.setInteractionState('disconnected');
break;
case "ropsten":
this.props.setNetworkMessage('Ropsten testnet');
this.props.web3ConnectionUnsuccessful();
this.props.setInteractionState('disconnected');
break;
case "rinkeby":
this.props.setNetworkMessage('Rinkeby testnet');
this.props.web3ConnectionSuccessful();
this.props.setInteractionState('connected');
break;
case "kovan":
this.props.setNetworkMessage('Kovan testnet');
this.props.web3ConnectionUnsuccessful();
this.props.setInteractionState('disconnected');
break;
default:
this.props.setNetworkMessage('an unknown network');
this.props.web3ConnectionUnsuccessful();
this.props.setInteractionState('disconnected');
}
})
}
// will require rewriting the connectionStatus reducer to take in true or falsa
// connectionSetter = (networkMessage, connectionStatus, interactionState) => {
// this.props.setNetworkMessage(networkMessage)
// }
// could possibly use refactoring // could possibly use refactoring
getContracts = () => { getContracts = () => {
...@@ -409,181 +325,6 @@ class App extends Component { ...@@ -409,181 +325,6 @@ class App extends Component {
}); });
} }
getExchangeRate = (input) => {
if (this.props.web3Store.exchangeType === 'ETH to Token') {
console.log('Getting Rate: ETH to ' + this.props.exchange.outputToken.value);
this.ethToTokenRate(input);
} else if (this.props.web3Store.exchangeType === 'Token to ETH') {
console.log('Getting Rate: ' + this.props.exchange.inputToken.value + ' to ETH');
this.tokenToEthRate(input);
} else if (this.props.web3Store.exchangeType === 'Token to Token') {
console.log('Getting Rate: ' + this.props.exchange.inputToken.value + ' to ' + this.props.exchange.outputToken.value);
this.tokenToTokenRate(input);
}
}
ethToTokenRate = (ethInput) => {
var ethInMarket = +this.props.exchange.marketEth2;
var tokensInMarket = +this.props.exchange.marketTokens2;
var invar = +this.props.exchange.invariant2;
var ethIn = ethInput*10**18;
var exchangeFee = ethIn/500;
var ethSold = ethIn - exchangeFee;
var newEthInMarket = ethInMarket + ethSold;
var newTokensInMarket = invar/newEthInMarket;
var tokensOut = tokensInMarket - newTokensInMarket;
var adjustedTokensOut = tokensOut * 0.98;
var buyRate = adjustedTokensOut/ethIn;
this.props.setExchangeRate(buyRate);
this.props.setExchangeFee(exchangeFee);
this.props.setExchangeOutputValue(adjustedTokensOut);
}
tokenToEthRate = (tokenInput) => {
var ethInMarket = +this.props.exchange.marketEth1;
var tokensInMarket = +this.props.exchange.marketTokens1;
var invar = +this.props.exchange.invariant1;
var tokensIn = tokenInput*10**18;
var exchangeFee = tokensIn/500;
var tokensSold = tokensIn - exchangeFee;
var newTokensInMarket = tokensInMarket + tokensSold;
var newEthInMarket = invar/newTokensInMarket;
var ethOut = ethInMarket - newEthInMarket;
var adjustedEthOut = ethOut * 0.98;
var buyRate = adjustedEthOut/tokensIn;
this.props.setExchangeRate(buyRate);
this.props.setExchangeFee(exchangeFee);
this.props.setExchangeOutputValue(adjustedEthOut);
}
tokenToTokenRate = (tokenInput) => {
// Token to ETH on Exchange 1
var ethInMarket1 = +this.props.exchange.marketEth1;
var tokensInMarket1 = +this.props.exchange.marketTokens1;
var invar1 = +this.props.exchange.invariant1;
var tokensIn = tokenInput*10**18;
var exchangeFee1 = tokensIn/500;
var tokensSold = tokensIn - exchangeFee1;
var newTokensInMarket1 = tokensInMarket1 + tokensSold;
var newEthInMarket1 = invar1/newTokensInMarket1;
var ethToExchange2 = ethInMarket1 - newEthInMarket1;
// ETH to Token on Exchange 2
var ethInMarket2 = +this.props.exchange.marketEth2;
var tokensInMarket2 = +this.props.exchange.marketTokens2;
var invar2 = +this.props.exchange.invariant2;
var exchangeFee2 = ethToExchange2/500;
var ethSold = ethToExchange2 - exchangeFee2;
var newEthInMarket2 = ethInMarket2 + ethSold;
var newTokensInMarket2 = invar2/newEthInMarket2;
var tokensOut = tokensInMarket2 - newTokensInMarket2;
var adjustedTokensOut = tokensOut * 0.98;
var buyRate = adjustedTokensOut/tokensIn;
this.props.setExchangeRate(buyRate);
this.props.setExchangeFee(exchangeFee1);
this.props.setExchangeOutputValue(adjustedTokensOut);
}
purchaseTokens = async () => {
await this.props.setBlockTimestamp(this.props.web3Store.globalWeb3);
if (this.props.web3Store.exchangeType === 'ETH to Token') {
this.ethToTokenPurchase();
} else if (this.props.web3Store.exchangeType === 'Token to ETH') {
this.tokenToEthPurchase();
} else if (this.props.web3Store.exchangeType=== 'Token to Token') {
this.tokenToTokenPurchase();
}
}
// YOU ARE HERE NOW
ethToTokenPurchase = () => {
var exchange = this.symbolToExchangeContract(this.props.exchange.outputToken.value);
var minTokens = (this.props.exchange.outputValue/10**18).toString();
var minTokensInt = localweb3.utils.toWei(minTokens);
var ethSold = this.props.exchange.inputValue;
var weiSold = localweb3.utils.toWei(ethSold);
var timeout = this.props.web3Store.blockTimestamp + 300; //current block time + 5mins
// console.log(minTokensInt, weiSold, timeout);
exchange.methods.ethToTokenSwap(minTokensInt, timeout).send({from: this.props.web3Store.currentMaskAddress, value: weiSold})
.on('transactionHash', (result) => {
console.log('Transaction Hash created')
let transactions = this.state.transactions
transactions.push(result);
// transactions is cookie stuff, we'll keep that in state
this.setState({ transactions: transactions })
// any particular reason why there are initialized as 0, but get turned to empty strings after the transaction is over?
this.props.setExchangeInputValue('');
this.props.setExchangeOutputValue('');
this.props.setInteractionState('submitted');
cookie.save('transactions', transactions, { path: '/' })
})
.on('receipt', (receipt) => {
console.log(receipt)
}) //Transaction Submitted to blockchain
.on('confirmation', (confirmationNumber, receipt) => {
console.log("Block Confirmations: " + confirmationNumber)
if(confirmationNumber === 1) {
this.getAccountInfo();
}
}) //Transaction Mined
.on('error', console.error);
}
// tokenToEth and EthToToken purchase functions are very similar structurally
// maybe we can make this more DRY in refactor
tokenToEthPurchase = () => {
var exchange = this.symbolToExchangeContract(this.props.exchange.inputToken.value);
var minEth = (this.props.exchange.outputValue/10**18).toString();
var minEthInt = localweb3.utils.toWei(minEth);
var tokensSold = this.props.exchange.inputValue;
var tokensSoldInt = localweb3.utils.toWei(tokensSold);
var timeout = this.props.web3Store.blockTimestamp + 300; //current block time + 5mins
exchange.methods.tokenToEthSwap(tokensSoldInt, minEthInt, timeout).send({from: this.props.web3Store.currentMaskAddress})
.on('transactionHash', (result) => {
console.log('Transaction Hash created')
let transactions = this.state.transactions
transactions.push(result)
this.setState({ transactions: transactions });
this.props.setExchangeInputValue('');
this.props.setExchangeOutputValue('');
this.props.setInteractionState('submitted');
cookie.save('transactions', transactions, { path: '/' })
})
.on('receipt', (receipt) => {console.log(receipt)}) //Transaction Submitted to blockchain
.on('confirmation', (confirmationNumber, receipt) => {console.log("Block Confirmations: " + confirmationNumber)}) //Transaction Mined
.on('error', console.error);
}
tokenToTokenPurchase = () => {
var exchange = this.symbolToExchangeContract(this.props.exchange.inputToken.value);
var tokenOutAddress = this.symbolToTokenAddress(this.props.exchange.outputToken.value);
var minTokens = (this.props.exchange.outputValue/10**18).toString();
var minTokensInt = localweb3.utils.toWei(minTokens);
var tokensSold = this.props.exchange.inputValue;
var tokensSoldInt = localweb3.utils.toWei(tokensSold);
var timeout = this.props.web3Store.blockTimestamp + 300; //current block time + 5mins
console.log('tokenOutAddress', tokenOutAddress);
console.log('minTokensInt', minTokensInt);
console.log('tokensSoldInt', tokensSoldInt);
console.log('timeout', timeout);
exchange.methods.tokenToTokenSwap(tokenOutAddress, tokensSoldInt, minTokensInt, timeout).send({from: this.props.web3Store.currentMaskAddress})
.on('transactionHash', (result) => {
console.log('Transaction Hash created')
let transactions = this.state.transactions
transactions.push(result)
this.setState({ transactions: transactions });
this.props.setExchangeInputValue('');
this.props.setExchangeOutputValue('');
this.props.setInteractionState('submitted');
cookie.save('transactions', transactions, { path: '/' })
})
.on('receipt', (receipt) => {console.log(receipt)}) //Transaction Submitted to blockchain
.on('confirmation', (confirmationNumber, receipt) => {console.log("Block Confirmations: " + confirmationNumber)}) //Transaction Mined
.on('error', console.error);
}
onCloseHelper = () => { onCloseHelper = () => {
if(this.props.exchange.outputToken.value === 'UNI'){ if(this.props.exchange.outputToken.value === 'UNI'){
this.setState({ uniAdded: true }) // cookie stuff this.setState({ uniAdded: true }) // cookie stuff
...@@ -597,50 +338,34 @@ class App extends Component { ...@@ -597,50 +338,34 @@ class App extends Component {
} }
} }
toggleAbout = () => {
let current = this.props.web3Store.aboutToggle;
this.props.toggleAbout(!current);
setTimeout(this.scrollToAbout, 300);
}
scrollToAbout = () => {
scrollToComponent(this.About, { offset: 0, align: 'top', duration: 500})
}
render() { render() {
return ( return (
<div className={this.props.web3Store.connected && !this.props.web3Store.metamaskLocked && this.props.web3Store.interaction !== 'disconnected' ? "App" : "App dim"}> <div className={this.props.web3Store.connected && !this.props.web3Store.metamaskLocked && this.props.web3Store.interaction !== 'disconnected' ? "App" : "App dim"}>
<Head /> <UniHead />
<section className="title"> <Header metamask={this.props.metamask}/>
<div className="logo border pa2">
<span role="img" aria-label="Unicorn">🦄</span>
</div>
<NetworkStatus
network={this.props.web3Store.networkMessage}
connected={this.props.web3Store.connected}
metamask={this.props.metamask}
interaction={this.props.web3Store.interaction}
address={this.props.web3Store.currentMaskAddress}
locked={this.props.web3Store.metamaskLocked}
balance={this.props.exchange.inputBalance}
/>
</section>
<ConnectionHelper <ConnectionHelper
network={this.props.web3Store.networkMessage}
connected={this.props.web3Store.connected}
metamask={this.props.metamask} metamask={this.props.metamask}
address={this.props.web3Store.currentMaskAddress}
locked={this.props.web3Store.metamaskLocked}
approved={this.props.exchange.allowanceApproved}
tokenAdded={this.state.tokenAdded}
approveAllowance={this.approveAllowance} approveAllowance={this.approveAllowance}
interaction={this.props.web3Store.interaction}
exchangeType={this.props.web3Store.exchangeType}
firstRun={this.state.firstRun} firstRun={this.state.firstRun}
uniAdded={this.state.uniAdded} uniAdded={this.state.uniAdded}
swapAdded={this.state.swapAdded} swapAdded={this.state.swapAdded}
onCloseHelper={this.onCloseHelper} onCloseHelper={this.onCloseHelper}
input={this.props.exchange.inputValue}
balance={this.props.exchange.inputBalance}
toggleAbout={this.toggleAbout} toggleAbout={this.toggleAbout}
inputToken={this.props.exchange.inputToken}
outputToken={this.props.exchange.outputToken}
about={this.state.about}
/> />
<Order <Exchange
getAccountInfo={this.getAccountInfo} getAccountInfo={this.getAccountInfo}
getMarketInfo={this.getMarketInfo} getMarketInfo={this.getMarketInfo}
getExchangeRate={this.getExchangeRate}
symbolToTokenContract={this.symbolToTokenContract} symbolToTokenContract={this.symbolToTokenContract}
symbolToExchangeAddress={this.symbolToExchangeAddress} symbolToExchangeAddress={this.symbolToExchangeAddress}
/> />
...@@ -650,15 +375,11 @@ class App extends Component { ...@@ -650,15 +375,11 @@ class App extends Component {
inputTokenValue={this.props.exchange.inputToken.value} inputTokenValue={this.props.exchange.inputToken.value}
exchangeFee={this.props.exchange.fee} exchangeFee={this.props.exchange.fee}
/> />
<Swap <Purchase
interaction={this.props.web3Store.interaction} symbolToExchangeContract={this.symbolToExchangeContract}
inputValue={this.props.exchange.inputValue } symbolToTokenAddress={this.symbolToTokenAddress}
inputTokenValue={this.props.exchange.inputToken.value} />
outputValue={this.props.exchange.outputValue} <About toggleAbout={this.toggleAbout} location={this}/>
outputTokenValue={this.props.exchange.outputToken.value}
purchaseTokens={this.purchaseTokens}
/>
<About />
<Links /> <Links />
<Transactions transactions={this.state.transactions} interaction={this.props.web3Store.interaction} /> <Transactions transactions={this.state.transactions} interaction={this.props.web3Store.interaction} />
</div> </div>
...@@ -675,8 +396,7 @@ const mapStateToProps = state => ({ ...@@ -675,8 +396,7 @@ const mapStateToProps = state => ({
const mapDispatchToProps = (dispatch) => { const mapDispatchToProps = (dispatch) => {
return bindActionCreators({ return bindActionCreators({
web3ConnectionSuccessful, setWeb3ConnectionStatus,
web3ConnectionUnsuccessful,
setCurrentMaskAddress, setCurrentMaskAddress,
metamaskLocked, metamaskLocked,
metamaskUnlocked, metamaskUnlocked,
...@@ -686,13 +406,8 @@ const mapDispatchToProps = (dispatch) => { ...@@ -686,13 +406,8 @@ const mapDispatchToProps = (dispatch) => {
swtExchangeContractReady, swtExchangeContractReady,
uniTokenContractReady, uniTokenContractReady,
swtTokenContractReady, swtTokenContractReady,
setNetworkMessage,
setBlockTimestamp,
setExchangeType,
setInputBalance, setInputBalance,
setOutputBalance, setOutputBalance,
setInputToken,
setOutputToken,
setInvariant1, setInvariant1,
setInvariant2, setInvariant2,
setMarketEth1, setMarketEth1,
...@@ -700,11 +415,8 @@ const mapDispatchToProps = (dispatch) => { ...@@ -700,11 +415,8 @@ const mapDispatchToProps = (dispatch) => {
setMarketTokens1, setMarketTokens1,
setMarketTokens2, setMarketTokens2,
setAllowanceApprovalState, setAllowanceApprovalState,
setExchangeInputValue, initializeGlobalWeb3,
setExchangeOutputValue, toggleAbout
setExchangeRate,
setExchangeFee,
initializeGlobalWeb3
}, dispatch) }, dispatch)
} }
......
import { INITIALIZE_GLOBAL_WEB3 } from '../constants';
export const initializeGlobalWeb3 = (globalWeb3) => ({
type: INITIALIZE_GLOBAL_WEB3,
globalWeb3
})
\ No newline at end of file
import { import {
WEB3_CONNECTION_SUCCESSFUL, SET_WEB3_CONNECTION_STATUS,
WEB3_CONNECTION_UNSUCCESSFUL,
SET_CURRENT_MASK_ADDRESS, SET_CURRENT_MASK_ADDRESS,
METAMASK_LOCKED, METAMASK_LOCKED,
METAMASK_UNLOCKED, METAMASK_UNLOCKED,
...@@ -9,21 +8,16 @@ import { ...@@ -9,21 +8,16 @@ import {
SET_NETWORK_MESSAGE, SET_NETWORK_MESSAGE,
SET_BLOCK_TIMESTAMP, SET_BLOCK_TIMESTAMP,
SET_EXCHANGE_TYPE, SET_EXCHANGE_TYPE,
INITIALIZE_GLOBAL_WEB3 TOGGLE_ABOUT
} from '../constants'; } from '../constants';
// this actions folder is actually full of action creators // this actions folder is actually full of action creators
// your asynchronous calls are going to be in redux-thunk style action creators // your asynchronous calls are going to be in redux-thunk style action creators
export const web3ConnectionSuccessful = () => ({ export const setWeb3ConnectionStatus = (connected) => ({
type: WEB3_CONNECTION_SUCCESSFUL, type: SET_WEB3_CONNECTION_STATUS,
connected: true connected
}); })
export const web3ConnectionUnsuccessful = () => ({
type: WEB3_CONNECTION_UNSUCCESSFUL,
connected: false
});
export const setCurrentMaskAddress = (currentMaskAddress) => ({ export const setCurrentMaskAddress = (currentMaskAddress) => ({
type: SET_CURRENT_MASK_ADDRESS, type: SET_CURRENT_MASK_ADDRESS,
...@@ -43,17 +37,41 @@ export const metamaskUnlocked = () => ({ ...@@ -43,17 +37,41 @@ export const metamaskUnlocked = () => ({
export const setInteractionState = (interaction) => ({ export const setInteractionState = (interaction) => ({
type: SET_INTERACTION_STATE, type: SET_INTERACTION_STATE,
interaction interaction
}); })
export const factoryContractReady = (factoryContract) => ({ export const factoryContractReady = (factoryContract) => ({
type: FACTORY_CONTRACT_READY, type: FACTORY_CONTRACT_READY,
factoryContract factoryContract
}); });
export const setNetworkMessage = (networkMessage) => ({ export const setNetworkMessage = (networkMessage) => {
type: SET_NETWORK_MESSAGE, return async (dispatch) => {
networkMessage let networkName;
}); switch (networkMessage) {
case "main":
networkName = 'Ethereum Mainet'
break;
case "morden":
networkName = 'Morden testnet'
break;
case "ropsten":
networkName = 'Ropsten testnet'
break;
case "rinkeby":
networkName = 'Rinkeby testnet'
break;
case "kovan":
networkName = 'Kovan testnet'
break;
default:
networkName = 'an unknown network'
}
dispatch ({
type: SET_NETWORK_MESSAGE,
networkMessage: networkName
})
}
};
export const setBlockTimestamp = () => { export const setBlockTimestamp = () => {
return async (dispatch, getState) => { return async (dispatch, getState) => {
...@@ -73,7 +91,7 @@ export const setExchangeType = (exchangeType) => ({ ...@@ -73,7 +91,7 @@ export const setExchangeType = (exchangeType) => ({
exchangeType exchangeType
}); });
export const initializeGlobalWeb3 = (globalWeb3) => ({ export const toggleAbout = (toggle) => ({
type: INITIALIZE_GLOBAL_WEB3, type: TOGGLE_ABOUT,
globalWeb3 aboutToggle: toggle
}) })
\ No newline at end of file
import React, { Component } from 'react'; import React, { Component } from 'react';
import AboutMessage from './AboutMessage'; import { connect } from 'react-redux';
import scrollToComponent from 'react-scroll-to-component';
export default class About extends Component {
constructor (props) {
super(props)
this.state = { toggled: false }
}
toggleAbout = () => {
this.setState({toggled: !this.state.toggled})
setTimeout(this.scrollToAbout, 300);
}
scrollToAbout = () => { import AboutMessage from './AboutMessage';
scrollToComponent(this.About, { offset: 0, align: 'top', duration: 500})
}
class About extends Component {
render () { render () {
const { toggled } = this.state;
return( return(
<div> <div>
<section className="About" ref={(section) => { this.About = section; }}> <section className="About" ref={(section) => { this.props.location.About = section; }}>
<a onClick={() => {this.toggleAbout()}} className="link border pa2 f-a"> <a onClick={() => {this.props.toggleAbout()}} className="link border pa2 f-a">
<p className="underline">About Uniswap.</p> <p className="underline">About Uniswap.</p>
<p></p> <p></p>
</a> </a>
</section> </section>
<AboutMessage toggled={toggled} /> <AboutMessage toggled={this.props.web3Store.aboutToggle} />
</div> </div>
) )
} }
} }
const mapStateToProps = state => ({
web3Store: state.web3Store
});
export default connect (mapStateToProps)(About)
\ No newline at end of file
import React from 'react'; import React from 'react';
import { connect } from 'react-redux';
function ConnectionHelper(props) { function ConnectionHelper(props) {
if (!props.metamask) { if (!props.metamask) {
...@@ -8,53 +9,53 @@ function ConnectionHelper(props) { ...@@ -8,53 +9,53 @@ function ConnectionHelper(props) {
<b>To get started, please install <a href="https://metamask.io/">Metamask</a>.</b></p> <b>To get started, please install <a href="https://metamask.io/">Metamask</a>.</b></p>
</div> </div>
) )
} else if (props.connected && props.interaction === 'disconnected') { } else if (props.web3Store.connected && props.web3Store.interaction === 'disconnected') {
return ( return (
<div className="grey-bg connection border pa2"> <div className="grey-bg connection border pa2">
<p>Welcome! Uniswap is a decentralized exhange platform for ERC20 Tokens. <a onClick={() => {props.toggleAbout()}} className="f-a" >How it works </a><br /><br /> <p>Welcome! Uniswap is a decentralized exhange platform for ERC20 Tokens. <a onClick={() => {props.toggleAbout()}} className="f-a" >How it works </a><br /><br />
Looks like you aren't connected. <b>Please switch to the correct network.</b></p> Looks like you aren't connected. <b>Please switch to the correct network.</b></p>
</div> </div>
) )
} else if (props.locked) { } else if (props.web3Store.metamaskLocked) {
return ( return (
<div className="grey-bg connection border pa2"> <div className="grey-bg connection border pa2">
<p>Welcome! Uniswap is a decentralized exhange platform for ERC20 Tokens. <a onClick={() => {props.toggleAbout()}} className="f-a" >How it works ↘</a><br /><br /> <p>Welcome! Uniswap is a decentralized exhange platform for ERC20 Tokens. <a onClick={() => {props.toggleAbout()}} className="f-a" >How it works ↘</a><br /><br />
Looks like you aren't connected. <b>Please unlock Metamask to continue.</b></p> Looks like you aren't connected. <b>Please unlock Metamask to continue.</b></p>
</div> </div>
) )
} else if (props.interaction === "error1") { } else if (props.web3Store.interaction === "error1") {
return ( return (
<div className="grey-bg connection border pa2"> <div className="grey-bg connection border pa2">
<p>You can't swap a token for itself! <span role="img" aria-label="Crying">😂</span></p> <p>You can't swap a token for itself! <span role="img" aria-label="Crying">😂</span></p>
</div> </div>
) )
} else if (props.interaction === "submitted") { } else if (props.web3Store.interaction === "submitted") {
return ( return (
<div className="grey-bg connection border pa2"> <div className="grey-bg connection border pa2">
<p>{"Transaction submitted! Click on the transaction hash below to check its status?"}</p> <p>{"Transaction submitted! Click on the transaction hash below to check its status?"}</p>
</div> </div>
) )
} else if (props.input > props.balance/10**18 && props.inputToken.value === 'ETH') { } else if (props.exchange.inputValue > props.exchange.inputBalance/10**18 && props.exchange.inputToken.value === 'ETH') {
return ( return (
<div className="grey-bg red connection border pa2"> <div className="grey-bg red connection border pa2">
<p>This account doesn't have enough balance to make this transaction! Get more {props.inputToken.value} with the <a target="_blank" rel="noopener noreferrer" href="https://faucet.rinkeby.io/">Rinkeby Faucet.</a></p> <p>This account doesn't have enough balance to make this transaction! Get more {props.exchange.inputToken.value} with the <a target="_blank" rel="noopener noreferrer" href="https://faucet.rinkeby.io/">Rinkeby Faucet.</a></p>
</div> </div>
) )
} else if (!props.approved && props.exchangeType === "Token to Token") { } else if (!props.exchange.allowanceApproved && props.web3Store.exchangeType === "Token to Token") {
return ( return (
<div className="grey-bg connection border pa2"> <div className="grey-bg connection border pa2">
<p>Our smart contract has to be approved by your address to be able to swap this token for other tokens.<br /> We set a high transfer limit for the demo (<a onClick={() => {props.toggleAbout()}} className="f-a">Why?</a>).</p> <p>Our smart contract has to be approved by your address to be able to swap this token for other tokens.<br /> We set a high transfer limit for the demo (<a onClick={() => {props.toggleAbout()}} className="f-a">Why?</a>).</p>
<a className="f-a" onClick={() => props.approveAllowance()}>Approve </a> <a className="f-a" onClick={() => props.approveAllowance()}>Approve </a>
</div> </div>
) )
} else if (!props.approved && props.exchangeType === "Token to ETH") { } else if (!props.exchange.allowanceApproved && props.web3Store.exchangeType === "Token to ETH") {
return ( return (
<div className="grey-bg connection border pa2"> <div className="grey-bg connection border pa2">
<p>Our smart contract has to be approved by your address to be able to swap this token for ETH.<br /> We set a high transfer limit for the demo (<a onClick={() => {props.toggleAbout()}} className="f-a">Why?</a>).</p> <p>Our smart contract has to be approved by your address to be able to swap this token for ETH.<br /> We set a high transfer limit for the demo (<a onClick={() => {props.toggleAbout()}} className="f-a">Why?</a>).</p>
<a className="f-a" onClick={() => props.approveAllowance()}>Approve </a> <a className="f-a" onClick={() => props.approveAllowance()}>Approve </a>
</div> </div>
) )
} else if (!props.uniAdded && props.outputToken.value === "UNI") { } else if (!props.uniAdded && props.exchange.outputToken.value === "UNI") {
return ( return (
<div className="grey-bg connection border pa2"> <div className="grey-bg connection border pa2">
<p>Welcome! Uniswap is a decentralized exhange platform for ERC20 Tokens. <a onClick={() => {props.toggleAbout()}} className="f-a" >How it works </a><br /><br /> <p>Welcome! Uniswap is a decentralized exhange platform for ERC20 Tokens. <a onClick={() => {props.toggleAbout()}} className="f-a" >How it works </a><br /><br />
...@@ -63,7 +64,7 @@ function ConnectionHelper(props) { ...@@ -63,7 +64,7 @@ function ConnectionHelper(props) {
<a className="f-a" onClick={() => props.onCloseHelper()}>I've added the token</a> <a className="f-a" onClick={() => props.onCloseHelper()}>I've added the token</a>
</div> </div>
) )
} else if (!props.swapAdded && props.outputToken.value === "SWAP") { } else if (!props.swapAdded && props.exchange.outputToken.value === "SWAP") {
return ( return (
<div className="grey-bg connection border pa2"> <div className="grey-bg connection border pa2">
<p>Welcome! Uniswap is a decentralized exhange platform for ERC20 Tokens. <a onClick={() => {props.toggleAbout()}} className="f-a" >How it works</a>.<br /><br /> <p>Welcome! Uniswap is a decentralized exhange platform for ERC20 Tokens. <a onClick={() => {props.toggleAbout()}} className="f-a" >How it works</a>.<br /><br />
...@@ -72,10 +73,10 @@ function ConnectionHelper(props) { ...@@ -72,10 +73,10 @@ function ConnectionHelper(props) {
<a className="f-a" onClick={() => props.onCloseHelper()}>I've added the token</a> <a className="f-a" onClick={() => props.onCloseHelper()}>I've added the token</a>
</div> </div>
) )
} else if (props.input > props.balance/10**18) { } else if (props.exchange.inputValue > props.exchange.inputBalance/10**18) {
return ( return (
<div className="grey-bg red connection border pa2"> <div className="grey-bg red connection border pa2">
<p>{"This account doesn't have enough balance to make this transaction! You'll need to swap some ETH for " + props.inputToken.value + "."}</p> <p>{"This account doesn't have enough balance to make this transaction! You'll need to swap some ETH for " + props.exchange.inputToken.value + "."}</p>
</div> </div>
) )
} else { } else {
...@@ -89,4 +90,10 @@ function ConnectionHelper(props) { ...@@ -89,4 +90,10 @@ function ConnectionHelper(props) {
} }
} }
export default ConnectionHelper; const mapStateToProps = state => ({
web3Store: state.web3Store,
exchange: state.exchange
});
export default connect(mapStateToProps)(ConnectionHelper);
...@@ -2,31 +2,16 @@ import React, { Component }from 'react'; ...@@ -2,31 +2,16 @@ import React, { Component }from 'react';
import SelectToken from './SelectToken'; import SelectToken from './SelectToken';
import { bindActionCreators } from 'redux'; import { bindActionCreators } from 'redux';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { subscribe } from 'redux-subscriber';
import { setInteractionState, setExchangeType } from '../actions/web3-actions'; import { setInteractionState, setExchangeType } from '../actions/web3-actions';
import { import { setExchangeInputValue, setExchangeOutputValue, setExchangeRate, setExchangeFee, setInputToken, setOutputToken, setInputBalance, setOutputBalance, setAllowanceApprovalState } from '../actions/exchange-actions';
setExchangeInputValue,
setExchangeOutputValue,
setExchangeRate,
setExchangeFee,
setInputToken,
setOutputToken,
setInputBalance,
setOutputBalance,
setAllowanceApprovalState
} from '../actions/exchange-actions';
class Order extends Component { class Exchange extends Component {
constructor (props){
super(props)
}
// props and functions ready
onInputChange = async (event) => { onInputChange = async (event) => {
var inputValue = event.target.value; var inputValue = event.target.value;
await this.props.setExchangeInputValue(inputValue); await this.props.setExchangeInputValue(inputValue);
this.setExchangeOutput(); this.setExchangeOutput();
} }
// props ready,
onSelectToken = async (selected, type) => { onSelectToken = async (selected, type) => {
this.props.setExchangeInputValue(0); this.props.setExchangeInputValue(0);
this.props.setExchangeOutputValue(0); this.props.setExchangeOutputValue(0);
...@@ -57,13 +42,12 @@ class Order extends Component { ...@@ -57,13 +42,12 @@ class Order extends Component {
} else if(inputValue && inputValue !== 0 && inputValue !== '0'){ } else if(inputValue && inputValue !== 0 && inputValue !== '0'){
this.props.setInteractionState('input'); this.props.setInteractionState('input');
// another function to be pulled out into HOC // another function to be pulled out into HOC
this.props.getExchangeRate(inputValue); this.getExchangeRate(inputValue);
} else { } else {
this.props.setExchangeOutputValue(0); this.props.setExchangeOutputValue(0);
this.props.setInteractionState('connected'); this.props.setInteractionState('connected');
} }
} }
// props ready // props ready
// TODO: change this to use the redux-subscribe pattern // TODO: change this to use the redux-subscribe pattern
getMarketType = () => { getMarketType = () => {
...@@ -83,82 +67,81 @@ class Order extends Component { ...@@ -83,82 +67,81 @@ class Order extends Component {
console.log('input: ', this.props.exchange.inputToken.value); console.log('input: ', this.props.exchange.inputToken.value);
console.log('output: ', this.props.exchange.outputToken.value); console.log('output: ', this.props.exchange.outputToken.value);
} }
// we are here
// TODO: change this to use the redux-subscribe pattern
getAccountInfo = () => {
switch (this.props.web3Store.exchangeType) {
case 'ETH to Token':
this.getEthBalance('input');
this.getTokenBalance('output');
break;
case 'Token to ETH':
this.getEthBalance('output');
this.getTokenBalance('input');
this.getAllowance();
break;
case 'Token to Token':
this.getTokenBalance('input');
this.getTokenBalance('output');
this.getAllowance();
break;
default:
}
console.log("Getting account info");
}
// props ready getExchangeRate = (input) => {
// TODO: TODO: TODO: TURN THIS INTO A REDUX-SUBSCRIBE LISTENER NOW!!! if (this.props.web3Store.exchangeType === 'ETH to Token') {
getEthBalance = (type) => { console.log('Getting Rate: ETH to ' + this.props.exchange.outputToken.value);
// this.props.web3Store.globalWeb3 this.ethToTokenRate(input);
if (type === 'input') { } else if (this.props.web3Store.exchangeType === 'Token to ETH') {
this.props.web3Store.globalWeb3.eth.getBalance(this.props.web3Store.currentMaskAddress, (error, balance) => { console.log('Getting Rate: ' + this.props.exchange.inputToken.value + ' to ETH');
this.props.setInputBalance(balance); this.tokenToEthRate(input);
// console.log('ETH Balance: ' + balance); } else if (this.props.web3Store.exchangeType === 'Token to Token') {
}); console.log('Getting Rate: ' + this.props.exchange.inputToken.value + ' to ' + this.props.exchange.outputToken.value);
} else if (type === 'output') { this.tokenToTokenRate(input);
this.props.web3Store.globalWeb3.eth.getBalance(this.props.web3Store.currentMaskAddress, (error, balance) => {
this.props.setOutputBalance(balance);
// console.log('ETH Balance: ' + balance);
});
} }
} }
// props ready
// TODO: this might also be able to change to the redux-subscribe method ethToTokenRate = (ethInput) => {
getTokenBalance = (type) => { var ethInMarket = +this.props.exchange.marketEth2;
var token; var tokensInMarket = +this.props.exchange.marketTokens2;
if (type === 'input') { var invar = +this.props.exchange.invariant2;
token = this.symbolToTokenContract(this.props.exchange.inputToken.value); var ethIn = ethInput*10**18;
token.methods.balanceOf(this.props.web3Store.currentMaskAddress).call((error, balance) => { var exchangeFee = ethIn/500;
this.props.setInputBalance(balance); var ethSold = ethIn - exchangeFee;
// console.log(this.props.exchange.inputToken.value + ' Balance: ' + balance); var newEthInMarket = ethInMarket + ethSold;
}); var newTokensInMarket = invar/newEthInMarket;
} else if (type === 'output') { var tokensOut = tokensInMarket - newTokensInMarket;
token = this.symbolToTokenContract(this.props.exchange.outputToken.value); var adjustedTokensOut = tokensOut * 0.98;
token.methods.balanceOf(this.props.web3Store.currentMaskAddress).call((error, balance) => { var buyRate = adjustedTokensOut/ethIn;
this.props.setOutputBalance(balance); this.props.setExchangeRate(buyRate);
// console.log(this.props.exchange.outputToken.value + ' Balance: ' + balance); this.props.setExchangeFee(exchangeFee);
}); this.props.setExchangeOutputValue(adjustedTokensOut);
}
} }
// TODO: refactor to redux-subscribe
// props ready
getAllowance = () => {
var type = this.props.web3Store.exchangeType;
if(type === 'Token to ETH' || type === 'Token to Token') {
// another pair of functions to be exported to a HOC
var token = this.props.symbolToTokenContract(this.props.exchange.inputToken.value);
var exchangeAddress = this.props.symbolToExchangeAddress(this.props.exchange.inputToken.value);
token.methods.allowance(this.props.web3Store.currentMaskAddress, exchangeAddress).call().then((result, error) => { tokenToEthRate = (tokenInput) => {
console.log(this.props.exchange.inputToken.value + ' allowance: ' + result); var ethInMarket = +this.props.exchange.marketEth1;
if(result === '0'){ var tokensInMarket = +this.props.exchange.marketTokens1;
this.props.setAllowanceApprovalState(false) var invar = +this.props.exchange.invariant1;
console.log(this.props.exchange.allowanceApproved) var tokensIn = tokenInput*10**18;
} var exchangeFee = tokensIn/500;
}) var tokensSold = tokensIn - exchangeFee;
} var newTokensInMarket = tokensInMarket + tokensSold;
var newEthInMarket = invar/newTokensInMarket;
var ethOut = ethInMarket - newEthInMarket;
var adjustedEthOut = ethOut * 0.98;
var buyRate = adjustedEthOut/tokensIn;
this.props.setExchangeRate(buyRate);
this.props.setExchangeFee(exchangeFee);
this.props.setExchangeOutputValue(adjustedEthOut);
} }
tokenToTokenRate = (tokenInput) => {
// Token to ETH on Exchange 1
var ethInMarket1 = +this.props.exchange.marketEth1;
var tokensInMarket1 = +this.props.exchange.marketTokens1;
var invar1 = +this.props.exchange.invariant1;
var tokensIn = tokenInput*10**18;
var exchangeFee1 = tokensIn/500;
var tokensSold = tokensIn - exchangeFee1;
var newTokensInMarket1 = tokensInMarket1 + tokensSold;
var newEthInMarket1 = invar1/newTokensInMarket1;
var ethToExchange2 = ethInMarket1 - newEthInMarket1;
// ETH to Token on Exchange 2
var ethInMarket2 = +this.props.exchange.marketEth2;
var tokensInMarket2 = +this.props.exchange.marketTokens2;
var invar2 = +this.props.exchange.invariant2;
var exchangeFee2 = ethToExchange2/500;
var ethSold = ethToExchange2 - exchangeFee2;
var newEthInMarket2 = ethInMarket2 + ethSold;
var newTokensInMarket2 = invar2/newEthInMarket2;
var tokensOut = tokensInMarket2 - newTokensInMarket2;
var adjustedTokensOut = tokensOut * 0.98;
var buyRate = adjustedTokensOut/tokensIn;
this.props.setExchangeRate(buyRate);
this.props.setExchangeFee(exchangeFee1);
this.props.setExchangeOutputValue(adjustedTokensOut);
}
render () { render () {
return ( return (
<section className="order"> <section className="order">
...@@ -178,13 +161,12 @@ class Order extends Component { ...@@ -178,13 +161,12 @@ class Order extends Component {
</section> </section>
) )
} }
} }
const mapStateToProps = state => ({ const mapStateToProps = state => ({
web3Store: state.web3Store, web3Store: state.web3Store,
exchange: state.exchange exchange: state.exchange
}) })
const mapDispatchToProps = (dispatch) => { const mapDispatchToProps = (dispatch) => {
return bindActionCreators({ return bindActionCreators({
...@@ -202,4 +184,4 @@ const mapStateToProps = state => ({ ...@@ -202,4 +184,4 @@ const mapStateToProps = state => ({
}, dispatch); }, dispatch);
} }
export default connect(mapStateToProps, mapDispatchToProps)(Order); export default connect(mapStateToProps, mapDispatchToProps)(Exchange);
\ No newline at end of file \ No newline at end of file
import React from 'react';
import NetworkStatus from '../components/NetworkStatus';
function Header (props){
return (
<section className="title">
<div className="logo border pa2">
<span role="img" aria-label="Unicorn">🦄</span>
</div>
<NetworkStatus metamask={props.metamask}/>
</section>
)
}
export default Header;
\ No newline at end of file
import React from 'react'; import React, { Component }from 'react';
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import { setWeb3ConnectionStatus, setInteractionState, setNetworkMessage } from '../actions/web3-actions';
function NetworkStatus(props) { class NetworkStatus extends Component {
let isConnected = props.connected componentDidMount(){
let metamask = props.metamask if (this.props.global.web3 !== undefined){
let locked = props.locked this.checkNetwork();
}
}
checkNetwork = () => {
this.props.global.web3.eth.net.getNetworkType((err, networkId) => {
console.log("Connected to " + networkId)
let interactionState = networkId === 'rinkeby' ? 'connected' : 'disconnected';
let connectionStatus = networkId === 'rinkeby' ? true : false;
this.props.setNetworkMessage(networkId);
this.props.setWeb3ConnectionStatus(connectionStatus);
this.props.setInteractionState(interactionState);
})
}
if (isConnected && props.interaction !== 'disconnected'){ render () {
return ( if (this.props.web3Store.connected && this.props.web3Store.interaction !== 'disconnected'){
<div className="connection border pa2 green"> return (
<a target="_blank" rel="noopener noreferrer" href={'https://rinkeby.etherscan.io/search?q=' + props.address}>{props.address}</a> <div className="connection border pa2 green">
<p></p> <a target="_blank" rel="noopener noreferrer" href={'https://rinkeby.etherscan.io/search?q=' + this.props.web3Store.currentMaskAddress}>{this.props.web3Store.currentMaskAddress}</a>
</div> <p></p>
) </div>
} else if (!metamask) { )
return ( } else if (!this.props.metamask) {
<div className="connection red border pa2"> return (
<p>{"Waiting for connection to the blockchain..."}</p> <div className="connection red border pa2">
<p></p> <p>{"Waiting for connection to the blockchain..."}</p>
</div> <p></p>
) </div>
} else if (locked && !isConnected) { )
return ( } else if (this.props.web3Store.metamaskLocked && !this.props.web3Store.connected) {
<div className="connection yellow border pa2"> return (
<p>{"Waiting for Metamask to unlock..."}</p> <div className="connection yellow border pa2">
<p></p> <p>{"Waiting for Metamask to unlock..."}</p>
</div> <p></p>
) </div>
} else { )
return ( } else {
<div className="connection yellow border pa2"> return (
<p>{'MetaMask connected to ' + props.network + ' Switch to Rinkeby and refresh!'}</p> <div className="connection yellow border pa2">
<p></p> <p>{'MetaMask connected to ' + this.props.web3Store.networkMessage + ' Switch to Rinkeby and refresh!'}</p>
</div> <p></p>
) </div>
)
}
} }
} }
const mapStateToProps = state => ({
global: state.global,
web3Store: state.web3Store,
exchange: state.exchange
});
const mapDispatchToProps = (dispatch) => {
return bindActionCreators({
setWeb3ConnectionStatus,
setInteractionState,
setNetworkMessage,
}, dispatch)
}
export default NetworkStatus; export default connect (mapStateToProps, mapDispatchToProps)(NetworkStatus);
\ No newline at end of file
import React, { Component } from 'react';
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux';
import { setBlockTimestamp, setInteractionState } from '../actions/web3-actions';
import { setExchangeInputValue, setExchangeOutputValue } from '../actions/exchange-actions';
class Purchase extends Component {
purchaseTokens = async () => {
await this.props.setBlockTimestamp(this.props.global.web3);
if (this.props.web3Store.exchangeType === 'ETH to Token') {
this.ethToTokenPurchase();
} else if (this.props.web3Store.exchangeType === 'Token to ETH') {
this.tokenToEthPurchase();
} else if (this.props.web3Store.exchangeType === 'Token to Token') {
this.tokenToTokenPurchase();
}
}
ethToTokenPurchase = () => {
var exchange = this.props.symbolToExchangeContract(this.props.exchange.outputToken.value);
var minTokens = (this.props.exchange.outputValue/10**18).toString();
var minTokensInt = this.props.global.web3.utils.toWei(minTokens);
var ethSold = this.props.exchange.inputValue;
var weiSold = this.props.global.web3.utils.toWei(ethSold);
var timeout = this.props.web3Store.blockTimestamp + 300; //current block time + 5mins
// console.log(minTokensInt, weiSold, timeout);
exchange.methods.ethToTokenSwap(minTokensInt, timeout).send({from: this.props.web3Store.currentMaskAddress, value: weiSold})
.on('transactionHash', (result) => {
// console.log('Transaction Hash created'
// let transactions = this.state.transactions
// transactions.push(result);
// transactions is cookie stuff, we'll keep that in state
// this.setState({ transactions: transactions })
// any particular reason why there are initialized as 0, but get turned to empty strings after the transaction is over?
this.props.setExchangeInputValue('');
this.props.setExchangeOutputValue('');
this.props.setInteractionState('submitted');
// cookie.save('transactions', transactions, { path: '/' })
})
.on('receipt', (receipt) => {
console.log(receipt)
}) //Transaction Submitted to blockchain
.on('confirmation', (confirmationNumber, receipt) => {
console.log("Block Confirmations: " + confirmationNumber)
if(confirmationNumber === 1) {
this.getAccountInfo();
}
}) //Transaction Mined
.on('error', console.error);
}
tokenToEthPurchase = () => {
var exchange = this.props.symbolToExchangeContract(this.props.exchange.inputToken.value);
var minEth = (this.props.exchange.outputValue/10**18).toString();
var minEthInt = this.props.global.web3.utils.toWei(minEth);
var tokensSold = this.props.exchange.inputValue;
var tokensSoldInt = this.props.global.web3.utils.toWei(tokensSold);
var timeout = this.props.web3Store.blockTimestamp + 300; //current block time + 5mins
exchange.methods.tokenToEthSwap(tokensSoldInt, minEthInt, timeout).send({from: this.props.web3Store.currentMaskAddress})
.on('transactionHash', (result) => {
// console.log('Transaction Hash created')
// let transactions = this.state.transactions
// transactions.push(result)
// this.setState({ transactions: transactions });
this.props.setExchangeInputValue('');
this.props.setExchangeOutputValue('');
this.props.setInteractionState('submitted');
// cookie.save('transactions', transactions, { path: '/' })
})
.on('receipt', (receipt) => {console.log(receipt)}) //Transaction Submitted to blockchain
.on('confirmation', (confirmationNumber, receipt) => {console.log("Block Confirmations: " + confirmationNumber)}) //Transaction Mined
.on('error', console.error);
}
tokenToTokenPurchase = () => {
var exchange = this.props.symbolToExchangeContract(this.props.exchange.inputToken.value);
var tokenOutAddress = this.props.symbolToTokenAddress(this.props.exchange.outputToken.value);
var minTokens = (this.props.exchange.outputValue/10**18).toString();
var minTokensInt = this.props.global.web3.utils.toWei(minTokens);
var tokensSold = this.props.exchange.inputValue;
var tokensSoldInt = this.props.global.web3.utils.toWei(tokensSold);
var timeout = this.props.web3Store.blockTimestamp + 300; //current block time + 5mins
console.log('tokenOutAddress', tokenOutAddress);
console.log('minTokensInt', minTokensInt);
console.log('tokensSoldInt', tokensSoldInt);
console.log('timeout', timeout);
exchange.methods.tokenToTokenSwap(tokenOutAddress, tokensSoldInt, minTokensInt, timeout).send({from: this.props.web3Store.currentMaskAddress})
.on('transactionHash', (result) => {
// console.log('Transaction Hash created')
// let transactions = this.state.transactions
// transactions.push(result)
// this.setState({ transactions: transactions });
this.props.setExchangeInputValue('');
this.props.setExchangeOutputValue('');
this.props.setInteractionState('submitted');
// cookie.save('transactions', transactions, { path: '/' })
})
.on('receipt', (receipt) => {console.log(receipt)}) //Transaction Submitted to blockchain
.on('confirmation', (confirmationNumber, receipt) => {console.log("Block Confirmations: " + confirmationNumber)}) //Transaction Mined
.on('error', console.error);
}
render() {
if (this.props.web3Store.interaction === 'input') {
return (
<a className="swap border pa2" role="button" onClick={() => {this.purchaseTokens()}}>
<b>{"I want to swap " + this.props.exchange.inputValue + " " + this.props.exchange.inputToken.value + " for " + this.props.exchange.outputValue/10**18 + " " + this.props.exchange.outputToken.value}</b>
</a>
)
} else {
return (<a className="swap grey-bg hidden border pa2"></a>)
}
}
}
const mapStateToProps = state => ({
global: state.global,
web3Store: state.web3Store,
exchange: state.exchange
})
const mapDispatchToProps = (dispatch) => {
return bindActionCreators({
setBlockTimestamp,
setExchangeInputValue,
setExchangeOutputValue,
setInteractionState
}, dispatch);
}
export default connect(mapStateToProps, mapDispatchToProps)(Purchase);
import React from 'react';
function Swap ({ interaction, inputValue, inputTokenValue, outputValue, outputTokenValue, purchaseTokens }) {
if (interaction === 'input') {
return (
<a className="swap border pa2" role="button" onClick={() => {purchaseTokens()}}>
<b>{"I want to swap " + inputValue + " " + inputTokenValue + " for " + outputValue/10**18 + " " + outputTokenValue}</b>
</a>
)
} else {
return (<a className="swap grey-bg hidden border pa2"></a>)
}
}
export default Swap;
// import React from 'react';
// import NetworkStatus from '../components/NetworkStatus';
// function Title (){
// return (
// <section className="title">
// <div className="logo border pa2">
// <span role="img" aria-label="Unicorn">🦄</span>
// </div>
// <NetworkStatus
// network={this.props.web3Store.networkMessage}
// connected={this.props.web3Store.connected}
// metamask={this.props.metamask}
// interaction={this.props.web3Store.interaction}
// address={this.props.web3Store.currentMaskAddress}
// locked={this.props.web3Store.metamaskLocked}
// balance={this.props.exchange.inputBalance}
// />
// </section>
// )
// }
// export default Title;
\ No newline at end of file
import React from 'react'; import React from 'react';
import {Helmet} from "react-helmet"; import { Helmet } from "react-helmet";
import unicorn from '../images/🦄.png' import unicorn from '../images/🦄.png'
function Head(props) { function UniHead(props) {
return ( return (
<Helmet> <Helmet>
<meta charSet="utf-8" /> <meta charSet="utf-8" />
...@@ -13,4 +13,4 @@ function Head(props) { ...@@ -13,4 +13,4 @@ function Head(props) {
); );
} }
export default Head; export default UniHead;
...@@ -2,9 +2,8 @@ ...@@ -2,9 +2,8 @@
// maybe there's an action to see if you've been connected to web3 // maybe there's an action to see if you've been connected to web3
// web3 actions, all set from action creator to reducer to app // web3 actions, all set from action creator to reducer to app
export const SET_WEB3_CONNECTION_STATUS = 'WEB3_CONNECTION_STATUS';
export const CHECK_WEB3_CONNECTION = 'CHECK_WEB3_CONNECTION'; export const CHECK_WEB3_CONNECTION = 'CHECK_WEB3_CONNECTION';
export const WEB3_CONNECTION_SUCCESSFUL = 'WEB3_CONNECTION_SUCCESSFUL';
export const WEB3_CONNECTION_UNSUCCESSFUL = 'WEB3_CONNECTION_UNSUCCESSFUL';
export const SET_CURRENT_MASK_ADDRESS = 'SET_CURRENT_MASK_ADDRESS'; export const SET_CURRENT_MASK_ADDRESS = 'SET_CURRENT_MASK_ADDRESS';
export const METAMASK_LOCKED = 'METAMASK_LOCKED'; export const METAMASK_LOCKED = 'METAMASK_LOCKED';
...@@ -15,6 +14,9 @@ export const SET_NETWORK_MESSAGE = 'SET_NETWORK_MESSAGE'; ...@@ -15,6 +14,9 @@ export const SET_NETWORK_MESSAGE = 'SET_NETWORK_MESSAGE';
export const SET_BLOCK_TIMESTAMP = 'SET_BLOCK_TIMESTAMP'; export const SET_BLOCK_TIMESTAMP = 'SET_BLOCK_TIMESTAMP';
export const SET_EXCHANGE_TYPE = 'SET_EXCHANGE_TYPE'; export const SET_EXCHANGE_TYPE = 'SET_EXCHANGE_TYPE';
// action to toggle the 'about' div
export const TOGGLE_ABOUT = 'TOGGLE_ABOUT';
// factory contract action, also set // factory contract action, also set
export const FACTORY_CONTRACT_READY = 'FACTORY_CONTRACT_READY'; export const FACTORY_CONTRACT_READY = 'FACTORY_CONTRACT_READY';
......
import { INITIALIZE_GLOBAL_WEB3 } from '../constants';
export default (state = {}, action) => {
const { globalWeb3 } = action;
switch(action.type) {
case INITIALIZE_GLOBAL_WEB3:
return Object.assign({}, state, { web3: globalWeb3 });
default: return state
}
}
\ No newline at end of file
import { combineReducers } from 'redux'; import { combineReducers } from 'redux';
import global from './global-reducer';
import web3Store from './web3-reducer'; import web3Store from './web3-reducer';
import exchangeContracts from './exchangeContract-reducer'; import exchangeContracts from './exchangeContract-reducer';
import tokenContracts from './tokenContract-reducer'; import tokenContracts from './tokenContract-reducer';
import exchange from './exchange-reducer'; import exchange from './exchange-reducer';
export default combineReducers({ export default combineReducers({
global,
web3Store, web3Store,
exchangeContracts, exchangeContracts,
tokenContracts, tokenContracts,
......
// these will take in an action, have a default state set in the arguments and return a new state // these will take in an action, have a default state set in the arguments and return a new state
import { import {
WEB3_CONNECTION_SUCCESSFUL, SET_WEB3_CONNECTION_STATUS,
WEB3_CONNECTION_UNSUCCESSFUL,
SET_CURRENT_MASK_ADDRESS, SET_CURRENT_MASK_ADDRESS,
METAMASK_LOCKED, METAMASK_LOCKED,
METAMASK_UNLOCKED, METAMASK_UNLOCKED,
...@@ -10,15 +9,14 @@ import { ...@@ -10,15 +9,14 @@ import {
SET_NETWORK_MESSAGE, SET_NETWORK_MESSAGE,
SET_BLOCK_TIMESTAMP, SET_BLOCK_TIMESTAMP,
SET_EXCHANGE_TYPE, SET_EXCHANGE_TYPE,
INITIALIZE_GLOBAL_WEB3 INITIALIZE_GLOBAL_WEB3,
TOGGLE_ABOUT
} from '../constants'; } from '../constants';
export default (state = {}, action) => { export default (state = {}, action) => {
const { connected, currentMaskAddress, metamaskLocked, interaction, factoryContract, networkMessage, timestamp, exchangeType, globalWeb3 } = action const { connected, currentMaskAddress, metamaskLocked, interaction, factoryContract, networkMessage, timestamp, exchangeType, globalWeb3, aboutToggle } = action
switch (action.type) { switch (action.type) {
case WEB3_CONNECTION_SUCCESSFUL: case SET_WEB3_CONNECTION_STATUS:
return Object.assign({}, state, { connected: connected });
case WEB3_CONNECTION_UNSUCCESSFUL:
return Object.assign({}, state, { connected: connected }); return Object.assign({}, state, { connected: connected });
case SET_CURRENT_MASK_ADDRESS: case SET_CURRENT_MASK_ADDRESS:
return Object.assign({}, state, { currentMaskAddress: currentMaskAddress }); return Object.assign({}, state, { currentMaskAddress: currentMaskAddress });
...@@ -38,6 +36,8 @@ export default (state = {}, action) => { ...@@ -38,6 +36,8 @@ export default (state = {}, action) => {
return Object.assign({}, state, { exchangeType: exchangeType }); return Object.assign({}, state, { exchangeType: exchangeType });
case INITIALIZE_GLOBAL_WEB3: case INITIALIZE_GLOBAL_WEB3:
return Object.assign({}, state, { globalWeb3: globalWeb3 }); return Object.assign({}, state, { globalWeb3: globalWeb3 });
case TOGGLE_ABOUT:
return Object.assign({}, state, { aboutToggle: aboutToggle })
default: return state; default: return state;
} }
} }
// what states do you need upon initialization?
// connected: are you connnected? default state = false
// props.metamask --> maybe we should keep this in global state too?
// both of these are set to false in the default state
// fire dispatch functions to check for installation and connection in the default store
// you are probably going to be storing stuff like invariants and all that jazz here
export default { export default {
// lets check if metamask is installed global: {},
// also, lets assume that we're disconnected initially
// we're going to need to include a seperate nest for exchange actions
web3Store: { web3Store: {
connected: false, connected: false,
aboutToggle: false,
globalWeb3: {}, globalWeb3: {},
currentMaskAddress: '', currentMaskAddress: '',
metamaskLocked: true, metamaskLocked: true,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment