Skip to content

Commit

Permalink
Add ETH and ERC20 balance/transaction/address support (with BAT/DAI/ETH)
Browse files Browse the repository at this point in the history
  • Loading branch information
michaeltout committed Aug 28, 2020
1 parent 29d184a commit 2955261
Show file tree
Hide file tree
Showing 86 changed files with 1,142 additions and 399 deletions.
2 changes: 0 additions & 2 deletions App.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import React from 'react';
import VerusMobile from './src/VerusMobile'
import store from './src/store'
import { Provider } from 'react-redux'
import './global'


export default class App extends React.Component {
render() {
Expand Down
3 changes: 2 additions & 1 deletion debug/setupJest.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ global.fetch = require('../__mocks__/react-native-fetch/fetch')
// App functionality
global.ENABLE_FIAT_GATEWAY = true;
global.ENABLE_VERUS_IDENTITIES = true;
global.ENABLE_DLIGHT = true;
global.DISABLED_CHANNELS = ['dlight'];
global.ENABLE_DLIGHT = !global.DISABLED_CHANNELS.includes('dlight')

25 changes: 25 additions & 0 deletions env/main.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"APP_VERSION": "0.1.9-beta",
"VERUS_QR_VERSION": "0.1.1",
"CHAIN_QR_VERSION": "0.1.0",
"ELECTRUM_PROTOCOL_CHANGE": 1.4,

"REQUEST_TIMEOUT_MS": 10000,

"BLOCK_HEADER_STORE_CAP": 20,
"MIN_HEADER_CACHE_CONFS": 100,

"ENABLE_FIAT_GATEWAY": false,
"ENABLE_VERUS_IDENTITIES": false,
"DISABLED_CHANNELS": ["dlight"],
"ENABLE_DLIGHT": false,
"ENABLE_ERC20": true,
"ENABLE_ETH": true,
"ENABLE_ELECTRUM": true,
"ENABLE_GENERAL": true,

"ETH_NETWORK": "ropsten",

"ETHERSCAN_API_KEY": "PUT_KEY_HERE",
"INFURA_PROJECT_ID": "PUT_ID_HERE"
}
34 changes: 19 additions & 15 deletions global.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
// Versions
global.APP_VERSION = "0.1.9-beta";
global.VERUS_QR_VERSION = "0.1.1";
global.CHAIN_QR_VERSION = "0.1.0"
global.ELECTRUM_PROTOCOL_CHANGE = 1.4;
//TODO: Test with Jest and delete

// HTTPS
global.REQUEST_TIMEOUT_MS = 10000;
// // Versions
// global.APP_VERSION = "0.1.9-beta";
// global.VERUS_QR_VERSION = "0.1.1";
// global.CHAIN_QR_VERSION = "0.1.0"
// global.ELECTRUM_PROTOCOL_CHANGE = 1.4;

// Cache globals (more in cache files because globals cant be used for
// constants that are needed immediately on app load)
global.BLOCK_HEADER_STORE_CAP = 20;
global.MIN_HEADER_CACHE_CONFS = 100;
// // HTTPS
// global.REQUEST_TIMEOUT_MS = 10000;

// App functionality
global.ENABLE_FIAT_GATEWAY = false;
global.ENABLE_VERUS_IDENTITIES = false;
global.ENABLE_DLIGHT = false;
// // Cache globals (more in cache files because globals cant be used for
// // constants that are needed immediately on app load)
// global.BLOCK_HEADER_STORE_CAP = 20;
// global.MIN_HEADER_CACHE_CONFS = 100;

// // App functionality
// global.ENABLE_FIAT_GATEWAY = false;
// global.ENABLE_VERUS_IDENTITIES = false;
// global.DISABLED_CHANNELS = ['dlight'];
// global.ENABLE_DLIGHT = !global.DISABLED_CHANNELS.includes('dlight')
// global.ENABLE_ERC20 = !global.DISABLED_CHANNELS.includes('erc20')

41 changes: 41 additions & 0 deletions shim.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,44 @@ if (typeof localStorage !== 'undefined') {
// If using the crypto shim, uncomment the following line to ensure
// crypto is loaded first, so it can populate global.crypto
require('crypto')

// Shim required to fix .readAsArrayBuffer (not implemented in react-native yet)

// from: https://stackoverflow.com/questions/42829838/react-native-atob-btoa-not-working-without-remote-js-debugging
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
const atob = (input = '') => {
let str = input.replace(/=+$/, '');
let output = '';

if (str.length % 4 == 1) {
throw new Error("'atob' failed: The string to be decoded is not correctly encoded.");
}
for (let bc = 0, bs = 0, buffer, i = 0;
buffer = str.charAt(i++);

~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer,
bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0
) {
buffer = chars.indexOf(buffer);
}

return output;
}

// from: https://github.com/facebook/react-native/issues/21209 & https://github.com/ethers-io/ethers.js/issues/993
FileReader.prototype.readAsArrayBuffer = function (blob) {
if (this.readyState === this.LOADING) throw new Error("InvalidStateError");
this._setReadyState(this.LOADING);
this._result = null;
this._error = null;
const fr = new FileReader();
fr.onloadend = () => {
const content = atob(fr.result.substr("data:application/octet-stream".length));
const buffer = new ArrayBuffer(content.length);
const view = new Uint8Array(buffer);
view.set(Array.from(content).map(c => c.charCodeAt(0)));
this._result = buffer;
this._setReadyState(this.DONE);
};
fr.readAsDataURL(blob);
}
3 changes: 2 additions & 1 deletion src/VerusMobile.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
checkAndSetVersion
} from './utils/asyncStore/asyncStore'
import { connect } from 'react-redux';
import { ENABLE_VERUS_IDENTITIES } from '../env/main.json'


class VerusMobile extends React.Component {
Expand Down Expand Up @@ -63,7 +64,7 @@ class VerusMobile extends React.Component {
Alert.alert("Error", err.message)
})

if (global.ENABLE_VERUS_IDENTITIES) {
if (ENABLE_VERUS_IDENTITIES) {
this.props.dispatch(requestSeedData());
}
}
Expand Down
47 changes: 31 additions & 16 deletions src/actions/actions/UserData.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ import {
} from '../../utils/keys'
import {
decryptkey,
decryptGeneral,
} from '../../utils/seedCrypt'
import { sha256, hashAccountId } from '../../utils/crypto/hash';

import WyreService from '../../services/wyreService';
import { CHANNELS, ELECTRUM } from '../../utils/constants/intervalConstants';
import { arrayToObject } from '../../utils/objectManip';
import { ENABLE_FIAT_GATEWAY } from '../../../env/main.json';


//TODO: Fingerprint authentication
Expand Down Expand Up @@ -77,30 +79,41 @@ export const fetchUsers = () => {

export const authenticateAccount = (account, password) => {
let _keys = {};
const { electrum, dlight } = account.encryptedKeys

let seeds = {
electrum: electrum != null ? decryptkey(password, electrum) : null,
dlight: dlight != null ? decryptkey(password, dlight) : null,
}
let seeds = arrayToObject(
CHANNELS,
(acc, key) =>
account.encryptedKeys[key]
? decryptkey(password, account.encryptedKeys[key])
: null,
true
);

return new Promise((resolve, reject) => {
getActiveCoinList()
.then(activeCoins => {
for (let i = 0; i < activeCoins.length; i++) {
if (activeCoins[i].users.includes(account.id)) {
_keys[activeCoins[i].id] = {
electrum: electrum != null ? makeKeyPair(seeds.electrum, activeCoins[i].id) : null,
dlight: dlight != null ? makeKeyPair(seeds.dlight, activeCoins[i].id) : null,
}
_keys[activeCoins[i].id] = arrayToObject(
CHANNELS,
(acc, key) =>
activeCoins[i].compatible_channels.includes(key)
? makeKeyPair(
seeds[key] ? seeds[key] : seeds.electrum,
activeCoins[i].id,
key
)
: null,
true
);
}
}

let paymentMethods = {
...account.paymentMethods
}

if (global.ENABLE_FIAT_GATEWAY) {
if (ENABLE_FIAT_GATEWAY) {
const hashedSeed = sha256(seeds.electrum).toString('hex');

WyreService.build().submitAuthToken(hashedSeed).then((response) => {
Expand Down Expand Up @@ -162,12 +175,14 @@ export const validateLogin = (account, password) => {
});
}

export const addKeypairs = (accountSeeds, coinID, keys) => {
export const addKeypairs = (accountSeeds, coinObj, keys) => {
let keypairs = {}
Object.keys(accountSeeds).map(seedType => {
const seed = accountSeeds[seedType]
if (seed != null) {
keypairs[seedType] = makeKeyPair(seed, coinID)
const coinID = coinObj.id

CHANNELS.map(seedType => {
const seed = accountSeeds[seedType] ? accountSeeds[seedType] : accountSeeds[ELECTRUM]
if (coinObj.compatible_channels.includes(seedType)) {
keypairs[seedType] = makeKeyPair(seed, coinID, seedType)
}
})

Expand Down
8 changes: 4 additions & 4 deletions src/actions/actions/cache/Headers.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import {
getHeaderCache,
setCachedHeader,
BLOCK_HEADER_CACHE_CAP
} from '../../../utils/asyncStore/asyncStore';

import { BLOCK_HEADER_STORE_CAP } from '../../../../env/main.json'

import {
setBlockHeaders,
addBlockHeader
setBlockHeaders
} from '../../actionCreators'

//Load cached headers into store and pass in dispatch object
Expand Down Expand Up @@ -37,7 +37,7 @@ export const saveBlockHeader = (header, height, coinID, store) => {
return new Promise((resolve, reject) => {
setCachedHeader(header, height, coinID)
.then(() => {
if (numHeaders < global.BLOCK_HEADER_STORE_CAP) {
if (numHeaders < BLOCK_HEADER_STORE_CAP) {
return false
} else {
return loadCachedHeaders(store.dispatch)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Store from '../../../../store/index'
import Store from '../../../../../store/index'
import {
initializeWallet,
openWallet,
Expand All @@ -7,17 +7,18 @@ import {
startSync,
stopSync,
getAddresses
} from '../../../../utils/api/channels/dlight/callCreators'
import { DEFAULT_PRIVATE_ADDRS } from '../../../../utils/constants/constants'
import { resolveSequentially } from '../../../../utils/promises'
} from '../../../../../utils/api/channels/dlight/callCreators'
import { DEFAULT_PRIVATE_ADDRS } from '../../../../../utils/constants/constants'
import { resolveSequentially } from '../../../../../utils/promises'
import { canRetryDlightInitialization, blockchainQuitError } from './AlertManager'
import {
ERROR_DLIGHT_INIT,
STOP_DLIGHT_SYNC,
SET_DLIGHT_ADDRESSES,
CLOSE_DLIGHT_SOCKET,
INIT_DLIGHT_CHANNEL,
} from "../../../../utils/constants/storeType";
INIT_DLIGHT_CHANNEL_START,
CLOSE_DLIGHT_CHANNEL,
} from "../../../../../utils/constants/storeType";

// Initializes dlight wallet by either creating a backend native wallet and opening it or just opening it
export const initDlightWallet = (coinObj) => {
Expand Down Expand Up @@ -83,7 +84,7 @@ export const initDlightWallet = (coinObj) => {
resolveSequentially(initializationPromises)
.then(res => {
dispatch({
type: INIT_DLIGHT_CHANNEL,
type: INIT_DLIGHT_CHANNEL_START,
payload: { chainTicker: id }
})

Expand Down Expand Up @@ -156,6 +157,10 @@ export const closeDlightWallet = (coinObj, clearDb) => {
type: STOP_DLIGHT_SYNC,
payload: { chainTicker: id }
})
dispatch({
type: CLOSE_DLIGHT_CHANNEL,
payload: { chainTicker: id }
})

resolve()
})
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import Store from '../../../../../store/index'
import {
INIT_ELECTRUM_CHANNEL_START,
CLOSE_ELECTRUM_CHANNEL,
} from "../../../../../utils/constants/storeType";

export const initElectrumWallet = async (coinObj) => {
Store.dispatch({
type: INIT_ELECTRUM_CHANNEL_START,
payload: { chainTicker: coinObj.id }
})

return
}

export const closeElectrumWallet = async (coinObj) => {
Store.dispatch({
type: CLOSE_ELECTRUM_CHANNEL,
payload: { chainTicker: coinObj.id }
})

return
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import Store from '../../../../../store/index'
import {
INIT_ERC20_CHANNEL_START,
CLOSE_ERC20_CHANNEL,
} from "../../../../../utils/constants/storeType";

export const initErc20Wallet = async (coinObj) => {
Store.dispatch({
type: INIT_ERC20_CHANNEL_START,
payload: { chainTicker: coinObj.id, contractAddress: coinObj.contract_address }
})

return
}

export const closeErc20Wallet = async (coinObj) => {
Store.dispatch({
type: CLOSE_ERC20_CHANNEL,
payload: { chainTicker: coinObj.id, contractAddress: coinObj.contract_address }
})

return
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import Store from '../../../../../store/index'
import {
INIT_ETH_CHANNEL_START,
CLOSE_ETH_CHANNEL,
} from "../../../../../utils/constants/storeType";

export const initEthWallet = async (coinObj) => {
Store.dispatch({
type: INIT_ETH_CHANNEL_START,
payload: { chainTicker: coinObj.id }
})

return
}

export const closeEthWallet = async (coinObj) => {
Store.dispatch({
type: CLOSE_ETH_CHANNEL,
payload: { chainTicker: coinObj.id }
})

return
}
Loading

0 comments on commit 2955261

Please sign in to comment.