Skip to content

Commit

Permalink
Merge pull request #32 from WalletConnect/refactor
Browse files Browse the repository at this point in the history
Refactor
  • Loading branch information
pedrouid committed Feb 9, 2019
2 parents f8e5779 + 08542a8 commit 15b25b3
Show file tree
Hide file tree
Showing 17 changed files with 105 additions and 2,298 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
"version": "1.0.0-beta",
"private": true,
"dependencies": {
"@walletconnect/browser": "^1.0.0-beta.3",
"@walletconnect/qrcode-modal": "^1.0.0-beta.3",
"axios": "^0.18.0",
"bignumber.js": "^8.0.2",
"eth-crypto": "^1.3.2",
Expand Down
9 changes: 4 additions & 5 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import * as React from "react";
import styled from "styled-components";
import WalletConnect from "./lib";
import WalletConnectQRCodeModal from "./qrcode-modal";
import WalletConnect from "@walletconnect/browser";
import WalletConnectQRCodeModal from "@walletconnect/qrcode-modal";
import { IInternalEvent } from "@walletconnect/types";
import AssetRow from "./components/AssetRow";
import Button from "./components/Button";
import Column from "./components/Column";
Expand All @@ -24,7 +25,6 @@ import {
convertStringToHex
} from "./helpers/bignumber";
import { IAssetData } from "./helpers/types";
import { IInternalEvent } from "./lib/types";

const SLayout = styled.div`
position: relative;
Expand Down Expand Up @@ -288,8 +288,7 @@ class App extends React.Component<any, any> {
const to = address;

// nonce
const nonceRes = await apiGetAccountNonce(address, chainId);
const nonce = nonceRes.data.result;
const nonce = await apiGetAccountNonce(address, chainId);

// gasPrice
const gasPrices = await apiGetGasPrices();
Expand Down
276 changes: 24 additions & 252 deletions src/helpers/api.ts
Original file line number Diff line number Diff line change
@@ -1,278 +1,50 @@
import axios, { AxiosInstance } from "axios";
import {
IAssetData,
IGasPrices,
IBlockScoutTx,
IBlockScoutTokenTx,
IParsedTx,
ITxOperation
} from "./types";
import { convertStringToNumber, divide, multiply } from "./bignumber";
import { getChainData } from "./utilities";
import functionNames from "./functionNames";
import { IAssetData, IGasPrices, IParsedTx } from "./types";

const api: AxiosInstance = axios.create({
baseURL: "https://blockscout.com/",
baseURL: "https://ethereum-api.xyz",
timeout: 30000, // 30 secs
headers: {
Accept: "application/json",
"Content-Type": "application/json"
}
});

export async function apiGetAccountBalance(address: string, chainId: number) {
const chainData = getChainData(chainId);
const chain = chainData.chain.toLowerCase();
const network = chainData.network.toLowerCase();
const module = "account";
const action = "balance";
const url = `/${chain}/${network}/api?module=${module}&action=${action}&address=${address}`;
const result = await api.get(url);
return result;
}

export async function apiGetAccountTokenList(address: string, chainId: number) {
const chainData = getChainData(chainId);
const chain = chainData.chain.toLowerCase();
const network = chainData.network.toLowerCase();
const module = "account";
const action = "tokenlist";
const url = `/${chain}/${network}/api?module=${module}&action=${action}&address=${address}`;
const result = await api.get(url);
return result;
}

export async function apiGetAccountTokenBalance(
export async function apiGetAccountAssets(
address: string,
chainId: number,
contractAddress: string
) {
const chainData = getChainData(chainId);
const chain = chainData.chain.toLowerCase();
const network = chainData.network.toLowerCase();
const module = "account";
const action = "tokenbalance";
const url = `/${chain}/${network}/api?module=${module}&action=${action}&contractaddress=${contractAddress}&address=${address}`;
const result = await api.get(url);
return result;
}

export async function apiGetAccountAssets(address: string, chainId: number) {
const chainData = getChainData(chainId);

const nativeCurrency: IAssetData =
chainData.chain.toLowerCase() !== "dai"
? {
symbol: "ETH",
name: "Ethereum",
decimals: "18",
contractAddress: "",
balance: ""
}
: {
symbol: "DAI",
name: "Dai Stablecoin v1.0",
decimals: "18",
contractAddress: "0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359",
balance: ""
};
const balanceRes = await apiGetAccountBalance(address, chainId);
nativeCurrency.balance = balanceRes.data.result;

const tokenListRes = await apiGetAccountTokenList(address, chainId);
const tokenList: IAssetData[] = tokenListRes.data.result;

let tokens: IAssetData[] = await Promise.all(
tokenList.map(
async (token: IAssetData): Promise<IAssetData> => {
const tokenBalanceRes = await apiGetAccountTokenBalance(
address,
chainId,
token.contractAddress
);

const tokenBalance = tokenBalanceRes.data.result;

if (
tokenBalance &&
!Number.isNaN(tokenBalance) &&
!!Number(tokenBalance)
) {
token.balance = tokenBalance;
}

return token;
}
)
);
tokens = tokens.filter(
token =>
!!Number(token.balance) &&
!!token.balance &&
!!token.decimals &&
!!token.name
chainId: number
): Promise<IAssetData[]> {
const response = await api.get(
`/account-assets?address=${address}&chainId=${chainId}`
);

const assets: IAssetData[] = [nativeCurrency, ...tokens];

return assets;
}

export async function apiGetAccountTxList(address: string, chainId: number) {
const chainData = getChainData(chainId);
const chain = chainData.chain.toLowerCase();
const network = chainData.network.toLowerCase();
const module = "account";
const action = "txlist";
const url = `/${chain}/${network}/api?module=${module}&action=${action}&address=${address}`;
const result = await api.get(url);
return result;
}

export async function apiGetAccountTokenTx(address: string, chainId: number) {
const chainData = getChainData(chainId);
const chain = chainData.chain.toLowerCase();
const network = chainData.network.toLowerCase();
const module = "account";
const action = "tokentx";
const url = `/${chain}/${network}/api?module=${module}&action=${action}&address=${address}`;
const result = await api.get(url);
const { result } = response.data;
return result;
}

export async function apiGetAccountTransactions(
address: string,
chainId: number
) {
const txListRes = await apiGetAccountTxList(address, chainId);
const txList: IBlockScoutTx[] = txListRes.data.result;

const transactions: IParsedTx[] = txList.map(
(tx: IBlockScoutTx): IParsedTx => {
const asset: IAssetData = {
symbol: "ETH",
name: "Ethereum",
decimals: "18",
contractAddress: ""
};

const parsedTx: IParsedTx = {
timeStamp: multiply(tx.timeStamp, 1000),
hash: tx.hash,
from: tx.from,
to: tx.to,
nonce: tx.nonce,
gasPrice: tx.gasPrice,
gasUsed: tx.gasUsed,
fee: multiply(tx.gasPrice, tx.gasUsed),
value: tx.value,
input: tx.input,
error: tx.isError === "1",
asset,
operations: []
};
return parsedTx;
}
);

const tokenTxnsRes = await apiGetAccountTokenTx(address, chainId);
const tokenTxns: IBlockScoutTokenTx[] = tokenTxnsRes.data.result;

tokenTxns.forEach((tokenTx: IBlockScoutTokenTx) => {
const asset: IAssetData = {
symbol: tokenTx.tokenSymbol,
name: tokenTx.tokenName,
decimals: tokenTx.tokenDecimal,
contractAddress: tokenTx.contractAddress
};

const functionHash = tokenTx.input.substring(0, 10);

const operation: ITxOperation = {
asset,
value: tokenTx.value,
from: tokenTx.from,
to: tokenTx.to,
functionName: functionNames[functionHash] || functionHash
};

let matchingTx = false;

for (const tx of transactions) {
if (tokenTx.hash.toLowerCase() === tx.hash.toLowerCase()) {
tx.operations.push(operation);
matchingTx = true;
break;
}
}
if (!matchingTx) {
const asset: IAssetData = {
symbol: "ETH",
name: "Ethereum",
decimals: "18",
contractAddress: ""
};

const parsedTx: IParsedTx = {
timeStamp: multiply(tokenTx.timeStamp, 100),
hash: tokenTx.hash,
from: tokenTx.from,
to: tokenTx.to,
nonce: tokenTx.nonce,
gasPrice: tokenTx.gasPrice,
gasUsed: tokenTx.gasUsed,
fee: multiply(tokenTx.gasPrice, tokenTx.gasUsed),
value: tokenTx.value,
input: tokenTx.input,
error: false,
asset,
operations: []
};
transactions.push(parsedTx);
}
});

transactions.sort(
(a, b) => parseInt(b.timeStamp, 10) - parseInt(a.timeStamp, 10)
): Promise<IParsedTx[]> {
const response = await api.get(
`/account-transactions?address=${address}&chainId=${chainId}`
);

return transactions;
const { result } = response.data;
return result;
}

export const apiGetGasPrices = async (): Promise<IGasPrices> => {
const { data } = await axios.get(
`https://ethgasstation.info/json/ethgasAPI.json`
export const apiGetAccountNonce = async (
address: string,
chainId: number
): Promise<string> => {
const response = await api.get(
`/account-nonce?address=${address}&chainId=${chainId}`
);
const result: IGasPrices = {
slow: {
time: convertStringToNumber(multiply(data.safeLowWait, 60)),
price: convertStringToNumber(divide(data.safeLow, 10))
},
average: {
time: convertStringToNumber(multiply(data.avgWait, 60)),
price: convertStringToNumber(divide(data.average, 10))
},
fast: {
time: convertStringToNumber(multiply(data.fastestWait, 60)),
price: convertStringToNumber(divide(data.fastest, 10))
}
};
const { result } = response.data;
return result;
};

export const apiGetAccountNonce = (
address: string,
chainId: number
): Promise<any> => {
const chainData = getChainData(chainId);
if (chainData.chain !== "ETH") {
throw new Error("Chain not supported");
}
const network = chainData.network;
return axios.post(`https://${network}.infura.io/`, {
jsonrpc: "2.0",
id: Date.now(),
method: "eth_getTransactionCount",
params: [address, "pending"]
});
export const apiGetGasPrices = async (): Promise<IGasPrices> => {
const response = await api.get(`/gas-prices`);
const { result } = response.data;
return result;
};
25 changes: 25 additions & 0 deletions src/helpers/bignumber.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,30 @@
import BigNumber from "bignumber.js";

export function isNaN(value: string | number): boolean {
return new BigNumber(`${value}`).isNaN();
}

export function isNumber(value: string | number): boolean {
const isNaNResult = isNaN(value);
return !isNaNResult;
}

export function isInteger(value: string | number): boolean {
return new BigNumber(`${value}`).isInteger();
}

export function isPositive(value: string | number): boolean {
return new BigNumber(`${value}`).isPositive();
}

export function isNegative(value: string | number): boolean {
return new BigNumber(`${value}`).isNegative();
}

export function isZero(value: string | number): boolean {
return new BigNumber(`${value}`).isZero();
}

export function countDecimalPlaces(value: string | number): number {
return new BigNumber(`${value}`).dp();
}
Expand Down
Loading

0 comments on commit 15b25b3

Please sign in to comment.