Add Arbitrary Token (#90)

This commit is contained in:
Chi Kei Chan 2018-10-27 12:34:03 -07:00 committed by GitHub
parent 39248a0f6b
commit 5ee3c90ba3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 96 additions and 38 deletions

1
src/abi/factory.json Normal file

@ -0,0 +1 @@
[{"name": "NewExchange", "inputs": [{"type": "address", "name": "token", "indexed": true}, {"type": "address", "name": "exchange", "indexed": true}], "anonymous": false, "type": "event"}, {"name": "initializeFactory", "outputs": [], "inputs": [{"type": "address", "name": "template"}], "constant": false, "payable": false, "type": "function", "gas": 35725}, {"name": "createExchange", "outputs": [{"type": "address", "name": "out"}], "inputs": [{"type": "address", "name": "token"}], "constant": false, "payable": false, "type": "function", "gas": 187911}, {"name": "getExchange", "outputs": [{"type": "address", "name": "out"}], "inputs": [{"type": "address", "name": "token"}], "constant": true, "payable": false, "type": "function", "gas": 715}, {"name": "getToken", "outputs": [{"type": "address", "name": "out"}], "inputs": [{"type": "address", "name": "exchange"}], "constant": true, "payable": false, "type": "function", "gas": 745}, {"name": "getTokenWithId", "outputs": [{"type": "address", "name": "out"}], "inputs": [{"type": "uint256", "name": "token_id"}], "constant": true, "payable": false, "type": "function", "gas": 736}, {"name": "exchangeTemplate", "outputs": [{"type": "address", "name": "out"}], "inputs": [], "constant": true, "payable": false, "type": "function", "gas": 633}, {"name": "tokenCount", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [], "constant": true, "payable": false, "type": "function", "gas": 663}]

@ -201,6 +201,12 @@
&:active {
background-color: darken($concrete-gray, 1);
}
&--no-exchange {
color: $dove-gray;
justify-content: center;
background-color: darken($concrete-gray, 1);;
}
}
&__token-logo {

@ -8,12 +8,13 @@ import Modal from '../Modal';
import TokenLogo from '../TokenLogo';
import SearchIcon from '../../assets/images/magnifying-glass.svg';
import { selectors } from "../../ducks/web3connect";
import { addExchange } from "../../ducks/addresses";
import { BigNumber as BN } from 'bignumber.js';
import './currency-panel.scss';
import ERC20_ABI from '../../abi/erc20';
import EXCHANGE_ABI from "../../abi/exchange";
import FACTORY_ABI from '../../abi/factory';
const FUSE_OPTIONS = {
includeMatches: false,
@ -45,12 +46,14 @@ class CurrencyInputPanel extends Component {
exchangeAddresses: PropTypes.shape({
fromToken: PropTypes.object.isRequired,
}).isRequired,
factoryAddress: PropTypes.string,
selectedTokens: PropTypes.array.isRequired,
errorMessage: PropTypes.string,
account: PropTypes.string,
selectedTokenAddress: PropTypes.string,
disableTokenSelect: PropTypes.bool,
selectors: PropTypes.func.isRequired,
addExchange: PropTypes.func.isRequired,
filteredTokens: PropTypes.arrayOf(PropTypes.string),
disableUnlock: PropTypes.bool,
};
@ -96,43 +99,36 @@ class CurrencyInputPanel extends Component {
});
this.props.onCurrencySelected(address);
// if (address && address !== 'ETH') {
// const { drizzle } = this.context;
// const { fromToken } = this.props.exchangeAddresses;
// const { web3 } = drizzle;
//
// // Add Token Contract
// if (!this.props.contracts[address]) {
// const tokenConfig = {
// contractName: address,
// web3Contract: new web3.eth.Contract(ERC20_ABI, address),
// };
// const tokenEvents = ['Approval', 'Transfer'];
// this.context.drizzle.addContract(tokenConfig, tokenEvents, { from: this.props.account });
// }
//
// // Add Exchange Contract
// const exchangeAddress = fromToken[address];
// if (!exchangeAddress) {
// return;
// }
//
// if (!this.props.contracts[exchangeAddress]) {
// const exchangeConfig = {
// contractName: exchangeAddress,
// web3Contract: new web3.eth.Contract(EXCHANGE_ABI, exchangeAddress),
// };
// const exchangeEvents = ['Approval', 'Transfer', 'TokenPurchase', 'EthPurchase', 'AddLiquidity', 'RemoveLiquidity'];
// this.context.drizzle.addContract(exchangeConfig, exchangeEvents , { from: this.props.account });
// }
// }
};
renderTokenList() {
const tokens = this.createTokenList();
const { searchQuery } = this.state;
const { selectedTokens, disableTokenSelect } = this.props;
const {
selectedTokens,
disableTokenSelect,
web3,
selectors,
account,
factoryAddress,
exchangeAddresses: { fromToken },
addExchange,
} = this.props;
if (web3.utils.isAddress(searchQuery)) {
const tokenAddress = searchQuery;
const { label } = selectors().getBalance(account, tokenAddress);
const factory = new web3.eth.Contract(FACTORY_ABI, factoryAddress);
const exchangeAddress = fromToken[tokenAddress];
if (!exchangeAddress) {
factory.methods.getExchange(tokenAddress).call((err, data) => {
if (!err && data !== '0x0000000000000000000000000000000000000000') {
addExchange({ label, tokenAddress, exchangeAddress: data });
}
});
}
}
if (disableTokenSelect) {
return;
@ -145,7 +141,14 @@ class CurrencyInputPanel extends Component {
} else {
const fuse = new Fuse(tokens, FUSE_OPTIONS);
results = fuse.search(this.state.searchQuery);
}
if (!results.length) {
return (
<div className="token-modal__token-row token-modal__token-row--no-exchange">
<div>No Exchange Found</div>
</div>
)
}
return results.map(({ label, address }) => {
@ -155,7 +158,9 @@ class CurrencyInputPanel extends Component {
<div
key={label}
className={
classnames('token-modal__token-row', { 'token-modal__token-row--selected': isSelected })
classnames('token-modal__token-row', {
'token-modal__token-row--selected': isSelected,
})
}
onClick={() => this.onTokenSelect(address)}
>
@ -172,7 +177,7 @@ class CurrencyInputPanel extends Component {
}
return (
<Modal onClose={() => this.setState({ isShowingModal: false })}>
<Modal onClose={() => this.setState({ isShowingModal: false, searchQuery: '' })}>
<CSSTransitionGroup
transitionName="token-modal"
transitionAppear={true}
@ -332,6 +337,7 @@ class CurrencyInputPanel extends Component {
export default drizzleConnect(
CurrencyInputPanel,
state => ({
factoryAddress: state.addresses.factoryAddress,
exchangeAddresses: state.addresses.exchangeAddresses,
tokenAddresses: state.addresses.tokenAddresses,
contracts: state.contracts,
@ -341,5 +347,6 @@ export default drizzleConnect(
}),
dispatch => ({
selectors: () => dispatch(selectors()),
addExchange: opts => dispatch(addExchange(opts)),
}),
);

@ -1,4 +1,5 @@
const RINKEBY = {
factoryAddress: '0xf5D915570BC477f9B8D6C0E980aA81757A3AaC36',
exchangeAddresses: {
addresses: [
['BAT','0x9B913956036a3462330B0642B20D3879ce68b450'],
@ -27,12 +28,13 @@ const RINKEBY = {
};
const MAIN = {
factoryAddress: '0xbe87b46515ab488713daA155D92abbd0E5964F6A',
exchangeAddresses: {
addresses: [
['BAT', '0x31684EB08E0d86AE970F4C2f9110afBce9C4C984'],
['DAI', '0xB23601D1E65002fA3173A0982b8E4AD5B46C7863'],
['MKR', '0x405f6187BeE030B1DF486968C673907F0fd58BE1'],
['ANT', '0x264B884Df87fBB97997994181d054e8657eB5c78'],
// ['ANT', '0x264B884Df87fBB97997994181d054e8657eB5c78'],
['REP', '0x997C2c6b08E33313C5512Fd3C6eF235BF0139Ca3'],
['ZRX', '0xE9674e73887bDCCd8fd46861a4f5b1E6485789BE'],
['SNT', '0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2'],
@ -41,7 +43,7 @@ const MAIN = {
'0x0D8775F648430679A709E98d2b0Cb6250d2887EF': '0x31684EB08E0d86AE970F4C2f9110afBce9C4C984',
'0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359': '0xB23601D1E65002fA3173A0982b8E4AD5B46C7863',
'0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2': '0x405f6187BeE030B1DF486968C673907F0fd58BE1',
'0x960b236A07cf122663c4303350609A66A7B288C0': '0x264B884Df87fBB97997994181d054e8657eB5c78',
// '0x960b236A07cf122663c4303350609A66A7B288C0': '0x264B884Df87fBB97997994181d054e8657eB5c78',
'0x1985365e9f78359a9B6AD760e32412f4a445E862': '0x997C2c6b08E33313C5512Fd3C6eF235BF0139Ca3',
'0xE41d2489571d322189246DaFA5ebDe1F4699F498': '0xE9674e73887bDCCd8fd46861a4f5b1E6485789BE',
'0x744d70FDBE2Ba4CF95131626614a1763DF805B9E': '0x63d4b39137dF65ebEad4E15456c291284fCB537C',
@ -52,7 +54,7 @@ const MAIN = {
['BAT', '0x0D8775F648430679A709E98d2b0Cb6250d2887EF'],
['DAI', '0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359'],
['MKR', '0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2'],
['ANT', '0x960b236A07cf122663c4303350609A66A7B288C0'],
// ['ANT', '0x960b236A07cf122663c4303350609A66A7B288C0'],
['REP', '0x1985365e9f78359a9B6AD760e32412f4a445E862'],
['ZRX', '0xE41d2489571d322189246DaFA5ebDe1F4699F498'],
['SNT', '0x744d70FDBE2Ba4CF95131626614a1763DF805B9E'],
@ -61,9 +63,19 @@ const MAIN = {
};
const SET_ADDRESSES = 'app/addresses/setAddresses';
const ADD_EXCHANGE = 'app/addresses/addExchange';
const initialState = RINKEBY;
export const addExchange = ({label, exchangeAddress, tokenAddress}) => ({
type: ADD_EXCHANGE,
payload: {
label,
exchangeAddress,
tokenAddress,
},
});
export const setAddresses = networkId => {
switch(networkId) {
// Main Net
@ -87,7 +99,39 @@ export default (state = initialState, { type, payload }) => {
switch (type) {
case SET_ADDRESSES:
return payload;
case ADD_EXCHANGE:
return handleAddExchange(state, { payload });
default:
return state;
}
}
function handleAddExchange(state, { payload }) {
const { label, tokenAddress, exchangeAddress } = payload;
if (!label || !tokenAddress || !exchangeAddress) {
return state;
}
return {
...state,
exchangeAddresses: {
...state.exchangeAddresses,
addresses: [
...state.exchangeAddresses.addresses,
[label,exchangeAddress]
],
fromToken: {
...state.exchangeAddresses.fromToken,
[tokenAddress]: exchangeAddress,
},
},
tokenAddresses: {
...state.tokenAddresses,
addresses: [
...state.tokenAddresses.addresses,
[label, tokenAddress]
],
},
};
}