mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2024-11-19 01:40:12 +01:00
prettier
This commit is contained in:
parent
490eaf332e
commit
f1d68e53e6
13
.eslintrc
13
.eslintrc
@ -1,7 +1,16 @@
|
||||
{
|
||||
"parser": "babel-eslint",
|
||||
"plugins": [
|
||||
"react", "standard"
|
||||
"react", "prettier"
|
||||
],
|
||||
"extends": ["standard", "standard-react"]
|
||||
"extends": ["standard", "standard-react", "prettier"],
|
||||
"rules": {
|
||||
'prettier/prettier': [
|
||||
'warn',
|
||||
{
|
||||
singleQuote: true,
|
||||
trailingComma: 'all',
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
92
App.js
92
App.js
@ -1,63 +1,73 @@
|
||||
/** @type {AppStorage} */
|
||||
import './shim.js'
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Text, ScrollView, StyleSheet } from 'react-native'
|
||||
import { DrawerNavigator, SafeAreaView } from 'react-navigation'
|
||||
import MainBottomTabs from './MainBottomTabs'
|
||||
import './shim.js';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Text, ScrollView, StyleSheet } from 'react-native';
|
||||
import { DrawerNavigator, SafeAreaView } from 'react-navigation';
|
||||
import MainBottomTabs from './MainBottomTabs';
|
||||
|
||||
require('./BlueApp')
|
||||
require('./BlueApp');
|
||||
|
||||
if (!Error.captureStackTrace) { // captureStackTrace is only available when debugging
|
||||
Error.captureStackTrace = () => {}
|
||||
if (!Error.captureStackTrace) {
|
||||
// captureStackTrace is only available when debugging
|
||||
Error.captureStackTrace = () => {};
|
||||
}
|
||||
|
||||
const pkg = require('./package.json')
|
||||
const pkg = require('./package.json');
|
||||
|
||||
// <DrawerItems {...props} />
|
||||
|
||||
const CustomDrawerContentComponent = (props) => (
|
||||
const CustomDrawerContentComponent = props => (
|
||||
<ScrollView>
|
||||
<SafeAreaView style={styles.container} forceInset={{ top: 'always', horizontal: 'never' }}>
|
||||
|
||||
<Text onPress={() => props.navigation.navigate('AddWallet')} style={styles.heading}> {pkg.name} v{pkg.version}</Text>
|
||||
<SafeAreaView
|
||||
style={styles.container}
|
||||
forceInset={{ top: 'always', horizontal: 'never' }}
|
||||
>
|
||||
<Text
|
||||
onPress={() => props.navigation.navigate('AddWallet')}
|
||||
style={styles.heading}
|
||||
>
|
||||
{' '}
|
||||
{pkg.name} v{pkg.version}
|
||||
</Text>
|
||||
</SafeAreaView>
|
||||
</ScrollView>
|
||||
)
|
||||
);
|
||||
|
||||
CustomDrawerContentComponent.propTypes = {
|
||||
navigation: PropTypes.shape({
|
||||
navigate: PropTypes.func
|
||||
})
|
||||
}
|
||||
navigate: PropTypes.func,
|
||||
}),
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
marginTop: 20,
|
||||
flex: 1
|
||||
flex: 1,
|
||||
},
|
||||
heading: {
|
||||
textAlign: 'center',
|
||||
color: 'black',
|
||||
fontWeight: 'bold',
|
||||
fontSize: 20
|
||||
}
|
||||
})
|
||||
fontSize: 20,
|
||||
},
|
||||
});
|
||||
|
||||
/* import scanQrWifLegacyAddress from './screen/wallets/scanQrWifLegacyAddress'
|
||||
import scanQrWifSegwitP2SHAddress from './screen/wallets/scanQrWifSegwitP2SHAddress' */
|
||||
|
||||
const TabsInDrawer = DrawerNavigator({
|
||||
MainBottomTabs: {
|
||||
screen: MainBottomTabs,
|
||||
navigationOptions: {
|
||||
drawer: () => ({
|
||||
label: 'Tabs'
|
||||
})
|
||||
}
|
||||
}
|
||||
const TabsInDrawer = DrawerNavigator(
|
||||
{
|
||||
MainBottomTabs: {
|
||||
screen: MainBottomTabs,
|
||||
navigationOptions: {
|
||||
drawer: () => ({
|
||||
label: 'Tabs',
|
||||
}),
|
||||
},
|
||||
},
|
||||
|
||||
/* SecondaryBottomTabs: {
|
||||
/* SecondaryBottomTabs: {
|
||||
screen: SecondaryBottomTabs,
|
||||
path: 'chat/aaa',
|
||||
navigationOptions: {
|
||||
@ -73,13 +83,13 @@ const TabsInDrawer = DrawerNavigator({
|
||||
}),
|
||||
},
|
||||
}, */
|
||||
},
|
||||
{
|
||||
contentComponent: CustomDrawerContentComponent,
|
||||
drawerOpenRoute: 'DrawerOpen',
|
||||
drawerCloseRoute: 'DrawerClose',
|
||||
drawerToggleRoute: 'DrawerToggle',
|
||||
},
|
||||
);
|
||||
|
||||
}, {
|
||||
contentComponent: CustomDrawerContentComponent,
|
||||
drawerOpenRoute: 'DrawerOpen',
|
||||
drawerCloseRoute: 'DrawerClose',
|
||||
drawerToggleRoute: 'DrawerToggle'
|
||||
|
||||
})
|
||||
|
||||
export default TabsInDrawer
|
||||
export default TabsInDrawer;
|
||||
|
22
App.test.js
22
App.test.js
@ -1,17 +1,17 @@
|
||||
/* global describe, it */
|
||||
|
||||
import { LegacyWallet } from './class'
|
||||
let assert = require('assert')
|
||||
import { LegacyWallet } from './class';
|
||||
let assert = require('assert');
|
||||
|
||||
describe('unit - LegacyWallet', function () {
|
||||
describe('unit - LegacyWallet', function() {
|
||||
it('serialize and unserialize work correctly', () => {
|
||||
let a = new LegacyWallet()
|
||||
a.setLabel('my1')
|
||||
let key = JSON.stringify(a)
|
||||
let a = new LegacyWallet();
|
||||
a.setLabel('my1');
|
||||
let key = JSON.stringify(a);
|
||||
|
||||
let b = LegacyWallet.fromJson(key)
|
||||
assert(key === JSON.stringify(b))
|
||||
let b = LegacyWallet.fromJson(key);
|
||||
assert(key === JSON.stringify(b));
|
||||
|
||||
assert.equal(key, JSON.stringify(b))
|
||||
})
|
||||
})
|
||||
assert.equal(key, JSON.stringify(b));
|
||||
});
|
||||
});
|
||||
|
21
BlueApp.js
21
BlueApp.js
@ -2,16 +2,15 @@
|
||||
* @exports {AppStorage}
|
||||
*/
|
||||
|
||||
import {AppStorage} from './class'
|
||||
let EV = require('./events')
|
||||
import { AppStorage } from './class';
|
||||
let EV = require('./events');
|
||||
|
||||
let BlueApp = new AppStorage()
|
||||
let BlueApp = new AppStorage();
|
||||
(async () => {
|
||||
await BlueApp.loadFromDisk();
|
||||
console.log('loaded from disk');
|
||||
EV(EV.enum.WALLETS_COUNT_CHANGED);
|
||||
EV(EV.enum.TRANSACTIONS_COUNT_CHANGED);
|
||||
})();
|
||||
|
||||
;(async () => {
|
||||
await BlueApp.loadFromDisk()
|
||||
console.log('loaded from disk')
|
||||
EV(EV.enum.WALLETS_COUNT_CHANGED)
|
||||
EV(EV.enum.TRANSACTIONS_COUNT_CHANGED)
|
||||
})()
|
||||
|
||||
module.exports = BlueApp
|
||||
module.exports = BlueApp;
|
||||
|
@ -1,168 +1,163 @@
|
||||
/** @type {AppStorage} */
|
||||
import React, { Component } from 'react'
|
||||
import { SafeAreaView } from 'react-navigation'
|
||||
import { Button, FormLabel, FormInput, Card, Text, Header, List, ListItem } from 'react-native-elements'
|
||||
import { ActivityIndicator, ListView, View } from 'react-native'
|
||||
let BlueApp = require('./BlueApp')
|
||||
import React, { Component } from 'react';
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
import {
|
||||
Button,
|
||||
FormLabel,
|
||||
FormInput,
|
||||
Card,
|
||||
Text,
|
||||
Header,
|
||||
List,
|
||||
ListItem,
|
||||
} from 'react-native-elements';
|
||||
import { ActivityIndicator, ListView, View } from 'react-native';
|
||||
let BlueApp = require('./BlueApp');
|
||||
|
||||
export class BlueButton extends Component {
|
||||
render () {
|
||||
render() {
|
||||
return (
|
||||
<Button
|
||||
{...this.props}
|
||||
style={{marginTop: 20, borderRadius: 6, borderWidth: 0.7, borderColor: '#ffffff'}}
|
||||
style={{
|
||||
marginTop: 20,
|
||||
borderRadius: 6,
|
||||
borderWidth: 0.7,
|
||||
borderColor: '#ffffff',
|
||||
}}
|
||||
borderRadius={10}
|
||||
backgroundColor={BlueApp.settings.buttonBackground}
|
||||
|
||||
/>
|
||||
)
|
||||
);
|
||||
}
|
||||
/* icon={{name: 'home', type: 'octicon'}} */
|
||||
}
|
||||
|
||||
export class SafeBlueArea extends Component {
|
||||
render () {
|
||||
render() {
|
||||
return (
|
||||
<SafeAreaView
|
||||
{...this.props}
|
||||
forceInset={{ horizontal: 'always' }} style={{flex: 1, backgroundColor: BlueApp.settings.brandingColor}}
|
||||
forceInset={{ horizontal: 'always' }}
|
||||
style={{ flex: 1, backgroundColor: BlueApp.settings.brandingColor }}
|
||||
/>
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class BlueCard extends Component {
|
||||
render () {
|
||||
render() {
|
||||
return (
|
||||
<Card
|
||||
{...this.props}
|
||||
titleStyle={{color: 'white'}}
|
||||
containerStyle={{backgroundColor: BlueApp.settings.buttonBackground}}
|
||||
wrapperStyle={{backgroundColor: BlueApp.settings.buttonBackground}}
|
||||
titleStyle={{ color: 'white' }}
|
||||
containerStyle={{ backgroundColor: BlueApp.settings.buttonBackground }}
|
||||
wrapperStyle={{ backgroundColor: BlueApp.settings.buttonBackground }}
|
||||
/>
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class BlueText extends Component {
|
||||
render () {
|
||||
return (
|
||||
<Text
|
||||
{...this.props}
|
||||
style={{color: 'white'}}
|
||||
/>
|
||||
)
|
||||
render() {
|
||||
return <Text {...this.props} style={{ color: 'white' }} />;
|
||||
}
|
||||
}
|
||||
|
||||
export class BlueListItem extends Component {
|
||||
render () {
|
||||
render() {
|
||||
return (
|
||||
<ListItem
|
||||
{...this.props}
|
||||
containerStyle={{backgroundColor: BlueApp.settings.brandingColor}}
|
||||
titleStyle={{color: 'white', fontSize: 18}}
|
||||
subtitleStyle={{color: 'white'}}
|
||||
containerStyle={{ backgroundColor: BlueApp.settings.brandingColor }}
|
||||
titleStyle={{ color: 'white', fontSize: 18 }}
|
||||
subtitleStyle={{ color: 'white' }}
|
||||
/>
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class BlueFormLabel extends Component {
|
||||
render () {
|
||||
return (
|
||||
<FormLabel
|
||||
{...this.props}
|
||||
labelStyle={{color: 'white'}}
|
||||
/>
|
||||
)
|
||||
render() {
|
||||
return <FormLabel {...this.props} labelStyle={{ color: 'white' }} />;
|
||||
}
|
||||
}
|
||||
|
||||
export class BlueFormInput extends Component {
|
||||
render () {
|
||||
return (
|
||||
<FormInput
|
||||
{...this.props}
|
||||
inputStyle={{color: 'white'}}
|
||||
/>
|
||||
)
|
||||
render() {
|
||||
return <FormInput {...this.props} inputStyle={{ color: 'white' }} />;
|
||||
}
|
||||
}
|
||||
|
||||
export class BlueHeader extends Component {
|
||||
render () {
|
||||
render() {
|
||||
return (
|
||||
<Header
|
||||
{...this.props}
|
||||
backgroundColor={BlueApp.settings.brandingColor}
|
||||
/>
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class BlueSpacing extends Component {
|
||||
render () {
|
||||
render() {
|
||||
return (
|
||||
<View
|
||||
{...this.props}
|
||||
style={{height: 60, backgroundColor: BlueApp.settings.brandingColor}}
|
||||
style={{ height: 60, backgroundColor: BlueApp.settings.brandingColor }}
|
||||
/>
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class BlueSpacing20 extends Component {
|
||||
render () {
|
||||
render() {
|
||||
return (
|
||||
<View
|
||||
{...this.props}
|
||||
style={{height: 20, backgroundColor: BlueApp.settings.brandingColor}}
|
||||
style={{ height: 20, backgroundColor: BlueApp.settings.brandingColor }}
|
||||
/>
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class BlueListView extends Component {
|
||||
render () {
|
||||
return (
|
||||
<ListView
|
||||
{...this.props}
|
||||
/>
|
||||
)
|
||||
render() {
|
||||
return <ListView {...this.props} />;
|
||||
}
|
||||
}
|
||||
|
||||
export class BlueList extends Component {
|
||||
render () {
|
||||
render() {
|
||||
return (
|
||||
<List
|
||||
{...this.props}
|
||||
containerStyle={{backgroundColor: BlueApp.settings.brandingColor}}
|
||||
containerStyle={{ backgroundColor: BlueApp.settings.brandingColor }}
|
||||
/>
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class BlueView extends Component {
|
||||
render () {
|
||||
render() {
|
||||
return (
|
||||
<View
|
||||
{...this.props}
|
||||
containerStyle={{backgroundColor: BlueApp.settings.brandingColor}}
|
||||
containerStyle={{ backgroundColor: BlueApp.settings.brandingColor }}
|
||||
/>
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class BlueLoading extends Component {
|
||||
render () {
|
||||
render() {
|
||||
return (
|
||||
<SafeBlueArea >
|
||||
<View style={{flex: 1, paddingTop: 200}}>
|
||||
<SafeBlueArea>
|
||||
<View style={{ flex: 1, paddingTop: 200 }}>
|
||||
<ActivityIndicator />
|
||||
</View>
|
||||
</SafeBlueArea>
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,39 +1,39 @@
|
||||
import { TabNavigator } from 'react-navigation'
|
||||
import { TabNavigator } from 'react-navigation';
|
||||
|
||||
import transactions from './screen/transactions'
|
||||
import wallets from './screen/wallets'
|
||||
import send from './screen/send'
|
||||
import settins from './screen/settings'
|
||||
import receive from './screen/receive'
|
||||
import transactions from './screen/transactions';
|
||||
import wallets from './screen/wallets';
|
||||
import send from './screen/send';
|
||||
import settins from './screen/settings';
|
||||
import receive from './screen/receive';
|
||||
|
||||
/**
|
||||
*
|
||||
* @type {AppStorage}
|
||||
*/
|
||||
let BlueApp = require('./BlueApp')
|
||||
let BlueApp = require('./BlueApp');
|
||||
|
||||
const Tabs = TabNavigator(
|
||||
{
|
||||
Wallets: {
|
||||
screen: wallets,
|
||||
path: 'wallets'
|
||||
path: 'wallets',
|
||||
},
|
||||
Transactions: {
|
||||
screen: transactions,
|
||||
path: 'trans'
|
||||
path: 'trans',
|
||||
},
|
||||
Send: {
|
||||
screen: send,
|
||||
path: 'cart'
|
||||
path: 'cart',
|
||||
},
|
||||
Receive: {
|
||||
screen: receive,
|
||||
path: 'receive'
|
||||
path: 'receive',
|
||||
},
|
||||
Settings: {
|
||||
screen: settins,
|
||||
path: 'settings'
|
||||
}
|
||||
path: 'settings',
|
||||
},
|
||||
},
|
||||
{
|
||||
tabBarPosition: 'bottom',
|
||||
@ -42,9 +42,9 @@ const Tabs = TabNavigator(
|
||||
activeTintColor: 'white',
|
||||
activeBackgroundColor: '#33bdf1',
|
||||
inactiveBackgroundColor: BlueApp.settings.brandingColor,
|
||||
inactiveTintColor: 'white'
|
||||
}
|
||||
}
|
||||
)
|
||||
inactiveTintColor: 'white',
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
export default Tabs
|
||||
export default Tabs;
|
||||
|
@ -2,12 +2,12 @@
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react'
|
||||
import { Button, ScrollView } from 'react-native'
|
||||
import { SafeAreaView, StackNavigator, TabNavigator } from 'react-navigation'
|
||||
import React from 'react';
|
||||
import { Button, ScrollView } from 'react-native';
|
||||
import { SafeAreaView, StackNavigator, TabNavigator } from 'react-navigation';
|
||||
|
||||
import Ionicons from 'react-native-vector-icons/Ionicons'
|
||||
import SampleText from './SampleText'
|
||||
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||
import SampleText from './SampleText';
|
||||
|
||||
const MyNavScreen = ({ navigation, banner }) => (
|
||||
<ScrollView>
|
||||
@ -15,35 +15,35 @@ const MyNavScreen = ({ navigation, banner }) => (
|
||||
<SampleText>{banner}</SampleText>
|
||||
<Button
|
||||
onPress={() => navigation.navigate('Profile', { name: 'Jordan' })}
|
||||
title='Open profile screen'
|
||||
title="Open profile screen"
|
||||
/>
|
||||
<Button
|
||||
onPress={() => navigation.navigate('NotifSettings')}
|
||||
title='Open notifications screen'
|
||||
title="Open notifications screen"
|
||||
/>
|
||||
<Button
|
||||
onPress={() => navigation.navigate('SettingsTab')}
|
||||
title='Go to settings tab'
|
||||
title="Go to settings tab"
|
||||
/>
|
||||
<Button onPress={() => navigation.goBack(null)} title='Go back' />
|
||||
<Button onPress={() => navigation.goBack(null)} title="Go back" />
|
||||
</SafeAreaView>
|
||||
</ScrollView>
|
||||
)
|
||||
);
|
||||
|
||||
const MyHomeScreen = ({ navigation }) => (
|
||||
<MyNavScreen banner='Home Screen' navigation={navigation} />
|
||||
)
|
||||
<MyNavScreen banner="Home Screen" navigation={navigation} />
|
||||
);
|
||||
|
||||
const MyNotificationsSettingsScreen = ({ navigation }) => (
|
||||
<MyNavScreen banner='Notifications Screen' navigation={navigation} />
|
||||
)
|
||||
<MyNavScreen banner="Notifications Screen" navigation={navigation} />
|
||||
);
|
||||
|
||||
const MySettingsScreen = ({ navigation }) => (
|
||||
<MyNavScreen banner='Settings Screen' navigation={navigation} />
|
||||
)
|
||||
<MyNavScreen banner="Settings Screen" navigation={navigation} />
|
||||
);
|
||||
|
||||
var bitcoin = require('bitcoinjs-lib')
|
||||
var myString = bitcoin.ECPair.makeRandom().toWIF()
|
||||
var bitcoin = require('bitcoinjs-lib');
|
||||
var myString = bitcoin.ECPair.makeRandom().toWIF();
|
||||
|
||||
const TabNav = TabNavigator(
|
||||
{
|
||||
@ -59,8 +59,8 @@ const TabNav = TabNavigator(
|
||||
size={26}
|
||||
style={{ color: tintColor }}
|
||||
/>
|
||||
)
|
||||
}
|
||||
),
|
||||
},
|
||||
},
|
||||
SettingsTab: {
|
||||
screen: MySettingsScreen,
|
||||
@ -73,27 +73,27 @@ const TabNav = TabNavigator(
|
||||
size={26}
|
||||
style={{ color: tintColor }}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
tabBarPosition: 'bottom',
|
||||
animationEnabled: false,
|
||||
swipeEnabled: false
|
||||
}
|
||||
)
|
||||
swipeEnabled: false,
|
||||
},
|
||||
);
|
||||
|
||||
const SecondaryBottomTabs = StackNavigator({
|
||||
Root: {
|
||||
screen: TabNav
|
||||
screen: TabNav,
|
||||
},
|
||||
NotifSettings: {
|
||||
screen: MyNotificationsSettingsScreen,
|
||||
navigationOptions: {
|
||||
title: 'Notifications'
|
||||
}
|
||||
}
|
||||
})
|
||||
title: 'Notifications',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export default SecondaryBottomTabs
|
||||
export default SecondaryBottomTabs;
|
||||
|
536
class.js
536
class.js
@ -1,71 +1,71 @@
|
||||
/* global fetch */
|
||||
import { AsyncStorage } from 'react-native'
|
||||
import Frisbee from 'frisbee'
|
||||
import { AsyncStorage } from 'react-native';
|
||||
import Frisbee from 'frisbee';
|
||||
|
||||
let useBlockcypherTokens = false
|
||||
let useBlockcypherTokens = false;
|
||||
|
||||
let bitcoin = require('bitcoinjs-lib')
|
||||
let signer = require('./models/signer')
|
||||
let BigNumber = require('bignumber.js')
|
||||
let isaac = require('isaac')
|
||||
let bitcoin = require('bitcoinjs-lib');
|
||||
let signer = require('./models/signer');
|
||||
let BigNumber = require('bignumber.js');
|
||||
let isaac = require('isaac');
|
||||
// alternative https://github.com/pointbiz/bitaddress.org/blob/master/src/securerandom.js
|
||||
|
||||
class AbstractWallet {
|
||||
constructor () {
|
||||
this.type = 'abstract'
|
||||
this.label = ''
|
||||
this.secret = '' // private key or recovery phrase
|
||||
this.balance = 0
|
||||
this.transactions = []
|
||||
this._address = false // cache
|
||||
this.utxo = []
|
||||
constructor() {
|
||||
this.type = 'abstract';
|
||||
this.label = '';
|
||||
this.secret = ''; // private key or recovery phrase
|
||||
this.balance = 0;
|
||||
this.transactions = [];
|
||||
this._address = false; // cache
|
||||
this.utxo = [];
|
||||
}
|
||||
|
||||
getTransactions () {
|
||||
return this.transactions
|
||||
getTransactions() {
|
||||
return this.transactions;
|
||||
}
|
||||
|
||||
getTypeReadable () {
|
||||
return this.type
|
||||
getTypeReadable() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
getLabel () {
|
||||
return this.label
|
||||
getLabel() {
|
||||
return this.label;
|
||||
}
|
||||
|
||||
getBalance () {
|
||||
return this.balance
|
||||
getBalance() {
|
||||
return this.balance;
|
||||
}
|
||||
|
||||
setLabel (newLabel) {
|
||||
this.label = newLabel
|
||||
return this
|
||||
setLabel(newLabel) {
|
||||
this.label = newLabel;
|
||||
return this;
|
||||
}
|
||||
|
||||
getSecret () {
|
||||
return this.secret
|
||||
getSecret() {
|
||||
return this.secret;
|
||||
}
|
||||
|
||||
setSecret (newSecret) {
|
||||
this.secret = newSecret
|
||||
return this
|
||||
setSecret(newSecret) {
|
||||
this.secret = newSecret;
|
||||
return this;
|
||||
}
|
||||
|
||||
static fromJson (obj) {
|
||||
let obj2 = JSON.parse(obj)
|
||||
let temp = new this()
|
||||
static fromJson(obj) {
|
||||
let obj2 = JSON.parse(obj);
|
||||
let temp = new this();
|
||||
for (let key2 of Object.keys(obj2)) {
|
||||
temp[key2] = obj2[key2]
|
||||
temp[key2] = obj2[key2];
|
||||
}
|
||||
|
||||
return temp
|
||||
return temp;
|
||||
}
|
||||
|
||||
getAddress () {}
|
||||
getAddress() {}
|
||||
|
||||
// createTx () { throw Error('not implemented') }
|
||||
}
|
||||
@ -75,181 +75,252 @@ class AbstractWallet {
|
||||
* (legacy P2PKH compressed)
|
||||
*/
|
||||
export class LegacyWallet extends AbstractWallet {
|
||||
constructor () {
|
||||
super()
|
||||
this.type = 'legacy'
|
||||
constructor() {
|
||||
super();
|
||||
this.type = 'legacy';
|
||||
}
|
||||
|
||||
generate () {
|
||||
function myRng (c) {
|
||||
let buf = Buffer.alloc(c)
|
||||
let totalhex = ''
|
||||
generate() {
|
||||
function myRng(c) {
|
||||
let buf = Buffer.alloc(c);
|
||||
let totalhex = '';
|
||||
for (let i = 0; i < c; i++) {
|
||||
let randomNumber = isaac.random()
|
||||
randomNumber = Math.floor(randomNumber * 255)
|
||||
let n = new BigNumber(randomNumber)
|
||||
let hex = n.toString(16)
|
||||
let randomNumber = isaac.random();
|
||||
randomNumber = Math.floor(randomNumber * 255);
|
||||
let n = new BigNumber(randomNumber);
|
||||
let hex = n.toString(16);
|
||||
if (hex.length === 1) {
|
||||
hex = '0' + hex
|
||||
hex = '0' + hex;
|
||||
}
|
||||
totalhex += hex
|
||||
totalhex += hex;
|
||||
}
|
||||
totalhex = bitcoin.crypto.sha256('oh hai!' + totalhex).toString('hex')
|
||||
totalhex = bitcoin.crypto.sha256(totalhex).toString('hex')
|
||||
buf.fill(totalhex, 0, 'hex')
|
||||
return buf
|
||||
totalhex = bitcoin.crypto.sha256('oh hai!' + totalhex).toString('hex');
|
||||
totalhex = bitcoin.crypto.sha256(totalhex).toString('hex');
|
||||
buf.fill(totalhex, 0, 'hex');
|
||||
return buf;
|
||||
}
|
||||
this.secret = bitcoin.ECPair.makeRandom({ rng: myRng }).toWIF()
|
||||
this.secret = bitcoin.ECPair.makeRandom({ rng: myRng }).toWIF();
|
||||
}
|
||||
|
||||
getTypeReadable () {
|
||||
return 'P2 PKH'
|
||||
getTypeReadable() {
|
||||
return 'P2 PKH';
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
getAddress () {
|
||||
if (this._address) return this._address
|
||||
let address
|
||||
getAddress() {
|
||||
if (this._address) return this._address;
|
||||
let address;
|
||||
try {
|
||||
let keyPair = bitcoin.ECPair.fromWIF(this.secret)
|
||||
address = keyPair.getAddress()
|
||||
let keyPair = bitcoin.ECPair.fromWIF(this.secret);
|
||||
address = keyPair.getAddress();
|
||||
} catch (err) {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
this._address = address
|
||||
this._address = address;
|
||||
|
||||
return this._address
|
||||
return this._address;
|
||||
}
|
||||
|
||||
async fetchBalance () {
|
||||
let response
|
||||
let token = ((array) => {
|
||||
async fetchBalance() {
|
||||
let response;
|
||||
let token = (array => {
|
||||
for (let i = array.length - 1; i > 0; i--) {
|
||||
let j = Math.floor(Math.random() * (i + 1));
|
||||
[array[i], array[j]] = [array[j], array[i]]
|
||||
[array[i], array[j]] = [array[j], array[i]];
|
||||
}
|
||||
return array[0]
|
||||
})(['0326b7107b4149559d18ce80612ef812', 'a133eb7ccacd4accb80cb1225de4b155', '7c2b1628d27b4bd3bf8eaee7149c577f', 'f1e5a02b9ec84ec4bc8db2349022e5f5', 'e5926dbeb57145979153adc41305b183'])
|
||||
return array[0];
|
||||
})([
|
||||
'0326b7107b4149559d18ce80612ef812',
|
||||
'a133eb7ccacd4accb80cb1225de4b155',
|
||||
'7c2b1628d27b4bd3bf8eaee7149c577f',
|
||||
'f1e5a02b9ec84ec4bc8db2349022e5f5',
|
||||
'e5926dbeb57145979153adc41305b183',
|
||||
]);
|
||||
try {
|
||||
if (useBlockcypherTokens) {
|
||||
response = await fetch('https://api.blockcypher.com/v1/btc/main/addrs/' + this.getAddress() + '/balance?token=' + token)
|
||||
response = await fetch(
|
||||
'https://api.blockcypher.com/v1/btc/main/addrs/' +
|
||||
this.getAddress() +
|
||||
'/balance?token=' +
|
||||
token,
|
||||
);
|
||||
} else {
|
||||
response = await fetch('https://api.blockcypher.com/v1/btc/main/addrs/' + this.getAddress() + '/balance')
|
||||
response = await fetch(
|
||||
'https://api.blockcypher.com/v1/btc/main/addrs/' +
|
||||
this.getAddress() +
|
||||
'/balance',
|
||||
);
|
||||
}
|
||||
let json = await response.json()
|
||||
let json = await response.json();
|
||||
if (typeof json.final_balance === 'undefined') {
|
||||
throw new Error('Could not fetch balance from API')
|
||||
throw new Error('Could not fetch balance from API');
|
||||
}
|
||||
this.balance = json.final_balance / 100000000
|
||||
this.balance = json.final_balance / 100000000;
|
||||
} catch (err) {
|
||||
console.warn(err)
|
||||
console.warn(err);
|
||||
}
|
||||
}
|
||||
|
||||
async fetchUtxo () {
|
||||
let response
|
||||
let token = ((array) => {
|
||||
async fetchUtxo() {
|
||||
let response;
|
||||
let token = (array => {
|
||||
for (let i = array.length - 1; i > 0; i--) {
|
||||
let j = Math.floor(Math.random() * (i + 1));
|
||||
[array[i], array[j]] = [array[j], array[i]]
|
||||
[array[i], array[j]] = [array[j], array[i]];
|
||||
}
|
||||
return array[0]
|
||||
})(['0326b7107b4149559d18ce80612ef812', 'a133eb7ccacd4accb80cb1225de4b155', '7c2b1628d27b4bd3bf8eaee7149c577f', 'f1e5a02b9ec84ec4bc8db2349022e5f5', 'e5926dbeb57145979153adc41305b183'])
|
||||
return array[0];
|
||||
})([
|
||||
'0326b7107b4149559d18ce80612ef812',
|
||||
'a133eb7ccacd4accb80cb1225de4b155',
|
||||
'7c2b1628d27b4bd3bf8eaee7149c577f',
|
||||
'f1e5a02b9ec84ec4bc8db2349022e5f5',
|
||||
'e5926dbeb57145979153adc41305b183',
|
||||
]);
|
||||
try {
|
||||
// TODO: hande case when there's more than 2000 UTXOs (do pagination)
|
||||
// TODO: (2000 is max UTXOs we can fetch in one call)
|
||||
if (useBlockcypherTokens) {
|
||||
response = await fetch('https://api.blockcypher.com/v1/btc/main/addrs/' + this.getAddress() + '?unspentOnly=true&limit=2000&token=' + token)
|
||||
response = await fetch(
|
||||
'https://api.blockcypher.com/v1/btc/main/addrs/' +
|
||||
this.getAddress() +
|
||||
'?unspentOnly=true&limit=2000&token=' +
|
||||
token,
|
||||
);
|
||||
} else {
|
||||
response = await fetch('https://api.blockcypher.com/v1/btc/main/addrs/' + this.getAddress() + '?unspentOnly=true&limit=2000')
|
||||
response = await fetch(
|
||||
'https://api.blockcypher.com/v1/btc/main/addrs/' +
|
||||
this.getAddress() +
|
||||
'?unspentOnly=true&limit=2000',
|
||||
);
|
||||
}
|
||||
let json = await response.json()
|
||||
let json = await response.json();
|
||||
if (typeof json.final_balance === 'undefined') {
|
||||
throw new Error('Could not fetch UTXO from API')
|
||||
throw new Error('Could not fetch UTXO from API');
|
||||
}
|
||||
json.txrefs = json.txrefs || [] // case when source address is empty
|
||||
this.utxo = json.txrefs
|
||||
json.txrefs = json.txrefs || []; // case when source address is empty
|
||||
this.utxo = json.txrefs;
|
||||
|
||||
json.unconfirmed_txrefs = json.unconfirmed_txrefs || []
|
||||
this.utxo = this.utxo.concat(json.unconfirmed_txrefs)
|
||||
json.unconfirmed_txrefs = json.unconfirmed_txrefs || [];
|
||||
this.utxo = this.utxo.concat(json.unconfirmed_txrefs);
|
||||
|
||||
console.log('got utxo: ', this.utxo)
|
||||
console.log('got utxo: ', this.utxo);
|
||||
} catch (err) {
|
||||
console.warn(err)
|
||||
console.warn(err);
|
||||
}
|
||||
}
|
||||
|
||||
async fetchTransactions () {
|
||||
let response
|
||||
let token = ((array) => {
|
||||
async fetchTransactions() {
|
||||
let response;
|
||||
let token = (array => {
|
||||
for (let i = array.length - 1; i > 0; i--) {
|
||||
let j = Math.floor(Math.random() * (i + 1));
|
||||
[array[i], array[j]] = [array[j], array[i]]
|
||||
[array[i], array[j]] = [array[j], array[i]];
|
||||
}
|
||||
return array[0]
|
||||
})(['0326b7107b4149559d18ce80612ef812', 'a133eb7ccacd4accb80cb1225de4b155', '7c2b1628d27b4bd3bf8eaee7149c577f', 'f1e5a02b9ec84ec4bc8db2349022e5f5', 'e5926dbeb57145979153adc41305b183'])
|
||||
return array[0];
|
||||
})([
|
||||
'0326b7107b4149559d18ce80612ef812',
|
||||
'a133eb7ccacd4accb80cb1225de4b155',
|
||||
'7c2b1628d27b4bd3bf8eaee7149c577f',
|
||||
'f1e5a02b9ec84ec4bc8db2349022e5f5',
|
||||
'e5926dbeb57145979153adc41305b183',
|
||||
]);
|
||||
try {
|
||||
let url
|
||||
let url;
|
||||
if (useBlockcypherTokens) {
|
||||
response = await fetch(url = 'https://api.blockcypher.com/v1/btc/main/addrs/' + this.getAddress() + '/full?token=' + token)
|
||||
response = await fetch(
|
||||
(url =
|
||||
'https://api.blockcypher.com/v1/btc/main/addrs/' +
|
||||
this.getAddress() +
|
||||
'/full?token=' +
|
||||
token),
|
||||
);
|
||||
} else {
|
||||
response = await fetch(url = 'https://api.blockcypher.com/v1/btc/main/addrs/' + this.getAddress() + '/full')
|
||||
response = await fetch(
|
||||
(url =
|
||||
'https://api.blockcypher.com/v1/btc/main/addrs/' +
|
||||
this.getAddress() +
|
||||
'/full'),
|
||||
);
|
||||
}
|
||||
console.log(url)
|
||||
let json = await response.json()
|
||||
console.log(url);
|
||||
let json = await response.json();
|
||||
if (!json.txs) {
|
||||
throw new Error('Could not fetch transactions from API')
|
||||
throw new Error('Could not fetch transactions from API');
|
||||
}
|
||||
|
||||
this.transactions = json.txs
|
||||
this.transactions = json.txs;
|
||||
// now, calculating value per each transaction...
|
||||
for (let tx of this.transactions) {
|
||||
// how much came in...
|
||||
let value = 0
|
||||
let value = 0;
|
||||
for (let out of tx.outputs) {
|
||||
if (out.addresses.indexOf(this.getAddress()) !== -1) { // found our address in outs of this TX
|
||||
value += out.value
|
||||
if (out.addresses.indexOf(this.getAddress()) !== -1) {
|
||||
// found our address in outs of this TX
|
||||
value += out.value;
|
||||
}
|
||||
}
|
||||
tx.value = value
|
||||
tx.value = value;
|
||||
// end
|
||||
|
||||
// how much came out
|
||||
value = 0
|
||||
value = 0;
|
||||
for (let inp of tx.inputs) {
|
||||
if (inp.addresses.indexOf(this.getAddress()) !== -1) { // found our address in outs of this TX
|
||||
value -= inp.output_value
|
||||
if (inp.addresses.indexOf(this.getAddress()) !== -1) {
|
||||
// found our address in outs of this TX
|
||||
value -= inp.output_value;
|
||||
}
|
||||
}
|
||||
console.log('came out', value)
|
||||
tx.value += value
|
||||
console.log('came out', value);
|
||||
tx.value += value;
|
||||
// end
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn(err)
|
||||
console.warn(err);
|
||||
}
|
||||
}
|
||||
|
||||
getShortAddress () {
|
||||
let a = this.getAddress().split('')
|
||||
return a[0] + a[1] + a[2] + a[3] + a[4] + a[5] + a[6] + a[7] + a[8] + a[9] + a[10] + a[11] + a[12] + a[13] + '...' + a[a.length - 6] + a[a.length - 5] + a[a.length - 4] + a[a.length - 3] + a[a.length - 2] + a[a.length - 1]
|
||||
getShortAddress() {
|
||||
let a = this.getAddress().split('');
|
||||
return (
|
||||
a[0] +
|
||||
a[1] +
|
||||
a[2] +
|
||||
a[3] +
|
||||
a[4] +
|
||||
a[5] +
|
||||
a[6] +
|
||||
a[7] +
|
||||
a[8] +
|
||||
a[9] +
|
||||
a[10] +
|
||||
a[11] +
|
||||
a[12] +
|
||||
a[13] +
|
||||
'...' +
|
||||
a[a.length - 6] +
|
||||
a[a.length - 5] +
|
||||
a[a.length - 4] +
|
||||
a[a.length - 3] +
|
||||
a[a.length - 2] +
|
||||
a[a.length - 1]
|
||||
);
|
||||
}
|
||||
|
||||
async broadcastTx (txhex) {
|
||||
async broadcastTx(txhex) {
|
||||
const api = new Frisbee({
|
||||
baseURI: 'https://btczen.com',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
let res = await api.get('/broadcast/' + txhex)
|
||||
console.log('response', res.body)
|
||||
return res.body
|
||||
let res = await api.get('/broadcast/' + txhex);
|
||||
console.log('response', res.body);
|
||||
return res.body;
|
||||
|
||||
/* const api = new Frisbee({
|
||||
baseURI: 'https://api.blockcypher.com',
|
||||
@ -273,121 +344,144 @@ export class LegacyWallet extends AbstractWallet {
|
||||
}
|
||||
|
||||
export class SegwitBech32Wallet extends LegacyWallet {
|
||||
constructor () {
|
||||
super()
|
||||
this.type = 'segwitBech32'
|
||||
constructor() {
|
||||
super();
|
||||
this.type = 'segwitBech32';
|
||||
}
|
||||
|
||||
getTypeReadable () {
|
||||
return 'P2 WPKH'
|
||||
getTypeReadable() {
|
||||
return 'P2 WPKH';
|
||||
}
|
||||
|
||||
getAddress () {
|
||||
if (this._address) return this._address
|
||||
let address
|
||||
getAddress() {
|
||||
if (this._address) return this._address;
|
||||
let address;
|
||||
try {
|
||||
let keyPair = bitcoin.ECPair.fromWIF(this.secret)
|
||||
let pubKey = keyPair.getPublicKeyBuffer()
|
||||
let scriptPubKey = bitcoin.script.witnessPubKeyHash.output.encode(bitcoin.crypto.hash160(pubKey))
|
||||
address = bitcoin.address.fromOutputScript(scriptPubKey)
|
||||
let keyPair = bitcoin.ECPair.fromWIF(this.secret);
|
||||
let pubKey = keyPair.getPublicKeyBuffer();
|
||||
let scriptPubKey = bitcoin.script.witnessPubKeyHash.output.encode(
|
||||
bitcoin.crypto.hash160(pubKey),
|
||||
);
|
||||
address = bitcoin.address.fromOutputScript(scriptPubKey);
|
||||
} catch (err) {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
this._address = address
|
||||
this._address = address;
|
||||
|
||||
return this._address
|
||||
return this._address;
|
||||
}
|
||||
}
|
||||
|
||||
export class SegwitP2SHWallet extends LegacyWallet {
|
||||
constructor () {
|
||||
super()
|
||||
this.type = 'segwitP2SH'
|
||||
constructor() {
|
||||
super();
|
||||
this.type = 'segwitP2SH';
|
||||
}
|
||||
|
||||
getTypeReadable () {
|
||||
return 'SegWit (P2SH)'
|
||||
getTypeReadable() {
|
||||
return 'SegWit (P2SH)';
|
||||
}
|
||||
|
||||
getAddress () {
|
||||
if (this._address) return this._address
|
||||
let address
|
||||
getAddress() {
|
||||
if (this._address) return this._address;
|
||||
let address;
|
||||
try {
|
||||
let keyPair = bitcoin.ECPair.fromWIF(this.secret)
|
||||
let pubKey = keyPair.getPublicKeyBuffer()
|
||||
let witnessScript = bitcoin.script.witnessPubKeyHash.output.encode(bitcoin.crypto.hash160(pubKey))
|
||||
let scriptPubKey = bitcoin.script.scriptHash.output.encode(bitcoin.crypto.hash160(witnessScript))
|
||||
address = bitcoin.address.fromOutputScript(scriptPubKey)
|
||||
let keyPair = bitcoin.ECPair.fromWIF(this.secret);
|
||||
let pubKey = keyPair.getPublicKeyBuffer();
|
||||
let witnessScript = bitcoin.script.witnessPubKeyHash.output.encode(
|
||||
bitcoin.crypto.hash160(pubKey),
|
||||
);
|
||||
let scriptPubKey = bitcoin.script.scriptHash.output.encode(
|
||||
bitcoin.crypto.hash160(witnessScript),
|
||||
);
|
||||
address = bitcoin.address.fromOutputScript(scriptPubKey);
|
||||
} catch (err) {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
this._address = address
|
||||
this._address = address;
|
||||
|
||||
return this._address
|
||||
return this._address;
|
||||
}
|
||||
|
||||
createTx (utxos, amount, fee, address, memo, sequence) {
|
||||
createTx(utxos, amount, fee, address, memo, sequence) {
|
||||
if (sequence === undefined) {
|
||||
sequence = 0
|
||||
sequence = 0;
|
||||
}
|
||||
// transforming UTXOs fields to how module expects it
|
||||
for (let u of utxos) {
|
||||
u.confirmations = 6 // hack to make module accept 0 confirmations
|
||||
u.txid = u.tx_hash
|
||||
u.vout = u.tx_output_n
|
||||
u.amount = new BigNumber(u.value)
|
||||
u.amount = u.amount.div(100000000)
|
||||
u.amount = u.amount.toString(10)
|
||||
u.confirmations = 6; // hack to make module accept 0 confirmations
|
||||
u.txid = u.tx_hash;
|
||||
u.vout = u.tx_output_n;
|
||||
u.amount = new BigNumber(u.value);
|
||||
u.amount = u.amount.div(100000000);
|
||||
u.amount = u.amount.toString(10);
|
||||
}
|
||||
console.log('creating tx ', amount, ' with fee ', fee, 'secret=', this.getSecret(), 'from address', this.getAddress())
|
||||
let amountPlusFee = parseFloat((new BigNumber(amount)).add(fee).toString(10))
|
||||
console.log(
|
||||
'creating tx ',
|
||||
amount,
|
||||
' with fee ',
|
||||
fee,
|
||||
'secret=',
|
||||
this.getSecret(),
|
||||
'from address',
|
||||
this.getAddress(),
|
||||
);
|
||||
let amountPlusFee = parseFloat(new BigNumber(amount).add(fee).toString(10));
|
||||
// to compensate that module substracts fee from amount
|
||||
return signer.createSegwitTransaction(utxos, address, amountPlusFee, fee, this.getSecret(), this.getAddress(), sequence)
|
||||
return signer.createSegwitTransaction(
|
||||
utxos,
|
||||
address,
|
||||
amountPlusFee,
|
||||
fee,
|
||||
this.getSecret(),
|
||||
this.getAddress(),
|
||||
sequence,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class AppStorage {
|
||||
constructor () {
|
||||
constructor() {
|
||||
/** {Array.<AbstractWallet>} */
|
||||
this.wallets = []
|
||||
this.tx_metadata = {}
|
||||
this.wallets = [];
|
||||
this.tx_metadata = {};
|
||||
this.settings = {
|
||||
brandingColor: '#00aced',
|
||||
buttonBackground: '#00aced',
|
||||
buttonDangedBackground: '#F40349'
|
||||
}
|
||||
buttonDangedBackground: '#F40349',
|
||||
};
|
||||
}
|
||||
|
||||
async loadFromDisk () {
|
||||
async loadFromDisk() {
|
||||
try {
|
||||
let data = await AsyncStorage.getItem('data')
|
||||
let data = await AsyncStorage.getItem('data');
|
||||
if (data !== null) {
|
||||
data = JSON.parse(data)
|
||||
if (!data.wallets) return false
|
||||
let wallets = data.wallets
|
||||
data = JSON.parse(data);
|
||||
if (!data.wallets) return false;
|
||||
let wallets = data.wallets;
|
||||
for (let key of wallets) {
|
||||
// deciding which type is wallet and instatiating correct object
|
||||
let tempObj = JSON.parse(key)
|
||||
let unserializedWallet
|
||||
let tempObj = JSON.parse(key);
|
||||
let unserializedWallet;
|
||||
switch (tempObj.type) {
|
||||
case 'segwitBech32':
|
||||
unserializedWallet = SegwitBech32Wallet.fromJson(key)
|
||||
break
|
||||
unserializedWallet = SegwitBech32Wallet.fromJson(key);
|
||||
break;
|
||||
case 'segwitP2SH':
|
||||
unserializedWallet = SegwitP2SHWallet.fromJson(key)
|
||||
break
|
||||
unserializedWallet = SegwitP2SHWallet.fromJson(key);
|
||||
break;
|
||||
case 'legacy':
|
||||
default:
|
||||
unserializedWallet = LegacyWallet.fromJson(key)
|
||||
break
|
||||
unserializedWallet = LegacyWallet.fromJson(key);
|
||||
break;
|
||||
}
|
||||
// done
|
||||
this.wallets.push(unserializedWallet)
|
||||
this.tx_metadata = data.tx_metadata
|
||||
this.wallets.push(unserializedWallet);
|
||||
this.tx_metadata = data.tx_metadata;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -395,44 +489,46 @@ export class AppStorage {
|
||||
*
|
||||
* @param wallet {AbstractWallet}
|
||||
*/
|
||||
deleteWallet (wallet) {
|
||||
let secret = wallet.getSecret()
|
||||
let tempWallets = []
|
||||
deleteWallet(wallet) {
|
||||
let secret = wallet.getSecret();
|
||||
let tempWallets = [];
|
||||
for (let value of this.wallets) {
|
||||
if (value.getSecret() === secret) { // the one we should delete
|
||||
if (value.getSecret() === secret) {
|
||||
// the one we should delete
|
||||
// nop
|
||||
} else { // the one we must keep
|
||||
tempWallets.push(value)
|
||||
} else {
|
||||
// the one we must keep
|
||||
tempWallets.push(value);
|
||||
}
|
||||
}
|
||||
this.wallets = tempWallets
|
||||
this.wallets = tempWallets;
|
||||
}
|
||||
|
||||
saveToDisk () {
|
||||
let walletsToSave = []
|
||||
saveToDisk() {
|
||||
let walletsToSave = [];
|
||||
for (let key of this.wallets) {
|
||||
walletsToSave.push(JSON.stringify(key))
|
||||
walletsToSave.push(JSON.stringify(key));
|
||||
}
|
||||
|
||||
let data = {
|
||||
wallets: walletsToSave,
|
||||
tx_metadata: this.tx_metadata
|
||||
}
|
||||
tx_metadata: this.tx_metadata,
|
||||
};
|
||||
|
||||
return AsyncStorage.setItem('data', JSON.stringify(data))
|
||||
return AsyncStorage.setItem('data', JSON.stringify(data));
|
||||
}
|
||||
|
||||
async fetchWalletBalances () {
|
||||
async fetchWalletBalances() {
|
||||
// console.warn('app - fetchWalletBalances()')
|
||||
for (let wallet of this.wallets) {
|
||||
await wallet.fetchBalance()
|
||||
await wallet.fetchBalance();
|
||||
}
|
||||
}
|
||||
|
||||
async fetchWalletTransactions () {
|
||||
async fetchWalletTransactions() {
|
||||
// console.warn('app - fetchWalletTransactions()')
|
||||
for (let wallet of this.wallets) {
|
||||
await wallet.fetchTransactions()
|
||||
await wallet.fetchTransactions();
|
||||
}
|
||||
}
|
||||
|
||||
@ -440,29 +536,29 @@ export class AppStorage {
|
||||
*
|
||||
* @returns {Array.<AbstractWallet>}
|
||||
*/
|
||||
getWallets () {
|
||||
return this.wallets
|
||||
getWallets() {
|
||||
return this.wallets;
|
||||
}
|
||||
|
||||
getTransactions () {
|
||||
let txs = []
|
||||
getTransactions() {
|
||||
let txs = [];
|
||||
for (let wallet of this.wallets) {
|
||||
txs = txs.concat(wallet.transactions)
|
||||
txs = txs.concat(wallet.transactions);
|
||||
}
|
||||
return txs
|
||||
return txs;
|
||||
}
|
||||
|
||||
saveWallets () {}
|
||||
saveWallets() {}
|
||||
|
||||
listTXs () {}
|
||||
listTXs() {}
|
||||
|
||||
listUnconfirmed () {}
|
||||
listUnconfirmed() {}
|
||||
|
||||
getBalance () {
|
||||
let finalBalance = 0
|
||||
getBalance() {
|
||||
let finalBalance = 0;
|
||||
for (let wal of this.wallets) {
|
||||
finalBalance += wal.balance
|
||||
finalBalance += wal.balance;
|
||||
}
|
||||
return finalBalance
|
||||
return finalBalance;
|
||||
}
|
||||
}
|
||||
|
36
events.js
36
events.js
@ -1,26 +1,34 @@
|
||||
function EV (eventName, arg) {
|
||||
function EV(eventName, arg) {
|
||||
if (Object.values(EV.enum).indexOf(eventName) === -1) {
|
||||
return console.warn('Unregistered event', eventName, 'registered events:', EV.enum)
|
||||
return console.warn(
|
||||
'Unregistered event',
|
||||
eventName,
|
||||
'registered events:',
|
||||
EV.enum,
|
||||
);
|
||||
}
|
||||
EV.callbacks = EV.callbacks || {} // static variable
|
||||
EV.callbacks[eventName] = EV.callbacks[eventName] || []
|
||||
EV.callbacks = EV.callbacks || {}; // static variable
|
||||
EV.callbacks[eventName] = EV.callbacks[eventName] || [];
|
||||
|
||||
if (typeof arg !== 'function') { // then its an argument
|
||||
console.log('got event', eventName, '...')
|
||||
if (typeof arg !== 'function') {
|
||||
// then its an argument
|
||||
console.log('got event', eventName, '...');
|
||||
for (let cc of EV.callbacks[eventName]) {
|
||||
console.log('dispatching event', eventName)
|
||||
cc(arg)
|
||||
console.log('dispatching event', eventName);
|
||||
cc(arg);
|
||||
}
|
||||
} else { // its a callback. subscribe it to event
|
||||
console.log('someone subscribed to', eventName)
|
||||
EV.callbacks[eventName].push(arg)
|
||||
} else {
|
||||
// its a callback. subscribe it to event
|
||||
console.log('someone subscribed to', eventName);
|
||||
EV.callbacks[eventName].push(arg);
|
||||
}
|
||||
}
|
||||
|
||||
EV.enum = {
|
||||
WALLETS_COUNT_CHANGED: 'WALLETS_COUNT_CHANGED',
|
||||
TRANSACTIONS_COUNT_CHANGED: 'TRANSACTIONS_COUNT_CHANGED',
|
||||
CREATE_TRANSACTION_NEW_DESTINATION_ADDRESS: 'CREATE_TRANSACTION_NEW_DESTINATION_ADDRESS'
|
||||
}
|
||||
CREATE_TRANSACTION_NEW_DESTINATION_ADDRESS:
|
||||
'CREATE_TRANSACTION_NEW_DESTINATION_ADDRESS',
|
||||
};
|
||||
|
||||
module.exports = EV
|
||||
module.exports = EV;
|
||||
|
372
package-lock.json
generated
372
package-lock.json
generated
@ -295,6 +295,12 @@
|
||||
"integrity": "sha1-X6rZwsB/YN12dw9xzwJbYqY8/U4=",
|
||||
"dev": true
|
||||
},
|
||||
"abbrev": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
||||
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
|
||||
"dev": true
|
||||
},
|
||||
"absolute-path": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://registry.npmjs.org/absolute-path/-/absolute-path-0.0.0.tgz",
|
||||
@ -2095,6 +2101,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"boolify": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/boolify/-/boolify-1.0.1.tgz",
|
||||
"integrity": "sha1-tcCeF8rNET0Rt7s+04TMASmU2Gs=",
|
||||
"dev": true
|
||||
},
|
||||
"boom": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz",
|
||||
@ -2368,6 +2380,17 @@
|
||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
|
||||
"integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0="
|
||||
},
|
||||
"camelcase-keys": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-4.2.0.tgz",
|
||||
"integrity": "sha1-oqpfsa9oh1glnDLBQUJteJI7m3c=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"camelcase": "4.1.0",
|
||||
"map-obj": "2.0.0",
|
||||
"quick-lru": "1.1.0"
|
||||
}
|
||||
},
|
||||
"capture-stack-trace": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz",
|
||||
@ -2679,6 +2702,15 @@
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz",
|
||||
"integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ=="
|
||||
},
|
||||
"common-tags": {
|
||||
"version": "1.7.2",
|
||||
"resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.7.2.tgz",
|
||||
"integrity": "sha512-joj9ZlUOjCrwdbmiLqafeUSgkUM74NqhLsZtSqDmhKudaIY197zTrb8JMl31fMnCUuxwFT23eC/oWvrZzDLRJQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"babel-runtime": "6.26.0"
|
||||
}
|
||||
},
|
||||
"compare-versions": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.1.0.tgz",
|
||||
@ -3343,6 +3375,12 @@
|
||||
"randombytes": "2.0.6"
|
||||
}
|
||||
},
|
||||
"dlv": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.1.tgz",
|
||||
"integrity": "sha512-b/kUB0D6RgRGG69h5ExsLnUAwfs5Jndfk1pU2ao7/9mVdsxpUBlkFdTkNJThXw1jrLXpUbIIg+h3um5zXi6sFA==",
|
||||
"dev": true
|
||||
},
|
||||
"doctrine": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
|
||||
@ -3702,6 +3740,21 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"eslint-config-prettier": {
|
||||
"version": "2.9.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-2.9.0.tgz",
|
||||
"integrity": "sha512-ag8YEyBXsm3nmOv1Hz991VtNNDMRa+MNy8cY47Pl4bw6iuzqKbJajXdqUpiw13STdLLrznxgm1hj9NhxeOYq0A==",
|
||||
"requires": {
|
||||
"get-stdin": "5.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"get-stdin": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-5.0.1.tgz",
|
||||
"integrity": "sha1-Ei4WFZHiH/TFJTAwVpPyDmOTo5g="
|
||||
}
|
||||
}
|
||||
},
|
||||
"eslint-config-standard": {
|
||||
"version": "11.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-11.0.0.tgz",
|
||||
@ -3791,6 +3844,15 @@
|
||||
"semver": "5.5.0"
|
||||
}
|
||||
},
|
||||
"eslint-plugin-prettier": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-2.6.0.tgz",
|
||||
"integrity": "sha512-floiaI4F7hRkTrFe8V2ItOK97QYrX75DjmdzmVITZoAP6Cn06oEDPQRsO6MlHEP/u2SxI3xQ52Kpjw6j5WGfeQ==",
|
||||
"requires": {
|
||||
"fast-diff": "1.1.2",
|
||||
"jest-docblock": "21.2.0"
|
||||
}
|
||||
},
|
||||
"eslint-plugin-promise": {
|
||||
"version": "3.7.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-3.7.0.tgz",
|
||||
@ -4326,6 +4388,11 @@
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
|
||||
"integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ="
|
||||
},
|
||||
"fast-diff": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.1.2.tgz",
|
||||
"integrity": "sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig=="
|
||||
},
|
||||
"fast-json-stable-stringify": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
|
||||
@ -8105,6 +8172,18 @@
|
||||
"resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz",
|
||||
"integrity": "sha1-dx7Hg540c9nEzeKLGTlMNWL09tM="
|
||||
},
|
||||
"lodash.memoize": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
|
||||
"integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.merge": {
|
||||
"version": "4.6.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.1.tgz",
|
||||
"integrity": "sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ==",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.once": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
|
||||
@ -8161,11 +8240,33 @@
|
||||
"resolved": "https://registry.npmjs.org/lodash.times/-/lodash.times-4.3.2.tgz",
|
||||
"integrity": "sha1-Ph8lZcQxdU1Uq1fy7RdBk5KFyh0="
|
||||
},
|
||||
"lodash.unescape": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.unescape/-/lodash.unescape-4.0.1.tgz",
|
||||
"integrity": "sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.zipobject": {
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/lodash.zipobject/-/lodash.zipobject-4.1.3.tgz",
|
||||
"integrity": "sha1-s5n1q6j/YqdG9peb8gshT5ZNvvg="
|
||||
},
|
||||
"loglevel": {
|
||||
"version": "1.6.1",
|
||||
"resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.1.tgz",
|
||||
"integrity": "sha1-4PyVEztu8nbNyIh82vJKpvFW+Po=",
|
||||
"dev": true
|
||||
},
|
||||
"loglevel-colored-level-prefix": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/loglevel-colored-level-prefix/-/loglevel-colored-level-prefix-1.0.0.tgz",
|
||||
"integrity": "sha1-akAhj9x64V/HbD0PPmdsRlOIYD4=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chalk": "1.1.3",
|
||||
"loglevel": "1.6.1"
|
||||
}
|
||||
},
|
||||
"longest": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz",
|
||||
@ -8255,6 +8356,24 @@
|
||||
"resolved": "https://registry.npmjs.org/macos-release/-/macos-release-1.1.0.tgz",
|
||||
"integrity": "sha512-mmLbumEYMi5nXReB9js3WGsB8UE6cDBWyIO62Z4DNx6GbRhDxHNjA1MlzSpJ2S2KM1wyiPRA0d19uHWYYvMHjA=="
|
||||
},
|
||||
"make-plural": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/make-plural/-/make-plural-4.1.1.tgz",
|
||||
"integrity": "sha512-triaMVDDYiB+OU1Mz6ht74+z0Bb/bzNESeMwRboSprI3GRWbOvfxEnpWI0eDixQtMPrC2C0revd4wmuck5GcoQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "1.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"minimist": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
||||
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"makeerror": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz",
|
||||
@ -8268,6 +8387,12 @@
|
||||
"resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
|
||||
"integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8="
|
||||
},
|
||||
"map-obj": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/map-obj/-/map-obj-2.0.0.tgz",
|
||||
"integrity": "sha1-plzSkIepJZi4eRJXpSPgISIqwfk=",
|
||||
"dev": true
|
||||
},
|
||||
"map-visit": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
|
||||
@ -8391,6 +8516,41 @@
|
||||
"resolved": "https://registry.npmjs.org/merkle-lib/-/merkle-lib-2.0.10.tgz",
|
||||
"integrity": "sha1-grjbrnXieneFOItz+ddyXQ9vMyY="
|
||||
},
|
||||
"messageformat": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/messageformat/-/messageformat-1.1.1.tgz",
|
||||
"integrity": "sha512-Q0uXcDtF5pEZsVSyhzDOGgZZK6ykN79VY9CwU3Nv0gsqx62BjdJW0MT+63UkHQ4exe3HE33ZlxR2/YwoJarRTg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"glob": "7.0.6",
|
||||
"make-plural": "4.1.1",
|
||||
"messageformat-parser": "1.1.0",
|
||||
"nopt": "3.0.6",
|
||||
"reserved-words": "0.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"glob": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz",
|
||||
"integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fs.realpath": "1.0.0",
|
||||
"inflight": "1.0.6",
|
||||
"inherits": "2.0.3",
|
||||
"minimatch": "3.0.4",
|
||||
"once": "1.4.0",
|
||||
"path-is-absolute": "1.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"messageformat-parser": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/messageformat-parser/-/messageformat-parser-1.1.0.tgz",
|
||||
"integrity": "sha512-Hwem6G3MsKDLS1FtBRGIs8T50P1Q00r3srS6QJePCFbad9fq0nYxwf3rnU2BreApRGhmpKMV7oZI06Sy1c9TPA==",
|
||||
"dev": true
|
||||
},
|
||||
"method-override": {
|
||||
"version": "2.3.10",
|
||||
"resolved": "https://registry.npmjs.org/method-override/-/method-override-2.3.10.tgz",
|
||||
@ -8933,6 +9093,15 @@
|
||||
"resolved": "https://registry.npmjs.org/noop-fn/-/noop-fn-1.0.0.tgz",
|
||||
"integrity": "sha1-XzPUfxPSFQ35PgywNmmemC94/78="
|
||||
},
|
||||
"nopt": {
|
||||
"version": "3.0.6",
|
||||
"resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
|
||||
"integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"abbrev": "1.1.1"
|
||||
}
|
||||
},
|
||||
"normalize-package-data": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
|
||||
@ -9727,6 +9896,150 @@
|
||||
"resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz",
|
||||
"integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks="
|
||||
},
|
||||
"prettier": {
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-1.11.1.tgz",
|
||||
"integrity": "sha512-T/KD65Ot0PB97xTrG8afQ46x3oiVhnfGjGESSI9NWYcG92+OUPZKkwHqGWXH2t9jK1crnQjubECW0FuOth+hxw=="
|
||||
},
|
||||
"prettier-eslint": {
|
||||
"version": "8.8.1",
|
||||
"resolved": "https://registry.npmjs.org/prettier-eslint/-/prettier-eslint-8.8.1.tgz",
|
||||
"integrity": "sha512-8YMkJZnA+XVfEW6fPet05jpNmSQbD+Htbh/QyOxQcVf2GIUEZsnGP7ZScaM9Mq2Ra2261eCu60E7/TRIy9coXQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"babel-runtime": "6.26.0",
|
||||
"common-tags": "1.7.2",
|
||||
"dlv": "1.1.1",
|
||||
"eslint": "4.19.0",
|
||||
"indent-string": "3.2.0",
|
||||
"lodash.merge": "4.6.1",
|
||||
"loglevel-colored-level-prefix": "1.0.0",
|
||||
"prettier": "1.11.1",
|
||||
"pretty-format": "22.4.0",
|
||||
"require-relative": "0.8.7",
|
||||
"typescript": "2.7.2",
|
||||
"typescript-eslint-parser": "11.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-regex": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
|
||||
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
|
||||
"dev": true
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "1.9.1"
|
||||
}
|
||||
},
|
||||
"pretty-format": {
|
||||
"version": "22.4.0",
|
||||
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-22.4.0.tgz",
|
||||
"integrity": "sha512-pvCxP2iODIIk9adXlo4S3GRj0BrJiil68kByAa1PrgG97c1tClh9dLMgp3Z6cHFZrclaABt0UH8PIhwHuFLqYA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-regex": "3.0.0",
|
||||
"ansi-styles": "3.2.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"prettier-eslint-cli": {
|
||||
"version": "4.7.1",
|
||||
"resolved": "https://registry.npmjs.org/prettier-eslint-cli/-/prettier-eslint-cli-4.7.1.tgz",
|
||||
"integrity": "sha512-hQbsGaEVz97oBBcKdsJ46khv0kOGkMyWrXzcFOXW6X8UuetZ/j0yDJkNJgUTVc6PVFbbzBXk+qgd5vos9qzXPQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"arrify": "1.0.1",
|
||||
"babel-runtime": "6.26.0",
|
||||
"boolify": "1.0.1",
|
||||
"camelcase-keys": "4.2.0",
|
||||
"chalk": "2.3.0",
|
||||
"common-tags": "1.7.2",
|
||||
"eslint": "4.19.0",
|
||||
"find-up": "2.1.0",
|
||||
"get-stdin": "5.0.1",
|
||||
"glob": "7.1.2",
|
||||
"ignore": "3.3.7",
|
||||
"indent-string": "3.2.0",
|
||||
"lodash.memoize": "4.1.2",
|
||||
"loglevel-colored-level-prefix": "1.0.0",
|
||||
"messageformat": "1.1.1",
|
||||
"prettier-eslint": "8.8.1",
|
||||
"rxjs": "5.5.7",
|
||||
"yargs": "10.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "1.9.1"
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz",
|
||||
"integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "3.2.1",
|
||||
"escape-string-regexp": "1.0.5",
|
||||
"supports-color": "4.5.0"
|
||||
}
|
||||
},
|
||||
"get-stdin": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-5.0.1.tgz",
|
||||
"integrity": "sha1-Ei4WFZHiH/TFJTAwVpPyDmOTo5g=",
|
||||
"dev": true
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz",
|
||||
"integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "2.0.0"
|
||||
}
|
||||
},
|
||||
"yargs": {
|
||||
"version": "10.0.3",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-10.0.3.tgz",
|
||||
"integrity": "sha512-DqBpQ8NAUX4GyPP/ijDGHsJya4tYqLQrjPr95HNsr1YwL3+daCfvBwg7+gIC6IdJhR2kATh3hb61vjzMWEtjdw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cliui": "3.2.0",
|
||||
"decamelize": "1.2.0",
|
||||
"find-up": "2.1.0",
|
||||
"get-caller-file": "1.0.2",
|
||||
"os-locale": "2.1.0",
|
||||
"require-directory": "2.1.1",
|
||||
"require-main-filename": "1.0.1",
|
||||
"set-blocking": "2.0.0",
|
||||
"string-width": "2.1.1",
|
||||
"which-module": "2.0.0",
|
||||
"y18n": "3.2.1",
|
||||
"yargs-parser": "8.1.0"
|
||||
}
|
||||
},
|
||||
"yargs-parser": {
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-8.1.0.tgz",
|
||||
"integrity": "sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"camelcase": "4.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"pretty-format": {
|
||||
"version": "21.2.1",
|
||||
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-21.2.1.tgz",
|
||||
@ -9898,6 +10211,12 @@
|
||||
"resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",
|
||||
"integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM="
|
||||
},
|
||||
"quick-lru": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-1.1.0.tgz",
|
||||
"integrity": "sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g=",
|
||||
"dev": true
|
||||
},
|
||||
"random-bytes": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
|
||||
@ -10716,6 +11035,12 @@
|
||||
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
|
||||
"integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE="
|
||||
},
|
||||
"require-relative": {
|
||||
"version": "0.8.7",
|
||||
"resolved": "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz",
|
||||
"integrity": "sha1-eZlTn8ngR6N5KPoZb44VY9q9Nt4=",
|
||||
"dev": true
|
||||
},
|
||||
"require-uncached": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz",
|
||||
@ -10732,6 +11057,12 @@
|
||||
"integrity": "sha1-APsVrEkYxBnKgrQ/JMeIguZgOaE=",
|
||||
"dev": true
|
||||
},
|
||||
"reserved-words": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/reserved-words/-/reserved-words-0.1.2.tgz",
|
||||
"integrity": "sha1-AKCUD5jNUBrqqsMWQR2a3FKzGrE=",
|
||||
"dev": true
|
||||
},
|
||||
"resolve": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.5.0.tgz",
|
||||
@ -10914,6 +11245,23 @@
|
||||
"rx-lite": "4.0.8"
|
||||
}
|
||||
},
|
||||
"rxjs": {
|
||||
"version": "5.5.7",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.7.tgz",
|
||||
"integrity": "sha512-Hxo2ac8gRQjwjtKgukMIwBRbq5+KAeEV5hXM4obYBOAghev41bDQWgFH4svYiU9UnQ5kNww2LgfyBdevCd2HXA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"symbol-observable": "1.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"symbol-observable": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz",
|
||||
"integrity": "sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
|
||||
@ -13086,6 +13434,30 @@
|
||||
"resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.12.0.tgz",
|
||||
"integrity": "sha512-fvnkvueAOFLhtAqDgIA/wMP21SMwS/NQESFKZuwVrj5m/Ew6eK2S0z0iB++cwtROPWDOhaT6OUfla8UwMw4Adg=="
|
||||
},
|
||||
"typescript": {
|
||||
"version": "2.7.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.7.2.tgz",
|
||||
"integrity": "sha512-p5TCYZDAO0m4G344hD+wx/LATebLWZNkkh2asWUFqSsD2OrDNhbAHuSjobrmsUmdzjJjEeZVU9g1h3O6vpstnw==",
|
||||
"dev": true
|
||||
},
|
||||
"typescript-eslint-parser": {
|
||||
"version": "11.0.0",
|
||||
"resolved": "https://registry.npmjs.org/typescript-eslint-parser/-/typescript-eslint-parser-11.0.0.tgz",
|
||||
"integrity": "sha512-/fBHTBRBSorWQGKWOOjeMPkzd3o8cOPtFjTRwU5JLNGgVtmMa3KDkiw0R2n+H6ovo9y3OX30/5usm6YTqY44PQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lodash.unescape": "4.0.1",
|
||||
"semver": "5.4.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"semver": {
|
||||
"version": "5.4.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz",
|
||||
"integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"ua-parser-js": {
|
||||
"version": "0.7.17",
|
||||
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.17.tgz",
|
||||
|
@ -14,6 +14,7 @@
|
||||
"eslint-plugin-react": "^7.7.0",
|
||||
"eslint-plugin-standard": "^3.0.1",
|
||||
"jest-expo": "^23.0.0",
|
||||
"prettier-eslint-cli": "^4.7.1",
|
||||
"react-native-scripts": "1.8.1",
|
||||
"react-test-renderer": "16.0.0",
|
||||
"rn-nodeify": "^8.3.0",
|
||||
@ -29,7 +30,7 @@
|
||||
"ios": "react-native-scripts ios",
|
||||
"postinstall": "./node_modules/.bin/rn-nodeify --install buffer,events,process,stream,util,inherits,fs,path --hack",
|
||||
"test": "nodejs ./node_modules/.bin/mocha tests/* && node node_modules/jest/bin/jest.js",
|
||||
"lint": "./node_modules/.bin/eslint *.js screen/**/*.js"
|
||||
"lint": "./node_modules/.bin/eslint *.js screen/**/*.js --fix"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "jest-expo"
|
||||
@ -39,11 +40,14 @@
|
||||
"bignumber.js": "^5.0.0",
|
||||
"bitcoinjs-lib": "^3.3.2",
|
||||
"buffer": "^4.9.1",
|
||||
"eslint-config-prettier": "^2.9.0",
|
||||
"eslint-plugin-prettier": "^2.6.0",
|
||||
"expo": "^23.0.6",
|
||||
"frisbee": "^1.6.4",
|
||||
"isaac": "0.0.5",
|
||||
"mocha": "^5.0.4",
|
||||
"node-libs-react-native": "^1.0.1",
|
||||
"prettier": "^1.11.1",
|
||||
"process": "^0.11.10",
|
||||
"prop-types": "^15.6.1",
|
||||
"react": "16.0.0",
|
||||
|
@ -1,18 +1,26 @@
|
||||
let BlueApp = require('../../BlueApp')
|
||||
let BlueApp = require('../../BlueApp');
|
||||
import React, { Component } from 'react';
|
||||
import { ActivityIndicator, View, TextInput } from 'react-native';
|
||||
import { ActivityIndicator, View, TextInput } from 'react-native';
|
||||
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||
import { SafeAreaView, } from 'react-navigation';
|
||||
import { Icon, Card, Header, } from 'react-native-elements'
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
import { Icon, Card, Header } from 'react-native-elements';
|
||||
import QRCode from 'react-native-qrcode';
|
||||
import { List, Button, ListItem } from 'react-native-elements'
|
||||
import { List, Button, ListItem } from 'react-native-elements';
|
||||
import {
|
||||
BlueLoading, BlueSpacing20, BlueList, BlueButton, SafeBlueArea, BlueCard, BlueText, BlueListItem, BlueHeader,
|
||||
BlueFormInput, BlueSpacing
|
||||
} from '../../BlueComponents'
|
||||
BlueLoading,
|
||||
BlueSpacing20,
|
||||
BlueList,
|
||||
BlueButton,
|
||||
SafeBlueArea,
|
||||
BlueCard,
|
||||
BlueText,
|
||||
BlueListItem,
|
||||
BlueHeader,
|
||||
BlueFormInput,
|
||||
BlueSpacing,
|
||||
} from '../../BlueComponents';
|
||||
|
||||
export default class ReceiveDetails extends Component {
|
||||
|
||||
static navigationOptions = {
|
||||
tabBarLabel: 'Receive',
|
||||
tabBarIcon: ({ tintColor, focused }) => (
|
||||
@ -22,62 +30,62 @@ export default class ReceiveDetails extends Component {
|
||||
style={{ color: tintColor }}
|
||||
/>
|
||||
),
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
let address = props.navigation.state.params.address
|
||||
let address = props.navigation.state.params.address;
|
||||
this.state = {
|
||||
isLoading: true,
|
||||
address : address
|
||||
}
|
||||
console.log(JSON.stringify(address))
|
||||
address: address,
|
||||
};
|
||||
console.log(JSON.stringify(address));
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
console.log('wallets/details - componentDidMount')
|
||||
console.log('wallets/details - componentDidMount');
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
const {navigate} = this.props.navigation;
|
||||
const { navigate } = this.props.navigation;
|
||||
|
||||
if (this.state.isLoading) {
|
||||
return (
|
||||
<BlueLoading/>
|
||||
);
|
||||
return <BlueLoading />;
|
||||
}
|
||||
|
||||
return (
|
||||
<SafeBlueArea forceInset={{ horizontal: 'always' }} style={{flex: 1, paddingTop: 20}}>
|
||||
<BlueSpacing/>
|
||||
<BlueCard title={"Share this address with payer"} style={{alignItems: 'center', flex: 1}}>
|
||||
<TextInput style={{marginBottom:20, color:'white'}} editable={true} value={this.state.address} />
|
||||
<SafeBlueArea
|
||||
forceInset={{ horizontal: 'always' }}
|
||||
style={{ flex: 1, paddingTop: 20 }}
|
||||
>
|
||||
<BlueSpacing />
|
||||
<BlueCard
|
||||
title={'Share this address with payer'}
|
||||
style={{ alignItems: 'center', flex: 1 }}
|
||||
>
|
||||
<TextInput
|
||||
style={{ marginBottom: 20, color: 'white' }}
|
||||
editable
|
||||
value={this.state.address}
|
||||
/>
|
||||
<QRCode
|
||||
value={this.state.address}
|
||||
size={312}
|
||||
bgColor='white'
|
||||
fgColor={BlueApp.settings.brandingColor}/>
|
||||
|
||||
bgColor="white"
|
||||
fgColor={BlueApp.settings.brandingColor}
|
||||
/>
|
||||
</BlueCard>
|
||||
|
||||
|
||||
<BlueButton
|
||||
icon={{name: 'arrow-left', type: 'octicon'}}
|
||||
icon={{ name: 'arrow-left', type: 'octicon' }}
|
||||
backgroundColor={BlueApp.settings.buttonBackground}
|
||||
onPress={() =>
|
||||
this.props.navigation.goBack()
|
||||
}
|
||||
onPress={() => this.props.navigation.goBack()}
|
||||
title="Go back"
|
||||
/>
|
||||
|
||||
</SafeBlueArea>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,19 +1,27 @@
|
||||
/** @type {AppStorage} */
|
||||
let BlueApp = require('../../BlueApp')
|
||||
let BlueApp = require('../../BlueApp');
|
||||
import React, { Component } from 'react';
|
||||
import { ActivityIndicator, Text, View } from 'react-native';
|
||||
import { ActivityIndicator, Text, View } from 'react-native';
|
||||
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||
import { SafeAreaView, } from 'react-navigation';
|
||||
import { Icon, Card, Header, } from 'react-native-elements'
|
||||
import { List, ListItem, Button } from 'react-native-elements'
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
import { Icon, Card, Header } from 'react-native-elements';
|
||||
import { List, ListItem, Button } from 'react-native-elements';
|
||||
import {
|
||||
BlueLoading, BlueSpacing20, BlueList, BlueButton, SafeBlueArea, BlueCard, BlueText, BlueListItem, BlueHeader,
|
||||
BlueFormInput, BlueSpacing
|
||||
} from '../../BlueComponents'
|
||||
let EV = require('../../events')
|
||||
BlueLoading,
|
||||
BlueSpacing20,
|
||||
BlueList,
|
||||
BlueButton,
|
||||
SafeBlueArea,
|
||||
BlueCard,
|
||||
BlueText,
|
||||
BlueListItem,
|
||||
BlueHeader,
|
||||
BlueFormInput,
|
||||
BlueSpacing,
|
||||
} from '../../BlueComponents';
|
||||
let EV = require('../../events');
|
||||
|
||||
export default class ReceiveList extends Component {
|
||||
|
||||
static navigationOptions = {
|
||||
tabBarLabel: 'Receive',
|
||||
tabBarIcon: ({ tintColor, focused }) => (
|
||||
@ -23,81 +31,80 @@ export default class ReceiveList extends Component {
|
||||
style={{ color: tintColor }}
|
||||
/>
|
||||
),
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
isLoading: true,
|
||||
}
|
||||
};
|
||||
this.walletsCount = 0;
|
||||
EV(EV.enum.WALLETS_COUNT_CHANGED, () => {
|
||||
return this.componentDidMount()
|
||||
})
|
||||
return this.componentDidMount();
|
||||
});
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
console.log('receive/list - componentDidMount')
|
||||
let list = []
|
||||
console.log('receive/list - componentDidMount');
|
||||
let list = [];
|
||||
|
||||
this.walletsCount = 0;
|
||||
for (let w of BlueApp.getWallets()) {
|
||||
list.push({
|
||||
title: w.getAddress(),
|
||||
subtitle: w.getLabel(),
|
||||
})
|
||||
});
|
||||
this.walletsCount++;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
list: list
|
||||
})
|
||||
list: list,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
const {navigate} = this.props.navigation;
|
||||
const { navigate } = this.props.navigation;
|
||||
|
||||
if (this.state.isLoading) {
|
||||
return (
|
||||
<BlueLoading/>
|
||||
);
|
||||
return <BlueLoading />;
|
||||
}
|
||||
|
||||
return (
|
||||
<SafeBlueArea forceInset={{ horizontal: 'always' }} style={{flex: 1}}>
|
||||
<SafeBlueArea forceInset={{ horizontal: 'always' }} style={{ flex: 1 }}>
|
||||
<BlueHeader
|
||||
backgroundColor={BlueApp.settings.brandingColor}
|
||||
leftComponent={<Icon name='menu' color="#fff" onPress={() => this.props.navigation.navigate('DrawerToggle') }/>}
|
||||
centerComponent={{ text: 'Choose a wallet to receive', style: { color: '#fff', fontSize: 25 }}}
|
||||
leftComponent={
|
||||
<Icon
|
||||
name="menu"
|
||||
color="#fff"
|
||||
onPress={() => this.props.navigation.navigate('DrawerToggle')}
|
||||
/>
|
||||
}
|
||||
centerComponent={{
|
||||
text: 'Choose a wallet to receive',
|
||||
style: { color: '#fff', fontSize: 25 },
|
||||
}}
|
||||
/>
|
||||
|
||||
<BlueCard containerStyle={{padding: 0}}>
|
||||
|
||||
{
|
||||
this.state.list.map((item, i) => (
|
||||
<BlueListItem
|
||||
|
||||
onPress={() =>
|
||||
{
|
||||
navigate('ReceiveDetails', {address: item.title})
|
||||
}
|
||||
}
|
||||
key={i}
|
||||
title={item.title}
|
||||
subtitle={item.subtitle}
|
||||
leftIcon={{name: 'bitcoin', type: 'font-awesome', color: 'white'}}
|
||||
/>
|
||||
))
|
||||
}
|
||||
<BlueCard containerStyle={{ padding: 0 }}>
|
||||
{this.state.list.map((item, i) => (
|
||||
<BlueListItem
|
||||
onPress={() => {
|
||||
navigate('ReceiveDetails', { address: item.title });
|
||||
}}
|
||||
key={i}
|
||||
title={item.title}
|
||||
subtitle={item.subtitle}
|
||||
leftIcon={{
|
||||
name: 'bitcoin',
|
||||
type: 'font-awesome',
|
||||
color: 'white',
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</BlueCard>
|
||||
|
||||
|
||||
</SafeBlueArea>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,21 +1,34 @@
|
||||
/** @type {AppStorage} */
|
||||
let BlueApp = require('../../BlueApp')
|
||||
let BlueApp = require('../../BlueApp');
|
||||
import React, { Component } from 'react';
|
||||
import { ActivityIndicator, TextInput, View } from 'react-native';
|
||||
import { ActivityIndicator, TextInput, View } from 'react-native';
|
||||
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||
import { SafeAreaView, } from 'react-navigation';
|
||||
import { Icon, Card, Header, } from 'react-native-elements'
|
||||
import { List, Button, ListItem } from 'react-native-elements'
|
||||
import { FormLabel, FormInput, Text, FormValidationMessage } from 'react-native-elements'
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
import { Icon, Card, Header } from 'react-native-elements';
|
||||
import { List, Button, ListItem } from 'react-native-elements';
|
||||
import {
|
||||
BlueLoading, BlueSpacing20, BlueList, BlueButton, SafeBlueArea, BlueCard, BlueText, BlueListItem, BlueHeader,
|
||||
BlueFormInput, BlueSpacing
|
||||
} from '../../BlueComponents'
|
||||
let EV = require('../../events')
|
||||
let BigNumber = require('bignumber.js')
|
||||
FormLabel,
|
||||
FormInput,
|
||||
Text,
|
||||
FormValidationMessage,
|
||||
} from 'react-native-elements';
|
||||
import {
|
||||
BlueLoading,
|
||||
BlueSpacing20,
|
||||
BlueList,
|
||||
BlueButton,
|
||||
SafeBlueArea,
|
||||
BlueCard,
|
||||
BlueText,
|
||||
BlueListItem,
|
||||
BlueHeader,
|
||||
BlueFormInput,
|
||||
BlueSpacing,
|
||||
} from '../../BlueComponents';
|
||||
let EV = require('../../events');
|
||||
let BigNumber = require('bignumber.js');
|
||||
|
||||
export default class SendCreate extends Component {
|
||||
|
||||
static navigationOptions = {
|
||||
tabBarIcon: ({ tintColor, focused }) => (
|
||||
<Ionicons
|
||||
@ -24,25 +37,25 @@ export default class SendCreate extends Component {
|
||||
style={{ color: tintColor }}
|
||||
/>
|
||||
),
|
||||
}
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
console.log('send/create constructor')
|
||||
console.log('send/create constructor');
|
||||
this.state = {
|
||||
isLoading : true,
|
||||
isLoading: true,
|
||||
amount: props.navigation.state.params.amount,
|
||||
fee: props.navigation.state.params.fee,
|
||||
address: props.navigation.state.params.address,
|
||||
memo: props.navigation.state.params.memo,
|
||||
fromAddress: props.navigation.state.params.fromAddress,
|
||||
broadcastErrorMessage : '',
|
||||
}
|
||||
broadcastErrorMessage: '',
|
||||
};
|
||||
|
||||
let fromWallet = false
|
||||
let fromWallet = false;
|
||||
for (let w of BlueApp.getWallets()) {
|
||||
if (w.getAddress() === this.state.fromAddress) {
|
||||
fromWallet = w
|
||||
fromWallet = w;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -50,85 +63,101 @@ export default class SendCreate extends Component {
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
console.log('send/create - componentDidMount')
|
||||
console.log('address = ', this.state.address)
|
||||
console.log('send/create - componentDidMount');
|
||||
console.log('address = ', this.state.address);
|
||||
|
||||
let utxo
|
||||
let satoshiPerByte
|
||||
let tx
|
||||
let utxo;
|
||||
let satoshiPerByte;
|
||||
let tx;
|
||||
|
||||
try {
|
||||
await this.state.fromWallet.fetchUtxo()
|
||||
utxo = this.state.fromWallet.utxo
|
||||
let startTime = Date.now()
|
||||
try {
|
||||
await this.state.fromWallet.fetchUtxo();
|
||||
utxo = this.state.fromWallet.utxo;
|
||||
let startTime = Date.now();
|
||||
|
||||
tx = this.state.fromWallet.createTx(utxo, this.state.amount, this.state.fee, this.state.address, this.state.memo)
|
||||
let endTime = Date.now()
|
||||
console.log('create tx ', (endTime-startTime) / 1000, 'sec')
|
||||
tx = this.state.fromWallet.createTx(
|
||||
utxo,
|
||||
this.state.amount,
|
||||
this.state.fee,
|
||||
this.state.address,
|
||||
this.state.memo,
|
||||
);
|
||||
let endTime = Date.now();
|
||||
console.log('create tx ', (endTime - startTime) / 1000, 'sec');
|
||||
|
||||
let bitcoin = require('bitcoinjs-lib');
|
||||
let txDecoded = bitcoin.Transaction.fromHex(tx);
|
||||
let txid = txDecoded.getId();
|
||||
console.log('txid', txid);
|
||||
console.log('txhex', tx);
|
||||
let bitcoin = require('bitcoinjs-lib');
|
||||
let txDecoded = bitcoin.Transaction.fromHex(tx);
|
||||
let txid = txDecoded.getId();
|
||||
console.log('txid', txid);
|
||||
console.log('txhex', tx);
|
||||
|
||||
BlueApp.tx_metadata = BlueApp.tx_metadata || {}
|
||||
BlueApp.tx_metadata[txid] = {
|
||||
'txhex' : tx,
|
||||
'memo': this.state.memo,
|
||||
}
|
||||
BlueApp.saveToDisk()
|
||||
|
||||
let feeSatoshi = new BigNumber(this.state.fee)
|
||||
feeSatoshi = feeSatoshi.mul(100000000)
|
||||
satoshiPerByte = feeSatoshi.div( Math.round(tx.length/2) )
|
||||
satoshiPerByte = Math.round(satoshiPerByte.toString(10))
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
return this.setState({
|
||||
isError: true,
|
||||
errorMessage: JSON.stringify(err.message)
|
||||
})
|
||||
}
|
||||
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
size: Math.round(tx.length/2),
|
||||
tx,
|
||||
satoshiPerByte,
|
||||
})
|
||||
BlueApp.tx_metadata = BlueApp.tx_metadata || {};
|
||||
BlueApp.tx_metadata[txid] = {
|
||||
txhex: tx,
|
||||
memo: this.state.memo,
|
||||
};
|
||||
BlueApp.saveToDisk();
|
||||
|
||||
let feeSatoshi = new BigNumber(this.state.fee);
|
||||
feeSatoshi = feeSatoshi.mul(100000000);
|
||||
satoshiPerByte = feeSatoshi.div(Math.round(tx.length / 2));
|
||||
satoshiPerByte = Math.round(satoshiPerByte.toString(10));
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
return this.setState({
|
||||
isError: true,
|
||||
errorMessage: JSON.stringify(err.message),
|
||||
});
|
||||
}
|
||||
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
size: Math.round(tx.length / 2),
|
||||
tx,
|
||||
satoshiPerByte,
|
||||
});
|
||||
}
|
||||
|
||||
async broadcast() {
|
||||
let result = await this.state.fromWallet.broadcastTx(this.state.tx)
|
||||
console.log('broadcast result = ', result)
|
||||
let result = await this.state.fromWallet.broadcastTx(this.state.tx);
|
||||
console.log('broadcast result = ', result);
|
||||
if (typeof result === 'string') {
|
||||
result = JSON.parse(result)
|
||||
result = JSON.parse(result);
|
||||
}
|
||||
if ((result && result.error)) {
|
||||
this.setState({broadcastErrorMessage : JSON.stringify(result.error), broadcastSuccessMessage : ''})
|
||||
if (result && result.error) {
|
||||
this.setState({
|
||||
broadcastErrorMessage: JSON.stringify(result.error),
|
||||
broadcastSuccessMessage: '',
|
||||
});
|
||||
} else {
|
||||
this.setState({broadcastErrorMessage : ''})
|
||||
this.setState({broadcastSuccessMessage : "Success! TXID: " + JSON.stringify(result.result)})
|
||||
this.setState({ broadcastErrorMessage: '' });
|
||||
this.setState({
|
||||
broadcastSuccessMessage:
|
||||
'Success! TXID: ' + JSON.stringify(result.result),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
const {navigate} = this.props.navigation;
|
||||
const { navigate } = this.props.navigation;
|
||||
|
||||
if (this.state.isError) {
|
||||
return (
|
||||
<SafeBlueArea style={{flex: 1, paddingTop: 20}}>
|
||||
<BlueSpacing/>
|
||||
<BlueCard title={"Create Transaction"} style={{alignItems: 'center', flex: 1}}>
|
||||
<BlueText>Error creating transaction. Invalid address or send amount?</BlueText>
|
||||
<FormValidationMessage>{this.state.errorMessage}</FormValidationMessage>
|
||||
<SafeBlueArea style={{ flex: 1, paddingTop: 20 }}>
|
||||
<BlueSpacing />
|
||||
<BlueCard
|
||||
title={'Create Transaction'}
|
||||
style={{ alignItems: 'center', flex: 1 }}
|
||||
>
|
||||
<BlueText>
|
||||
Error creating transaction. Invalid address or send amount?
|
||||
</BlueText>
|
||||
<FormValidationMessage>
|
||||
{this.state.errorMessage}
|
||||
</FormValidationMessage>
|
||||
</BlueCard>
|
||||
<BlueButton
|
||||
onPress={() =>this.props.navigation.goBack()}
|
||||
onPress={() => this.props.navigation.goBack()}
|
||||
title="Go back"
|
||||
/>
|
||||
</SafeBlueArea>
|
||||
@ -136,68 +165,65 @@ export default class SendCreate extends Component {
|
||||
}
|
||||
|
||||
if (this.state.isLoading) {
|
||||
return (
|
||||
<BlueLoading/>
|
||||
);
|
||||
return <BlueLoading />;
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<SafeBlueArea style={{flex: 1, paddingTop: 20}}>
|
||||
<BlueSpacing/>
|
||||
<BlueCard title={"Create Transaction"} style={{alignItems: 'center', flex: 1}}>
|
||||
|
||||
<BlueText>This is transaction hex, signed and ready to be broadcast to the network. Continue?</BlueText>
|
||||
<SafeBlueArea style={{ flex: 1, paddingTop: 20 }}>
|
||||
<BlueSpacing />
|
||||
<BlueCard
|
||||
title={'Create Transaction'}
|
||||
style={{ alignItems: 'center', flex: 1 }}
|
||||
>
|
||||
<BlueText>
|
||||
This is transaction hex, signed and ready to be broadcast to the
|
||||
network. Continue?
|
||||
</BlueText>
|
||||
|
||||
<TextInput
|
||||
style={{borderColor: '#ebebeb', borderWidth: 1, marginTop:20, color:'#ebebeb'}}
|
||||
style={{
|
||||
borderColor: '#ebebeb',
|
||||
borderWidth: 1,
|
||||
marginTop: 20,
|
||||
color: '#ebebeb',
|
||||
}}
|
||||
maxHeight={70}
|
||||
multiline={true}
|
||||
multiline
|
||||
editable={false}
|
||||
value={this.state.tx}
|
||||
/>
|
||||
|
||||
<BlueSpacing20/>
|
||||
<BlueSpacing20 />
|
||||
|
||||
<BlueText style={{paddingTop:20}} >To: {this.state.address}</BlueText>
|
||||
<BlueText style={{ paddingTop: 20 }}>
|
||||
To: {this.state.address}
|
||||
</BlueText>
|
||||
<BlueText>Amount: {this.state.amount} BTC</BlueText>
|
||||
<BlueText>Fee: {this.state.fee} BTC</BlueText>
|
||||
<BlueText >TX size: {this.state.size} Bytes</BlueText>
|
||||
<BlueText>TX size: {this.state.size} Bytes</BlueText>
|
||||
<BlueText>satoshiPerByte: {this.state.satoshiPerByte} Sat/B</BlueText>
|
||||
<BlueText>Memo: {this.state.memo}</BlueText>
|
||||
|
||||
|
||||
|
||||
|
||||
</BlueCard>
|
||||
|
||||
|
||||
|
||||
|
||||
<BlueButton
|
||||
icon={{name: 'megaphone', type: 'octicon'}}
|
||||
onPress={() =>
|
||||
this.broadcast()
|
||||
}
|
||||
icon={{ name: 'megaphone', type: 'octicon' }}
|
||||
onPress={() => this.broadcast()}
|
||||
title="Broadcast"
|
||||
/>
|
||||
|
||||
|
||||
<BlueButton
|
||||
icon={{name: 'arrow-left', type: 'octicon'}}
|
||||
onPress={() =>
|
||||
this.props.navigation.goBack()
|
||||
}
|
||||
icon={{ name: 'arrow-left', type: 'octicon' }}
|
||||
onPress={() => this.props.navigation.goBack()}
|
||||
title="Go back"
|
||||
/>
|
||||
|
||||
<FormValidationMessage>{this.state.broadcastErrorMessage}</FormValidationMessage>
|
||||
<Text style={{padding:20, color:"#090"}}>{this.state.broadcastSuccessMessage}</Text>
|
||||
|
||||
|
||||
<FormValidationMessage>
|
||||
{this.state.broadcastErrorMessage}
|
||||
</FormValidationMessage>
|
||||
<Text style={{ padding: 20, color: '#090' }}>
|
||||
{this.state.broadcastSuccessMessage}
|
||||
</Text>
|
||||
</SafeBlueArea>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,20 +1,32 @@
|
||||
let BlueApp = require('../../BlueApp')
|
||||
let BlueApp = require('../../BlueApp');
|
||||
import React, { Component } from 'react';
|
||||
import { ActivityIndicator, TextInput, View } from 'react-native';
|
||||
import { ActivityIndicator, TextInput, View } from 'react-native';
|
||||
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||
import { SafeAreaView, } from 'react-navigation';
|
||||
import { Icon, Card, Header, } from 'react-native-elements'
|
||||
import { List, Button, ListItem } from 'react-native-elements'
|
||||
import { FormLabel, FormInput, Text, FormValidationMessage } from 'react-native-elements'
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
import { Icon, Card, Header } from 'react-native-elements';
|
||||
import { List, Button, ListItem } from 'react-native-elements';
|
||||
import {
|
||||
BlueSpacing20, BlueList, BlueButton, SafeBlueArea, BlueCard, BlueText, BlueListItem, BlueHeader,
|
||||
BlueFormInput, BlueSpacing
|
||||
} from '../../BlueComponents'
|
||||
let EV = require('../../events')
|
||||
FormLabel,
|
||||
FormInput,
|
||||
Text,
|
||||
FormValidationMessage,
|
||||
} from 'react-native-elements';
|
||||
import {
|
||||
BlueSpacing20,
|
||||
BlueList,
|
||||
BlueButton,
|
||||
SafeBlueArea,
|
||||
BlueCard,
|
||||
BlueText,
|
||||
BlueListItem,
|
||||
BlueHeader,
|
||||
BlueFormInput,
|
||||
BlueSpacing,
|
||||
} from '../../BlueComponents';
|
||||
let EV = require('../../events');
|
||||
let BigNumber = require('bignumber.js');
|
||||
|
||||
export default class SendDetails extends Component {
|
||||
|
||||
static navigationOptions = {
|
||||
tabBarIcon: ({ tintColor, focused }) => (
|
||||
<Ionicons
|
||||
@ -23,121 +35,119 @@ export default class SendDetails extends Component {
|
||||
style={{ color: tintColor }}
|
||||
/>
|
||||
),
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
let startTime = Date.now()
|
||||
let address
|
||||
if (props.navigation.state.params) address = props.navigation.state.params.address
|
||||
let fromAddress
|
||||
if (props.navigation.state.params) fromAddress = props.navigation.state.params.fromAddress
|
||||
let fromWallet = {}
|
||||
let startTime = Date.now();
|
||||
let address;
|
||||
if (props.navigation.state.params)
|
||||
address = props.navigation.state.params.address;
|
||||
let fromAddress;
|
||||
if (props.navigation.state.params)
|
||||
fromAddress = props.navigation.state.params.fromAddress;
|
||||
let fromWallet = {};
|
||||
|
||||
let startTime2 = Date.now()
|
||||
let startTime2 = Date.now();
|
||||
for (let w of BlueApp.getWallets()) {
|
||||
if (w.getAddress() === fromAddress) {
|
||||
fromWallet = w
|
||||
fromWallet = w;
|
||||
}
|
||||
}
|
||||
|
||||
let endTime2 = Date.now()
|
||||
console.log('getAddress() took', (endTime2-startTime2)/1000, 'sec')
|
||||
let endTime2 = Date.now();
|
||||
console.log('getAddress() took', (endTime2 - startTime2) / 1000, 'sec');
|
||||
|
||||
this.state = {
|
||||
errorMessage: false,
|
||||
fromAddress: fromAddress,
|
||||
fromWallet: fromWallet,
|
||||
isLoading: true,
|
||||
address : address,
|
||||
address: address,
|
||||
amount: '',
|
||||
fee: '',
|
||||
}
|
||||
};
|
||||
|
||||
EV(EV.enum.CREATE_TRANSACTION_NEW_DESTINATION_ADDRESS, (data) => {
|
||||
console.log('received event with ', data)
|
||||
EV(EV.enum.CREATE_TRANSACTION_NEW_DESTINATION_ADDRESS, data => {
|
||||
console.log('received event with ', data);
|
||||
this.setState({
|
||||
address: data
|
||||
})
|
||||
})
|
||||
let endTime = Date.now()
|
||||
console.log('constructor took', (endTime-startTime)/1000, 'sec')
|
||||
address: data,
|
||||
});
|
||||
});
|
||||
let endTime = Date.now();
|
||||
console.log('constructor took', (endTime - startTime) / 1000, 'sec');
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
let startTime = Date.now()
|
||||
console.log('send/details - componentDidMount')
|
||||
let startTime = Date.now();
|
||||
console.log('send/details - componentDidMount');
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
})
|
||||
let endTime = Date.now()
|
||||
console.log('componentDidMount took', (endTime-startTime)/1000, 'sec')
|
||||
});
|
||||
let endTime = Date.now();
|
||||
console.log('componentDidMount took', (endTime - startTime) / 1000, 'sec');
|
||||
}
|
||||
|
||||
recalculateAvailableBalance(balance, amount, fee) {
|
||||
if (!amount) amount = 0
|
||||
if (!fee) fee = 0
|
||||
let availableBalance
|
||||
if (!amount) amount = 0;
|
||||
if (!fee) fee = 0;
|
||||
let availableBalance;
|
||||
try {
|
||||
availableBalance = new BigNumber(balance)
|
||||
availableBalance = availableBalance.sub(amount)
|
||||
availableBalance = availableBalance.sub(fee)
|
||||
availableBalance = availableBalance.toString(10)
|
||||
availableBalance = new BigNumber(balance);
|
||||
availableBalance = availableBalance.sub(amount);
|
||||
availableBalance = availableBalance.sub(fee);
|
||||
availableBalance = availableBalance.toString(10);
|
||||
} catch (err) {
|
||||
return balance
|
||||
return balance;
|
||||
}
|
||||
console.log(typeof availableBalance, availableBalance)
|
||||
return availableBalance === 'NaN' && balance || availableBalance
|
||||
console.log(typeof availableBalance, availableBalance);
|
||||
return (availableBalance === 'NaN' && balance) || availableBalance;
|
||||
}
|
||||
|
||||
|
||||
createTransaction() {
|
||||
|
||||
if (!this.state.amount) {
|
||||
this.setState({
|
||||
errorMessage: 'Amount field is not valid'
|
||||
})
|
||||
errorMessage: 'Amount field is not valid',
|
||||
});
|
||||
console.log('validation error');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.state.fee) {
|
||||
this.setState({
|
||||
errorMessage: 'Fee field is not valid'
|
||||
})
|
||||
errorMessage: 'Fee field is not valid',
|
||||
});
|
||||
console.log('validation error');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.state.address) {
|
||||
this.setState({
|
||||
errorMessage: 'Address field is not valid'
|
||||
})
|
||||
errorMessage: 'Address field is not valid',
|
||||
});
|
||||
console.log('validation error');
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
errorMessage: ''
|
||||
})
|
||||
errorMessage: '',
|
||||
});
|
||||
|
||||
this.props.navigation.navigate('CreateTransaction', {
|
||||
amount : this.state.amount,
|
||||
amount: this.state.amount,
|
||||
fee: this.state.fee,
|
||||
address: this.state.address,
|
||||
memo: this.state.memo,
|
||||
fromAddress: this.state.fromAddress
|
||||
})
|
||||
fromAddress: this.state.fromAddress,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
const {navigate} = this.props.navigation;
|
||||
const { navigate } = this.props.navigation;
|
||||
|
||||
if (this.state.isLoading) {
|
||||
return (
|
||||
<View style={{flex: 1, paddingTop: 20}}>
|
||||
<View style={{ flex: 1, paddingTop: 20 }}>
|
||||
<ActivityIndicator />
|
||||
</View>
|
||||
);
|
||||
@ -145,80 +155,85 @@ export default class SendDetails extends Component {
|
||||
|
||||
if (!this.state.fromWallet.getAddress) {
|
||||
return (
|
||||
<View style={{flex: 1, paddingTop: 20}}>
|
||||
<Text>System error: Source wallet not found (this should never happen)</Text>
|
||||
<View style={{ flex: 1, paddingTop: 20 }}>
|
||||
<Text>
|
||||
System error: Source wallet not found (this should never happen)
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<SafeBlueArea style={{flex: 1, paddingTop: 20}}>
|
||||
<BlueSpacing/>
|
||||
<BlueCard title={"Create Transaction"} style={{alignItems: 'center', flex: 1}}>
|
||||
|
||||
<BlueFormInput style={{width: 250}}
|
||||
onChangeText={(text) => this.setState({address: text})}
|
||||
placeholder={"receiver address here"}
|
||||
value={this.state.address}
|
||||
<SafeBlueArea style={{ flex: 1, paddingTop: 20 }}>
|
||||
<BlueSpacing />
|
||||
<BlueCard
|
||||
title={'Create Transaction'}
|
||||
style={{ alignItems: 'center', flex: 1 }}
|
||||
>
|
||||
<BlueFormInput
|
||||
style={{ width: 250 }}
|
||||
onChangeText={text => this.setState({ address: text })}
|
||||
placeholder={'receiver address here'}
|
||||
value={this.state.address}
|
||||
/>
|
||||
|
||||
|
||||
<BlueFormInput onChangeText={(text) => this.setState({amount: text})} keyboardType={"numeric"}
|
||||
placeholder={"amount to send (in BTC)"}
|
||||
value={this.state.amount+''}
|
||||
<BlueFormInput
|
||||
onChangeText={text => this.setState({ amount: text })}
|
||||
keyboardType={'numeric'}
|
||||
placeholder={'amount to send (in BTC)'}
|
||||
value={this.state.amount + ''}
|
||||
/>
|
||||
|
||||
|
||||
|
||||
<BlueFormInput onChangeText={(text) => this.setState({fee: text})} keyboardType={"numeric"}
|
||||
placeholder={"plus transaction fee (in BTC)"}
|
||||
value={this.state.fee + ''}
|
||||
<BlueFormInput
|
||||
onChangeText={text => this.setState({ fee: text })}
|
||||
keyboardType={'numeric'}
|
||||
placeholder={'plus transaction fee (in BTC)'}
|
||||
value={this.state.fee + ''}
|
||||
/>
|
||||
|
||||
<BlueFormInput onChangeText={(text) => this.setState({memo: text})}
|
||||
placeholder={"memo to self"}
|
||||
value={this.state.memo}
|
||||
<BlueFormInput
|
||||
onChangeText={text => this.setState({ memo: text })}
|
||||
placeholder={'memo to self'}
|
||||
value={this.state.memo}
|
||||
/>
|
||||
|
||||
<BlueSpacing20/>
|
||||
<BlueText>Remaining balance: {this.recalculateAvailableBalance(this.state.fromWallet.getBalance(), this.state.amount, this.state.fee)} BTC</BlueText>
|
||||
|
||||
|
||||
|
||||
<BlueSpacing20 />
|
||||
<BlueText>
|
||||
Remaining balance:{' '}
|
||||
{this.recalculateAvailableBalance(
|
||||
this.state.fromWallet.getBalance(),
|
||||
this.state.amount,
|
||||
this.state.fee,
|
||||
)}{' '}
|
||||
BTC
|
||||
</BlueText>
|
||||
</BlueCard>
|
||||
|
||||
<FormValidationMessage>{this.state.errorMessage}</FormValidationMessage>
|
||||
|
||||
<View style={{flex: 1, flexDirection: 'row', paddingTop:20,}}>
|
||||
<View style={{flex: 0.33}}>
|
||||
<View style={{ flex: 1, flexDirection: 'row', paddingTop: 20 }}>
|
||||
<View style={{ flex: 0.33 }}>
|
||||
<BlueButton
|
||||
onPress={() =>
|
||||
this.props.navigation.goBack()
|
||||
}
|
||||
onPress={() => this.props.navigation.goBack()}
|
||||
title="Cancel"
|
||||
/>
|
||||
</View>
|
||||
<View style={{flex: 0.33}}>
|
||||
<BlueButton icon={{name: 'qrcode', type: 'font-awesome'}} style={{}}
|
||||
title="scan"
|
||||
onPress={() => this.props.navigation.navigate('ScanQrAddress')}
|
||||
<View style={{ flex: 0.33 }}>
|
||||
<BlueButton
|
||||
icon={{ name: 'qrcode', type: 'font-awesome' }}
|
||||
style={{}}
|
||||
title="scan"
|
||||
onPress={() => this.props.navigation.navigate('ScanQrAddress')}
|
||||
/>
|
||||
</View>
|
||||
<View style={{flex: 0.33}}>
|
||||
<View style={{ flex: 0.33 }}>
|
||||
<BlueButton
|
||||
onPress={() =>
|
||||
this.createTransaction()
|
||||
}
|
||||
onPress={() => this.createTransaction()}
|
||||
title="Create"
|
||||
/>
|
||||
</View>
|
||||
|
||||
</View>
|
||||
|
||||
|
||||
</SafeBlueArea>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,16 +1,23 @@
|
||||
/** @type {AppStorage} */
|
||||
let BlueApp = require('../../BlueApp')
|
||||
let BlueApp = require('../../BlueApp');
|
||||
import React, { Component } from 'react';
|
||||
import { ActivityIndicator, Text, View } from 'react-native';
|
||||
import { ActivityIndicator, Text, View } from 'react-native';
|
||||
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||
import { SafeAreaView, } from 'react-navigation';
|
||||
import { Icon, Card, Header, } from 'react-native-elements'
|
||||
import { List, ListItem, Button } from 'react-native-elements'
|
||||
import { BlueList, BlueButton, SafeBlueArea, BlueCard, BlueText, BlueListItem, BlueHeader } from '../../BlueComponents'
|
||||
let EV = require('../../events')
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
import { Icon, Card, Header } from 'react-native-elements';
|
||||
import { List, ListItem, Button } from 'react-native-elements';
|
||||
import {
|
||||
BlueList,
|
||||
BlueButton,
|
||||
SafeBlueArea,
|
||||
BlueCard,
|
||||
BlueText,
|
||||
BlueListItem,
|
||||
BlueHeader,
|
||||
} from '../../BlueComponents';
|
||||
let EV = require('../../events');
|
||||
|
||||
export default class SendList extends Component {
|
||||
|
||||
static navigationOptions = {
|
||||
tabBarLabel: 'Send',
|
||||
tabBarIcon: ({ tintColor, focused }) => (
|
||||
@ -20,83 +27,83 @@ export default class SendList extends Component {
|
||||
style={{ color: tintColor }}
|
||||
/>
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
isLoading: true,
|
||||
}
|
||||
};
|
||||
this.walletsCount = 0;
|
||||
EV(EV.enum.WALLETS_COUNT_CHANGED, () => {
|
||||
return this.componentDidMount()
|
||||
})
|
||||
return this.componentDidMount();
|
||||
});
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
console.log('receive/list - componentDidMount')
|
||||
let list = []
|
||||
console.log('receive/list - componentDidMount');
|
||||
let list = [];
|
||||
|
||||
this.walletsCount = 0;
|
||||
for (let w of BlueApp.getWallets()) {
|
||||
list.push({
|
||||
title: w.getAddress(),
|
||||
subtitle: w.getLabel(),
|
||||
})
|
||||
});
|
||||
this.walletsCount++;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
list: list
|
||||
})
|
||||
list: list,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
const {navigate} = this.props.navigation;
|
||||
const { navigate } = this.props.navigation;
|
||||
|
||||
if (this.state.isLoading) {
|
||||
return (
|
||||
<View style={{flex: 1, paddingTop: 20}}>
|
||||
<View style={{ flex: 1, paddingTop: 20 }}>
|
||||
<ActivityIndicator />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<SafeBlueArea forceInset={{ horizontal: 'always' }} style={{flex: 1}}>
|
||||
<SafeBlueArea forceInset={{ horizontal: 'always' }} style={{ flex: 1 }}>
|
||||
<BlueHeader
|
||||
leftComponent={<Icon name='menu' color="#fff" onPress={() => this.props.navigation.navigate('DrawerToggle') }/>}
|
||||
centerComponent={{ text: 'Choose a wallet to send from', style: { color: '#fff', fontSize: 25 }}}
|
||||
leftComponent={
|
||||
<Icon
|
||||
name="menu"
|
||||
color="#fff"
|
||||
onPress={() => this.props.navigation.navigate('DrawerToggle')}
|
||||
/>
|
||||
}
|
||||
centerComponent={{
|
||||
text: 'Choose a wallet to send from',
|
||||
style: { color: '#fff', fontSize: 25 },
|
||||
}}
|
||||
/>
|
||||
|
||||
<BlueCard containerStyle={{padding: 0}}>
|
||||
|
||||
{
|
||||
this.state.list.map((item, i) => (
|
||||
<BlueListItem
|
||||
|
||||
onPress={() =>
|
||||
{
|
||||
navigate('SendDetails', {fromAddress: item.title})
|
||||
}
|
||||
}
|
||||
key={i}
|
||||
title={item.title}
|
||||
subtitle={item.subtitle}
|
||||
leftIcon={{name: 'bitcoin', type: 'font-awesome', color: 'white'}}
|
||||
/>
|
||||
))
|
||||
}
|
||||
<BlueCard containerStyle={{ padding: 0 }}>
|
||||
{this.state.list.map((item, i) => (
|
||||
<BlueListItem
|
||||
onPress={() => {
|
||||
navigate('SendDetails', { fromAddress: item.title });
|
||||
}}
|
||||
key={i}
|
||||
title={item.title}
|
||||
subtitle={item.subtitle}
|
||||
leftIcon={{
|
||||
name: 'bitcoin',
|
||||
type: 'font-awesome',
|
||||
color: 'white',
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</BlueCard>
|
||||
|
||||
|
||||
</SafeBlueArea>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,38 +1,41 @@
|
||||
let BlueApp = require('../../BlueApp')
|
||||
let BlueApp = require('../../BlueApp');
|
||||
import React from 'react';
|
||||
import { Text, ActivityIndicator, Button, View, TouchableOpacity } from 'react-native';
|
||||
import {
|
||||
Text,
|
||||
ActivityIndicator,
|
||||
Button,
|
||||
View,
|
||||
TouchableOpacity,
|
||||
} from 'react-native';
|
||||
import { Camera, Permissions } from 'expo';
|
||||
import { AppStorage, LegacyWallet } from '../../class'
|
||||
import { AppStorage, LegacyWallet } from '../../class';
|
||||
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||
let EV = require('../../events')
|
||||
let EV = require('../../events');
|
||||
|
||||
export default class CameraExample extends React.Component {
|
||||
|
||||
|
||||
state = {
|
||||
isLoading : false,
|
||||
isLoading: false,
|
||||
hasCameraPermission: null,
|
||||
type: Camera.Constants.Type.back,
|
||||
};
|
||||
|
||||
async onBarCodeRead (ret) {
|
||||
async onBarCodeRead(ret) {
|
||||
if (this.ignoreRead) return;
|
||||
this.ignoreRead = true;
|
||||
let that = this
|
||||
setTimeout(()=>{
|
||||
let that = this;
|
||||
setTimeout(() => {
|
||||
that.ignoreRead = false;
|
||||
}, 2000)
|
||||
|
||||
this.props.navigation.goBack()
|
||||
EV(EV.enum.CREATE_TRANSACTION_NEW_DESTINATION_ADDRESS, ret.data)
|
||||
}, 2000);
|
||||
|
||||
this.props.navigation.goBack();
|
||||
EV(EV.enum.CREATE_TRANSACTION_NEW_DESTINATION_ADDRESS, ret.data);
|
||||
} // end
|
||||
|
||||
async componentWillMount() {
|
||||
const { status } = await Permissions.askAsync(Permissions.CAMERA);
|
||||
this.setState({
|
||||
hasCameraPermission: status === 'granted',
|
||||
onCameraReady: function () {
|
||||
onCameraReady: function() {
|
||||
alert('onCameraReady');
|
||||
},
|
||||
barCodeTypes: [Camera.Constants.BarCodeType.qr],
|
||||
@ -40,10 +43,9 @@ export default class CameraExample extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
if (this.state.isLoading) {
|
||||
return (
|
||||
<View style={{flex: 1, paddingTop: 20}}>
|
||||
<View style={{ flex: 1, paddingTop: 20 }}>
|
||||
<ActivityIndicator />
|
||||
</View>
|
||||
);
|
||||
@ -57,14 +59,18 @@ export default class CameraExample extends React.Component {
|
||||
} else {
|
||||
return (
|
||||
<View style={{ flex: 1 }}>
|
||||
<Camera style={{ flex: 1 }} type={this.state.type}
|
||||
onBarCodeRead={this.onBarCodeRead.bind(this)}>
|
||||
<Camera
|
||||
style={{ flex: 1 }}
|
||||
type={this.state.type}
|
||||
onBarCodeRead={this.onBarCodeRead.bind(this)}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
backgroundColor: 'transparent',
|
||||
flexDirection: 'row',
|
||||
}}>
|
||||
}}
|
||||
>
|
||||
<TouchableOpacity
|
||||
style={{
|
||||
flex: 0.2,
|
||||
@ -73,17 +79,17 @@ export default class CameraExample extends React.Component {
|
||||
}}
|
||||
onPress={() => {
|
||||
this.setState({
|
||||
type: this.state.type === Camera.Constants.Type.back
|
||||
? Camera.Constants.Type.front
|
||||
: Camera.Constants.Type.back,
|
||||
type:
|
||||
this.state.type === Camera.Constants.Type.back
|
||||
? Camera.Constants.Type.front
|
||||
: Camera.Constants.Type.back,
|
||||
});
|
||||
}}>
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
style={{ fontSize: 18, marginBottom: 10 }}
|
||||
title='Go back'
|
||||
onPress={() =>
|
||||
this.props.navigation.goBack()
|
||||
}
|
||||
title="Go back"
|
||||
onPress={() => this.props.navigation.goBack()}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
@ -92,4 +98,4 @@ export default class CameraExample extends React.Component {
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +1,35 @@
|
||||
/** @type {AppStorage} */
|
||||
let BlueApp = require('../../BlueApp')
|
||||
let BlueApp = require('../../BlueApp');
|
||||
import React, { Component } from 'react';
|
||||
import { ActivityIndicator, TextInput, View } from 'react-native';
|
||||
import { ActivityIndicator, TextInput, View } from 'react-native';
|
||||
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||
import { SafeAreaView, } from 'react-navigation';
|
||||
import { Icon, Card, Header, } from 'react-native-elements'
|
||||
import { List, Button, ListItem } from 'react-native-elements'
|
||||
import { FormLabel, FormInput, Text, FormValidationMessage } from 'react-native-elements'
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
import { Icon, Card, Header } from 'react-native-elements';
|
||||
import { List, Button, ListItem } from 'react-native-elements';
|
||||
import {
|
||||
BlueLoading, BlueSpacing20, BlueList, BlueButton, SafeBlueArea, BlueCard, BlueText, BlueListItem, BlueHeader,
|
||||
BlueFormInput, BlueSpacing
|
||||
} from '../../BlueComponents'
|
||||
let EV = require('../../events')
|
||||
let BigNumber = require('bignumber.js')
|
||||
let bitcoinjs = require('bitcoinjs-lib')
|
||||
FormLabel,
|
||||
FormInput,
|
||||
Text,
|
||||
FormValidationMessage,
|
||||
} from 'react-native-elements';
|
||||
import {
|
||||
BlueLoading,
|
||||
BlueSpacing20,
|
||||
BlueList,
|
||||
BlueButton,
|
||||
SafeBlueArea,
|
||||
BlueCard,
|
||||
BlueText,
|
||||
BlueListItem,
|
||||
BlueHeader,
|
||||
BlueFormInput,
|
||||
BlueSpacing,
|
||||
} from '../../BlueComponents';
|
||||
let EV = require('../../events');
|
||||
let BigNumber = require('bignumber.js');
|
||||
let bitcoinjs = require('bitcoinjs-lib');
|
||||
|
||||
export default class SendCreate extends Component {
|
||||
|
||||
|
||||
static navigationOptions = {
|
||||
tabBarIcon: ({ tintColor, focused }) => (
|
||||
<Ionicons
|
||||
@ -26,162 +38,186 @@ export default class SendCreate extends Component {
|
||||
style={{ color: tintColor }}
|
||||
/>
|
||||
),
|
||||
}
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
console.log('send/create constructor')
|
||||
console.log('send/create constructor');
|
||||
if (!props.navigation.state.params.feeDelta) {
|
||||
props.navigation.state.params.feeDelta = '0'
|
||||
props.navigation.state.params.feeDelta = '0';
|
||||
}
|
||||
this.state = {
|
||||
isLoading : true,
|
||||
isLoading: true,
|
||||
feeDelta: props.navigation.state.params.feeDelta,
|
||||
newDestinationAddress: props.navigation.state.params.newDestinationAddress,
|
||||
newDestinationAddress:
|
||||
props.navigation.state.params.newDestinationAddress,
|
||||
txid: props.navigation.state.params.txid,
|
||||
sourceTx: props.navigation.state.params.sourceTx,
|
||||
fromWallet: props.navigation.state.params.sourceWallet,
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
console.log('RBF-create - componentDidMount')
|
||||
console.log('RBF-create - componentDidMount');
|
||||
|
||||
let utxo = []
|
||||
let utxo = [];
|
||||
|
||||
let lastSequence = 0
|
||||
let totalInputAmountSatoshi = 0
|
||||
for (let input of this.state.sourceTx.inputs){
|
||||
let lastSequence = 0;
|
||||
let totalInputAmountSatoshi = 0;
|
||||
for (let input of this.state.sourceTx.inputs) {
|
||||
if (input.sequence > lastSequence) {
|
||||
lastSequence = input.sequence
|
||||
lastSequence = input.sequence;
|
||||
}
|
||||
totalInputAmountSatoshi += input.output_value
|
||||
totalInputAmountSatoshi += input.output_value;
|
||||
// let amount = new BigNumber(input.output_value)
|
||||
// amount = amount.div(10000000).toString(10)
|
||||
utxo.push({
|
||||
tx_hash : input.prev_hash,
|
||||
tx_output_n : input.output_index,
|
||||
tx_hash: input.prev_hash,
|
||||
tx_output_n: input.output_index,
|
||||
value: input.output_value,
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// check seq=MAX and fail if it is
|
||||
if (lastSequence === bitcoinjs.Transaction.DEFAULT_SEQUENCE) {
|
||||
return this.setState({
|
||||
isLoading: false,
|
||||
nonReplaceable : true
|
||||
})
|
||||
nonReplaceable: true,
|
||||
});
|
||||
// lastSequence = 1
|
||||
}
|
||||
|
||||
let tx_metadata = BlueApp.tx_metadata[this.state.txid]
|
||||
let tx_metadata = BlueApp.tx_metadata[this.state.txid];
|
||||
if (tx_metadata) {
|
||||
if (tx_metadata.last_sequence) {
|
||||
lastSequence = Math.max(lastSequence, tx_metadata.last_sequence)
|
||||
lastSequence = Math.max(lastSequence, tx_metadata.last_sequence);
|
||||
}
|
||||
}
|
||||
|
||||
lastSequence += 1
|
||||
lastSequence += 1;
|
||||
|
||||
let changeAddress
|
||||
let transferAmount
|
||||
let totalOutputAmountSatoshi = 0
|
||||
let changeAddress;
|
||||
let transferAmount;
|
||||
let totalOutputAmountSatoshi = 0;
|
||||
for (let o of this.state.sourceTx.outputs) {
|
||||
totalOutputAmountSatoshi += o.value
|
||||
if (o.addresses[0] === this.state.fromWallet.getAddress()) { // change
|
||||
changeAddress = o.addresses[0]
|
||||
totalOutputAmountSatoshi += o.value;
|
||||
if (o.addresses[0] === this.state.fromWallet.getAddress()) {
|
||||
// change
|
||||
changeAddress = o.addresses[0];
|
||||
} else {
|
||||
transferAmount = new BigNumber(o.value)
|
||||
transferAmount = transferAmount.div(100000000).toString(10)
|
||||
transferAmount = new BigNumber(o.value);
|
||||
transferAmount = transferAmount.div(100000000).toString(10);
|
||||
}
|
||||
}
|
||||
let oldFee = new BigNumber(totalInputAmountSatoshi - totalOutputAmountSatoshi)
|
||||
oldFee = parseFloat(oldFee.div(100000000).toString(10))
|
||||
let oldFee = new BigNumber(
|
||||
totalInputAmountSatoshi - totalOutputAmountSatoshi,
|
||||
);
|
||||
oldFee = parseFloat(oldFee.div(100000000).toString(10));
|
||||
|
||||
console.log('changeAddress = ', changeAddress)
|
||||
console.log('utxo', utxo)
|
||||
console.log('lastSequence', lastSequence)
|
||||
console.log('totalInputAmountSatoshi', totalInputAmountSatoshi)
|
||||
console.log('totalOutputAmountSatoshi', totalOutputAmountSatoshi)
|
||||
console.log('transferAmount', transferAmount)
|
||||
console.log('oldFee', oldFee)
|
||||
|
||||
|
||||
let newFee = new BigNumber(oldFee)
|
||||
newFee = newFee.add(this.state.feeDelta).toString(10)
|
||||
console.log('new Fee', newFee)
|
||||
console.log('changeAddress = ', changeAddress);
|
||||
console.log('utxo', utxo);
|
||||
console.log('lastSequence', lastSequence);
|
||||
console.log('totalInputAmountSatoshi', totalInputAmountSatoshi);
|
||||
console.log('totalOutputAmountSatoshi', totalOutputAmountSatoshi);
|
||||
console.log('transferAmount', transferAmount);
|
||||
console.log('oldFee', oldFee);
|
||||
|
||||
let newFee = new BigNumber(oldFee);
|
||||
newFee = newFee.add(this.state.feeDelta).toString(10);
|
||||
console.log('new Fee', newFee);
|
||||
|
||||
// creating TX
|
||||
|
||||
setTimeout(() => { // more responsive
|
||||
let tx
|
||||
setTimeout(() => {
|
||||
// more responsive
|
||||
let tx;
|
||||
try {
|
||||
tx = this.state.fromWallet.createTx(utxo, transferAmount, newFee, this.state.newDestinationAddress, false, lastSequence)
|
||||
BlueApp.tx_metadata[this.state.txid] = tx_metadata || {}
|
||||
BlueApp.tx_metadata[this.state.txid]['last_sequence'] = lastSequence
|
||||
tx = this.state.fromWallet.createTx(
|
||||
utxo,
|
||||
transferAmount,
|
||||
newFee,
|
||||
this.state.newDestinationAddress,
|
||||
false,
|
||||
lastSequence,
|
||||
);
|
||||
BlueApp.tx_metadata[this.state.txid] = tx_metadata || {};
|
||||
BlueApp.tx_metadata[this.state.txid]['last_sequence'] = lastSequence;
|
||||
|
||||
// in case new TX get confirmed, we must save metadata under new txid
|
||||
let bitcoin = require('bitcoinjs-lib');
|
||||
let txDecoded = bitcoin.Transaction.fromHex(tx);
|
||||
let txid = txDecoded.getId();
|
||||
BlueApp.tx_metadata[txid] = BlueApp.tx_metadata[this.state.txid]
|
||||
BlueApp.tx_metadata[txid]['txhex'] = tx
|
||||
BlueApp.tx_metadata[txid] = BlueApp.tx_metadata[this.state.txid];
|
||||
BlueApp.tx_metadata[txid]['txhex'] = tx;
|
||||
//
|
||||
BlueApp.saveToDisk()
|
||||
console.log('BlueApp.tx_metadata[this.state.txid]', BlueApp.tx_metadata[this.state.txid])
|
||||
BlueApp.saveToDisk();
|
||||
console.log(
|
||||
'BlueApp.tx_metadata[this.state.txid]',
|
||||
BlueApp.tx_metadata[this.state.txid],
|
||||
);
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
console.log(err);
|
||||
return this.setState({
|
||||
isError: true,
|
||||
errorMessage: JSON.stringify(err.message)
|
||||
})
|
||||
errorMessage: JSON.stringify(err.message),
|
||||
});
|
||||
}
|
||||
|
||||
let newFeeSatoshi = new BigNumber(newFee)
|
||||
newFeeSatoshi = parseInt(newFeeSatoshi.mul(100000000))
|
||||
let satoshiPerByte = Math.round(newFeeSatoshi / (tx.length/2))
|
||||
let newFeeSatoshi = new BigNumber(newFee);
|
||||
newFeeSatoshi = parseInt(newFeeSatoshi.mul(100000000));
|
||||
let satoshiPerByte = Math.round(newFeeSatoshi / (tx.length / 2));
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
size: Math.round(tx.length/2),
|
||||
size: Math.round(tx.length / 2),
|
||||
tx,
|
||||
satoshiPerByte : satoshiPerByte,
|
||||
amount : transferAmount,
|
||||
satoshiPerByte: satoshiPerByte,
|
||||
amount: transferAmount,
|
||||
fee: newFee,
|
||||
})
|
||||
}, 10)
|
||||
});
|
||||
}, 10);
|
||||
}
|
||||
|
||||
async broadcast() {
|
||||
console.log('broadcasting', this.state.tx)
|
||||
let result = await this.state.fromWallet.broadcastTx(this.state.tx)
|
||||
console.log('broadcast result = ', result)
|
||||
console.log('broadcasting', this.state.tx);
|
||||
let result = await this.state.fromWallet.broadcastTx(this.state.tx);
|
||||
console.log('broadcast result = ', result);
|
||||
if (typeof result === 'string') {
|
||||
result = JSON.parse(result)
|
||||
result = JSON.parse(result);
|
||||
}
|
||||
if ((result && result.error)) {
|
||||
this.setState({broadcastErrorMessage : JSON.stringify(result.error), broadcastSuccessMessage : ''})
|
||||
if (result && result.error) {
|
||||
this.setState({
|
||||
broadcastErrorMessage: JSON.stringify(result.error),
|
||||
broadcastSuccessMessage: '',
|
||||
});
|
||||
} else {
|
||||
this.setState({broadcastErrorMessage : ''})
|
||||
this.setState({broadcastSuccessMessage : 'Success! TXID: ' + JSON.stringify(result.result)})
|
||||
this.setState({ broadcastErrorMessage: '' });
|
||||
this.setState({
|
||||
broadcastSuccessMessage:
|
||||
'Success! TXID: ' + JSON.stringify(result.result),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
const {navigate} = this.props.navigation;
|
||||
const { navigate } = this.props.navigation;
|
||||
|
||||
if (this.state.isError) {
|
||||
return (
|
||||
<SafeBlueArea style={{flex: 1, paddingTop: 20}}>
|
||||
<BlueSpacing/>
|
||||
<BlueCard title={"Replace Transaction"} style={{alignItems: 'center', flex: 1}}>
|
||||
<BlueText>Error creating transaction. Invalid address or send amount?</BlueText>
|
||||
<FormValidationMessage>{this.state.errorMessage}</FormValidationMessage>
|
||||
<SafeBlueArea style={{ flex: 1, paddingTop: 20 }}>
|
||||
<BlueSpacing />
|
||||
<BlueCard
|
||||
title={'Replace Transaction'}
|
||||
style={{ alignItems: 'center', flex: 1 }}
|
||||
>
|
||||
<BlueText>
|
||||
Error creating transaction. Invalid address or send amount?
|
||||
</BlueText>
|
||||
<FormValidationMessage>
|
||||
{this.state.errorMessage}
|
||||
</FormValidationMessage>
|
||||
</BlueCard>
|
||||
<BlueButton
|
||||
onPress={() =>this.props.navigation.goBack()}
|
||||
onPress={() => this.props.navigation.goBack()}
|
||||
title="Go back"
|
||||
/>
|
||||
</SafeBlueArea>
|
||||
@ -189,90 +225,83 @@ export default class SendCreate extends Component {
|
||||
}
|
||||
|
||||
if (this.state.isLoading) {
|
||||
return (
|
||||
<BlueLoading/>
|
||||
);
|
||||
return <BlueLoading />;
|
||||
}
|
||||
|
||||
if (this.state.nonReplaceable) {
|
||||
return (
|
||||
<SafeBlueArea style={{flex: 1, paddingTop: 20}}>
|
||||
<BlueSpacing20/>
|
||||
<BlueSpacing20/>
|
||||
<BlueSpacing20/>
|
||||
<BlueSpacing20/>
|
||||
<BlueSpacing20/>
|
||||
<SafeBlueArea style={{ flex: 1, paddingTop: 20 }}>
|
||||
<BlueSpacing20 />
|
||||
<BlueSpacing20 />
|
||||
<BlueSpacing20 />
|
||||
<BlueSpacing20 />
|
||||
<BlueSpacing20 />
|
||||
|
||||
<BlueText h4>This transaction is not replaceable</BlueText>
|
||||
|
||||
<BlueButton
|
||||
onPress={() =>
|
||||
this.props.navigation.goBack()
|
||||
}
|
||||
onPress={() => this.props.navigation.goBack()}
|
||||
title="Back"
|
||||
/>
|
||||
</SafeBlueArea>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<SafeBlueArea style={{flex: 1, paddingTop: 20}}>
|
||||
<BlueSpacing/>
|
||||
<BlueCard title={"Replace Transaction"} style={{alignItems: 'center', flex: 1}}>
|
||||
|
||||
<BlueText>This is transaction hex, signed and ready to be broadcast to the network. Continue?</BlueText>
|
||||
<SafeBlueArea style={{ flex: 1, paddingTop: 20 }}>
|
||||
<BlueSpacing />
|
||||
<BlueCard
|
||||
title={'Replace Transaction'}
|
||||
style={{ alignItems: 'center', flex: 1 }}
|
||||
>
|
||||
<BlueText>
|
||||
This is transaction hex, signed and ready to be broadcast to the
|
||||
network. Continue?
|
||||
</BlueText>
|
||||
|
||||
<TextInput
|
||||
style={{borderColor: '#ebebeb', borderWidth: 1, marginTop:20, color:'#ebebeb'}}
|
||||
style={{
|
||||
borderColor: '#ebebeb',
|
||||
borderWidth: 1,
|
||||
marginTop: 20,
|
||||
color: '#ebebeb',
|
||||
}}
|
||||
maxHeight={70}
|
||||
multiline={true}
|
||||
multiline
|
||||
editable={false}
|
||||
value={this.state.tx}
|
||||
/>
|
||||
|
||||
<BlueSpacing20/>
|
||||
<BlueSpacing20 />
|
||||
|
||||
<BlueText style={{paddingTop:20}} >To: {this.state.newDestinationAddress}</BlueText>
|
||||
<BlueText style={{ paddingTop: 20 }}>
|
||||
To: {this.state.newDestinationAddress}
|
||||
</BlueText>
|
||||
<BlueText>Amount: {this.state.amount} BTC</BlueText>
|
||||
<BlueText>Fee: {this.state.fee} BTC</BlueText>
|
||||
<BlueText>TX size: {this.state.size} Bytes</BlueText>
|
||||
<BlueText>satoshiPerByte: {this.state.satoshiPerByte} Sat/B</BlueText>
|
||||
|
||||
</BlueCard>
|
||||
|
||||
|
||||
|
||||
|
||||
<BlueButton
|
||||
icon={{name: 'megaphone', type: 'octicon'}}
|
||||
onPress={() =>
|
||||
this.broadcast()
|
||||
}
|
||||
icon={{ name: 'megaphone', type: 'octicon' }}
|
||||
onPress={() => this.broadcast()}
|
||||
title="Broadcast"
|
||||
/>
|
||||
|
||||
|
||||
<BlueButton
|
||||
icon={{name: 'arrow-left', type: 'octicon'}}
|
||||
onPress={() =>
|
||||
this.props.navigation.goBack()
|
||||
}
|
||||
icon={{ name: 'arrow-left', type: 'octicon' }}
|
||||
onPress={() => this.props.navigation.goBack()}
|
||||
title="Go back"
|
||||
/>
|
||||
|
||||
<FormValidationMessage>{this.state.broadcastErrorMessage}</FormValidationMessage>
|
||||
<Text style={{padding:20, color:"#080"}}>{this.state.broadcastSuccessMessage}</Text>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<FormValidationMessage>
|
||||
{this.state.broadcastErrorMessage}
|
||||
</FormValidationMessage>
|
||||
<Text style={{ padding: 20, color: '#080' }}>
|
||||
{this.state.broadcastSuccessMessage}
|
||||
</Text>
|
||||
</SafeBlueArea>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,23 +1,34 @@
|
||||
/** @type {AppStorage} */
|
||||
let BlueApp = require('../../BlueApp')
|
||||
let BlueApp = require('../../BlueApp');
|
||||
import React, { Component } from 'react';
|
||||
import { ActivityIndicator, TextInput, View } from 'react-native';
|
||||
import { ActivityIndicator, TextInput, View } from 'react-native';
|
||||
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||
import { SafeAreaView, } from 'react-navigation';
|
||||
import { Icon, Card, Header, } from 'react-native-elements'
|
||||
import { List, Button, ListItem } from 'react-native-elements'
|
||||
import { FormLabel, FormInput, Text, FormValidationMessage } from 'react-native-elements'
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
import { Icon, Card, Header } from 'react-native-elements';
|
||||
import { List, Button, ListItem } from 'react-native-elements';
|
||||
import {
|
||||
BlueSpacing20, BlueList, BlueButton, SafeBlueArea, BlueCard, BlueText, BlueListItem, BlueHeader,
|
||||
BlueFormInput, BlueSpacing
|
||||
} from '../../BlueComponents'
|
||||
let EV = require('../../events')
|
||||
FormLabel,
|
||||
FormInput,
|
||||
Text,
|
||||
FormValidationMessage,
|
||||
} from 'react-native-elements';
|
||||
import {
|
||||
BlueSpacing20,
|
||||
BlueList,
|
||||
BlueButton,
|
||||
SafeBlueArea,
|
||||
BlueCard,
|
||||
BlueText,
|
||||
BlueListItem,
|
||||
BlueHeader,
|
||||
BlueFormInput,
|
||||
BlueSpacing,
|
||||
} from '../../BlueComponents';
|
||||
let EV = require('../../events');
|
||||
let BigNumber = require('bignumber.js');
|
||||
let bitcoinjs = require('bitcoinjs-lib')
|
||||
let bitcoinjs = require('bitcoinjs-lib');
|
||||
|
||||
export default class RBF extends Component {
|
||||
|
||||
|
||||
static navigationOptions = {
|
||||
tabBarIcon: ({ tintColor, focused }) => (
|
||||
<Ionicons
|
||||
@ -26,34 +37,36 @@ export default class RBF extends Component {
|
||||
style={{ color: tintColor }}
|
||||
/>
|
||||
),
|
||||
}
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
let txid
|
||||
if (props.navigation.state.params) txid = props.navigation.state.params.txid
|
||||
let txid;
|
||||
if (props.navigation.state.params)
|
||||
txid = props.navigation.state.params.txid;
|
||||
|
||||
|
||||
let sourceWallet
|
||||
let sourceTx
|
||||
let sourceWallet;
|
||||
let sourceTx;
|
||||
for (let w of BlueApp.getWallets()) {
|
||||
for (let t of w.getTransactions()) {
|
||||
if (t.hash === txid) {
|
||||
// found our source wallet
|
||||
sourceWallet = w
|
||||
sourceTx = t
|
||||
console.log(t)
|
||||
sourceWallet = w;
|
||||
sourceTx = t;
|
||||
console.log(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let destinationAddress
|
||||
let destinationAddress;
|
||||
for (let o of sourceTx.outputs) {
|
||||
if (o.addresses[0] === sourceWallet.getAddress()) { // change
|
||||
if (o.addresses[0] === sourceWallet.getAddress()) {
|
||||
// change
|
||||
// nop
|
||||
} else { // DESTINATION address
|
||||
destinationAddress = o.addresses[0]
|
||||
console.log('dest = ', destinationAddress)
|
||||
} else {
|
||||
// DESTINATION address
|
||||
destinationAddress = o.addresses[0];
|
||||
console.log('dest = ', destinationAddress);
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,8 +74,8 @@ export default class RBF extends Component {
|
||||
this.state = {
|
||||
isLoading: false,
|
||||
nonReplaceable: true,
|
||||
}
|
||||
return ;
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
this.state = {
|
||||
@ -70,22 +83,21 @@ export default class RBF extends Component {
|
||||
txid,
|
||||
sourceTx,
|
||||
sourceWallet,
|
||||
newDestinationAddress : destinationAddress,
|
||||
feeDelta : '',
|
||||
}
|
||||
newDestinationAddress: destinationAddress,
|
||||
feeDelta: '',
|
||||
};
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
let startTime = Date.now()
|
||||
console.log('send/details - componentDidMount')
|
||||
let startTime = Date.now();
|
||||
console.log('send/details - componentDidMount');
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
})
|
||||
let endTime = Date.now()
|
||||
console.log('componentDidMount took', (endTime-startTime)/1000, 'sec')
|
||||
});
|
||||
let endTime = Date.now();
|
||||
console.log('componentDidMount took', (endTime - startTime) / 1000, 'sec');
|
||||
}
|
||||
|
||||
|
||||
createTransaction() {
|
||||
this.props.navigation.navigate('CreateRBF', {
|
||||
feeDelta: this.state.feeDelta,
|
||||
@ -93,15 +105,15 @@ export default class RBF extends Component {
|
||||
txid: this.state.txid,
|
||||
sourceTx: this.state.sourceTx,
|
||||
sourceWallet: this.state.sourceWallet,
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const {navigate} = this.props.navigation;
|
||||
const { navigate } = this.props.navigation;
|
||||
|
||||
if (this.state.isLoading) {
|
||||
return (
|
||||
<View style={{flex: 1, paddingTop: 20}}>
|
||||
<View style={{ flex: 1, paddingTop: 20 }}>
|
||||
<ActivityIndicator />
|
||||
</View>
|
||||
);
|
||||
@ -109,19 +121,17 @@ export default class RBF extends Component {
|
||||
|
||||
if (this.state.nonReplaceable) {
|
||||
return (
|
||||
<SafeBlueArea style={{flex: 1, paddingTop: 20}}>
|
||||
<BlueSpacing20/>
|
||||
<BlueSpacing20/>
|
||||
<BlueSpacing20/>
|
||||
<BlueSpacing20/>
|
||||
<BlueSpacing20/>
|
||||
<SafeBlueArea style={{ flex: 1, paddingTop: 20 }}>
|
||||
<BlueSpacing20 />
|
||||
<BlueSpacing20 />
|
||||
<BlueSpacing20 />
|
||||
<BlueSpacing20 />
|
||||
<BlueSpacing20 />
|
||||
|
||||
<BlueText h4>This transaction is not replaceable</BlueText>
|
||||
|
||||
<BlueButton
|
||||
onPress={() =>
|
||||
this.props.navigation.goBack()
|
||||
}
|
||||
onPress={() => this.props.navigation.goBack()}
|
||||
title="Back"
|
||||
/>
|
||||
</SafeBlueArea>
|
||||
@ -130,77 +140,68 @@ export default class RBF extends Component {
|
||||
|
||||
if (!this.state.sourceWallet.getAddress) {
|
||||
return (
|
||||
<SafeBlueArea style={{flex: 1, paddingTop: 20}}>
|
||||
<BlueText>System error: Source wallet not found (this should never happen)</BlueText>
|
||||
<SafeBlueArea style={{ flex: 1, paddingTop: 20 }}>
|
||||
<BlueText>
|
||||
System error: Source wallet not found (this should never happen)
|
||||
</BlueText>
|
||||
<BlueButton
|
||||
onPress={() =>
|
||||
this.props.navigation.goBack()
|
||||
}
|
||||
onPress={() => this.props.navigation.goBack()}
|
||||
title="Back"
|
||||
/>
|
||||
</SafeBlueArea>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<SafeBlueArea style={{flex: 1, paddingTop: 20}}>
|
||||
<BlueSpacing/>
|
||||
<BlueCard title={"Replace By Fee"} style={{alignItems: 'center', flex: 1}}>
|
||||
<SafeBlueArea style={{ flex: 1, paddingTop: 20 }}>
|
||||
<BlueSpacing />
|
||||
<BlueCard
|
||||
title={'Replace By Fee'}
|
||||
style={{ alignItems: 'center', flex: 1 }}
|
||||
>
|
||||
<BlueText>
|
||||
RBF allows you to increase fee on already sent but not confirmed
|
||||
transaction, thus speeding up mining
|
||||
</BlueText>
|
||||
<BlueSpacing20 />
|
||||
|
||||
<BlueText>RBF allows you to increase fee on already sent but not confirmed transaction, thus speeding up mining</BlueText>
|
||||
<BlueSpacing20/>
|
||||
|
||||
<BlueText>From wallet '{this.state.sourceWallet.getLabel()}' ({this.state.sourceWallet.getAddress()})</BlueText>
|
||||
<BlueSpacing20/>
|
||||
<BlueText>
|
||||
From wallet '{this.state.sourceWallet.getLabel()}' ({this.state.sourceWallet.getAddress()})
|
||||
</BlueText>
|
||||
<BlueSpacing20 />
|
||||
|
||||
<BlueFormInput
|
||||
onChangeText={(text) => this.setState({newDestinationAddress: text})}
|
||||
placeholder={"receiver address here"}
|
||||
value={this.state.newDestinationAddress}
|
||||
onChangeText={text =>
|
||||
this.setState({ newDestinationAddress: text })
|
||||
}
|
||||
placeholder={'receiver address here'}
|
||||
value={this.state.newDestinationAddress}
|
||||
/>
|
||||
|
||||
<BlueFormInput onChangeText={(text) => this.setState({feeDelta: text})} keyboardType={"numeric"}
|
||||
placeholder={"fee to add (in BTC)"}
|
||||
value={this.state.feeDelta + ''}
|
||||
<BlueFormInput
|
||||
onChangeText={text => this.setState({ feeDelta: text })}
|
||||
keyboardType={'numeric'}
|
||||
placeholder={'fee to add (in BTC)'}
|
||||
value={this.state.feeDelta + ''}
|
||||
/>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</BlueCard>
|
||||
|
||||
<View style={{flex: 1, flexDirection: 'row', paddingTop:20,}}>
|
||||
<View style={{flex: 0.33}}>
|
||||
<View style={{ flex: 1, flexDirection: 'row', paddingTop: 20 }}>
|
||||
<View style={{ flex: 0.33 }}>
|
||||
<BlueButton
|
||||
onPress={() =>
|
||||
this.props.navigation.goBack()
|
||||
}
|
||||
onPress={() => this.props.navigation.goBack()}
|
||||
title="Cancel"
|
||||
/>
|
||||
</View>
|
||||
<View style={{flex: 0.33}}>
|
||||
|
||||
|
||||
</View>
|
||||
<View style={{flex: 0.33}}>
|
||||
<View style={{ flex: 0.33 }} />
|
||||
<View style={{ flex: 0.33 }}>
|
||||
<BlueButton
|
||||
onPress={() =>
|
||||
this.createTransaction()
|
||||
}
|
||||
onPress={() => this.createTransaction()}
|
||||
title="Create"
|
||||
/>
|
||||
</View>
|
||||
|
||||
</View>
|
||||
|
||||
|
||||
</SafeBlueArea>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,19 +1,26 @@
|
||||
/** @type {AppStorage} */
|
||||
|
||||
let BlueApp = require('../../BlueApp')
|
||||
let BlueApp = require('../../BlueApp');
|
||||
import React, { Component } from 'react';
|
||||
import { ActivityIndicator, View } from 'react-native';
|
||||
import { ActivityIndicator, View } from 'react-native';
|
||||
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||
import { SafeAreaView, } from 'react-navigation';
|
||||
import { Icon, Card, Header, } from 'react-native-elements'
|
||||
import { List, Button, ListItem, Text } from 'react-native-elements'
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
import { Icon, Card, Header } from 'react-native-elements';
|
||||
import { List, Button, ListItem, Text } from 'react-native-elements';
|
||||
import {
|
||||
BlueList, BlueButton, SafeBlueArea, BlueCard, BlueText, BlueListItem, BlueHeader,
|
||||
BlueSpacing, BlueLoading, BlueSpacing20
|
||||
} from '../../BlueComponents'
|
||||
BlueList,
|
||||
BlueButton,
|
||||
SafeBlueArea,
|
||||
BlueCard,
|
||||
BlueText,
|
||||
BlueListItem,
|
||||
BlueHeader,
|
||||
BlueSpacing,
|
||||
BlueLoading,
|
||||
BlueSpacing20,
|
||||
} from '../../BlueComponents';
|
||||
|
||||
export default class TransactionsDetails extends Component {
|
||||
|
||||
static navigationOptions = {
|
||||
tabBarIcon: ({ tintColor, focused }) => (
|
||||
<Ionicons
|
||||
@ -22,67 +29,69 @@ export default class TransactionsDetails extends Component {
|
||||
style={{ color: tintColor }}
|
||||
/>
|
||||
),
|
||||
}
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
let hash = props.navigation.state.params.hash
|
||||
let foundTx = {}
|
||||
let from = []
|
||||
let to = []
|
||||
let hash = props.navigation.state.params.hash;
|
||||
let foundTx = {};
|
||||
let from = [];
|
||||
let to = [];
|
||||
for (let tx of BlueApp.getTransactions()) {
|
||||
if (tx.hash === hash) {
|
||||
console.log(tx);
|
||||
foundTx = tx;
|
||||
for (let input of foundTx.inputs) {
|
||||
from = from.concat(input.addresses)
|
||||
from = from.concat(input.addresses);
|
||||
}
|
||||
for (let output of foundTx.outputs) {
|
||||
to = to.concat(output.addresses)
|
||||
to = to.concat(output.addresses);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
this.state = {
|
||||
isLoading: true,
|
||||
tx: foundTx,
|
||||
from,
|
||||
to,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
console.log('transactions/details - componentDidMount')
|
||||
console.log('transactions/details - componentDidMount');
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
const {navigate} = this.props.navigation;
|
||||
const { navigate } = this.props.navigation;
|
||||
|
||||
if (this.state.isLoading) {
|
||||
return (
|
||||
<BlueLoading/>
|
||||
);
|
||||
return <BlueLoading />;
|
||||
}
|
||||
|
||||
return (
|
||||
<SafeBlueArea forceInset={{ horizontal: 'always' }} style={{flex: 1, paddingTop: 20}}>
|
||||
<BlueSpacing/>
|
||||
<BlueCard title={"Transaction details"} style={{alignItems: 'center', flex: 1}}>
|
||||
|
||||
<SafeBlueArea
|
||||
forceInset={{ horizontal: 'always' }}
|
||||
style={{ flex: 1, paddingTop: 20 }}
|
||||
>
|
||||
<BlueSpacing />
|
||||
<BlueCard
|
||||
title={'Transaction details'}
|
||||
style={{ alignItems: 'center', flex: 1 }}
|
||||
>
|
||||
{(() => {
|
||||
let memo
|
||||
let memo;
|
||||
if (BlueApp.tx_metadata[this.state.tx.hash]) {
|
||||
if (BlueApp.tx_metadata[this.state.tx.hash]['memo']){
|
||||
if (BlueApp.tx_metadata[this.state.tx.hash]['memo']) {
|
||||
return (
|
||||
<View>
|
||||
<BlueText h4>{BlueApp.tx_metadata[this.state.tx.hash]['memo']}</BlueText>
|
||||
<BlueSpacing20/>
|
||||
<BlueText h4>
|
||||
{BlueApp.tx_metadata[this.state.tx.hash]['memo']}
|
||||
</BlueText>
|
||||
<BlueSpacing20 />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@ -90,11 +99,14 @@ export default class TransactionsDetails extends Component {
|
||||
})()}
|
||||
|
||||
<BlueText h4>From:</BlueText>
|
||||
<BlueText style={{marginBottom: 10}}>{this.state.from.join(', ')}</BlueText>
|
||||
|
||||
<BlueText style={{ marginBottom: 10 }}>
|
||||
{this.state.from.join(', ')}
|
||||
</BlueText>
|
||||
|
||||
<BlueText h4>To:</BlueText>
|
||||
<BlueText style={{marginBottom: 10}}>{this.state.to.join(', ')}</BlueText>
|
||||
<BlueText style={{ marginBottom: 10 }}>
|
||||
{this.state.to.join(', ')}
|
||||
</BlueText>
|
||||
|
||||
<BlueText>Txid: {this.state.tx.hash}</BlueText>
|
||||
<BlueText>received: {this.state.tx.received}</BlueText>
|
||||
@ -103,18 +115,17 @@ export default class TransactionsDetails extends Component {
|
||||
<BlueText>inputs: {this.state.tx.inputs.length}</BlueText>
|
||||
<BlueText>outputs: {this.state.tx.outputs.length}</BlueText>
|
||||
|
||||
<BlueText style={{marginBottom: 10}}> </BlueText>
|
||||
|
||||
<BlueText style={{ marginBottom: 10 }} />
|
||||
</BlueCard>
|
||||
|
||||
|
||||
|
||||
{(() => {
|
||||
if (this.state.tx.confirmations === 0) {
|
||||
if (this.state.tx.confirmations === 0) {
|
||||
return (
|
||||
<BlueButton
|
||||
onPress={() =>
|
||||
this.props.navigation.navigate('RBF', {txid: this.state.tx.hash})
|
||||
this.props.navigation.navigate('RBF', {
|
||||
txid: this.state.tx.hash,
|
||||
})
|
||||
}
|
||||
title="Replace-By-Fee (RBF)"
|
||||
/>
|
||||
@ -122,20 +133,12 @@ export default class TransactionsDetails extends Component {
|
||||
}
|
||||
})()}
|
||||
|
||||
|
||||
|
||||
<BlueButton
|
||||
icon={{name: 'arrow-left', type: 'octicon'}}
|
||||
onPress={() =>
|
||||
this.props.navigation.goBack()
|
||||
}
|
||||
icon={{ name: 'arrow-left', type: 'octicon' }}
|
||||
onPress={() => this.props.navigation.goBack()}
|
||||
title="Go back"
|
||||
/>
|
||||
|
||||
|
||||
</SafeBlueArea>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,17 +1,33 @@
|
||||
/** @type {AppStorage} */
|
||||
let BlueApp = require('../../BlueApp')
|
||||
let BlueApp = require('../../BlueApp');
|
||||
import React, { Component } from 'react';
|
||||
import { ActivityIndicator, StyleSheet, ListView, Text, View } from 'react-native';
|
||||
import {
|
||||
ActivityIndicator,
|
||||
StyleSheet,
|
||||
ListView,
|
||||
Text,
|
||||
View,
|
||||
} from 'react-native';
|
||||
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||
import { SafeAreaView, TabNavigator } from 'react-navigation';
|
||||
import { Card, Header, Icon, List, ListItem } from 'react-native-elements'
|
||||
import { BlueLoading, BlueList, BlueListView, BlueSpacing, BlueButton, SafeBlueArea, BlueCard, BlueText, BlueListItem, BlueHeader } from '../../BlueComponents'
|
||||
let EV = require('../../events')
|
||||
import { Card, Header, Icon, List, ListItem } from 'react-native-elements';
|
||||
import {
|
||||
BlueLoading,
|
||||
BlueList,
|
||||
BlueListView,
|
||||
BlueSpacing,
|
||||
BlueButton,
|
||||
SafeBlueArea,
|
||||
BlueCard,
|
||||
BlueText,
|
||||
BlueListItem,
|
||||
BlueHeader,
|
||||
} from '../../BlueComponents';
|
||||
let EV = require('../../events');
|
||||
|
||||
let ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
|
||||
|
||||
export default class TransactionsList extends Component {
|
||||
let ds = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 });
|
||||
|
||||
export default class TransactionsList extends Component {
|
||||
static navigationOptions = {
|
||||
tabBarLabel: 'Transactions',
|
||||
tabBarIcon: ({ tintColor, focused }) => (
|
||||
@ -21,122 +37,156 @@ export default class TransactionsList extends Component {
|
||||
style={{ color: tintColor }}
|
||||
/>
|
||||
),
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
isLoading: true,
|
||||
}
|
||||
};
|
||||
|
||||
EV(EV.enum.TRANSACTIONS_COUNT_CHANGED, this.refreshFunction.bind(this))
|
||||
EV(EV.enum.TRANSACTIONS_COUNT_CHANGED, this.refreshFunction.bind(this));
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
console.log('transaction/list- componentDidMount')
|
||||
this.refreshFunction()
|
||||
console.log('transaction/list- componentDidMount');
|
||||
this.refreshFunction();
|
||||
} // end
|
||||
|
||||
refreshFunction () {
|
||||
this.setState({
|
||||
isLoading: true,
|
||||
}, () => {
|
||||
setTimeout(() => {
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
final_balance: BlueApp.getBalance(),
|
||||
dataSource: ds.cloneWithRows(BlueApp.getTransactions()),
|
||||
})
|
||||
}, 1)
|
||||
})
|
||||
refreshFunction() {
|
||||
this.setState(
|
||||
{
|
||||
isLoading: true,
|
||||
},
|
||||
() => {
|
||||
setTimeout(() => {
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
final_balance: BlueApp.getBalance(),
|
||||
dataSource: ds.cloneWithRows(BlueApp.getTransactions()),
|
||||
});
|
||||
}, 1);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
txMemo (hash) {
|
||||
if (BlueApp.tx_metadata[hash] && BlueApp.tx_metadata[hash]['memo']) {
|
||||
txMemo(hash) {
|
||||
if (BlueApp.tx_metadata[hash] && BlueApp.tx_metadata[hash]['memo']) {
|
||||
return ' | ' + BlueApp.tx_metadata[hash]['memo'];
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
refresh() {
|
||||
this.setState({
|
||||
isLoading: true,
|
||||
}, async function () {
|
||||
this.setState(
|
||||
{
|
||||
isLoading: true,
|
||||
},
|
||||
async function() {
|
||||
let that = this;
|
||||
setTimeout(async function() {
|
||||
// more responsive
|
||||
let noErr = true;
|
||||
try {
|
||||
await BlueApp.fetchWalletTransactions();
|
||||
await BlueApp.fetchWalletBalances();
|
||||
} catch (err) {
|
||||
noErr = false;
|
||||
console.warn(err);
|
||||
}
|
||||
if (noErr) await BlueApp.saveToDisk(); // caching
|
||||
EV(EV.enum.WALLETS_COUNT_CHANGED); // TODO: some other event type?
|
||||
|
||||
let that = this
|
||||
setTimeout( async function() { // more responsive
|
||||
let noErr = true
|
||||
try {
|
||||
await BlueApp.fetchWalletTransactions()
|
||||
await BlueApp.fetchWalletBalances()
|
||||
} catch (err) {
|
||||
noErr = false
|
||||
console.warn(err)
|
||||
}
|
||||
if (noErr) await BlueApp.saveToDisk() // caching
|
||||
EV(EV.enum.WALLETS_COUNT_CHANGED) // TODO: some other event type?
|
||||
|
||||
that.setState({
|
||||
isLoading: false,
|
||||
final_balance: BlueApp.getBalance(),
|
||||
dataSource: ds.cloneWithRows(BlueApp.getTransactions()),
|
||||
})
|
||||
}, 10)
|
||||
})
|
||||
that.setState({
|
||||
isLoading: false,
|
||||
final_balance: BlueApp.getBalance(),
|
||||
dataSource: ds.cloneWithRows(BlueApp.getTransactions()),
|
||||
});
|
||||
}, 10);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {navigate} = this.props.navigation;
|
||||
const { navigate } = this.props.navigation;
|
||||
|
||||
if (this.state.isLoading) {
|
||||
return (
|
||||
<BlueLoading/>
|
||||
);
|
||||
return <BlueLoading />;
|
||||
}
|
||||
|
||||
return (
|
||||
<SafeBlueArea forceInset={{ horizontal: 'always' }} style={{flex: 1}}>
|
||||
<SafeBlueArea forceInset={{ horizontal: 'always' }} style={{ flex: 1 }}>
|
||||
<Header
|
||||
backgroundColor={BlueApp.settings.brandingColor}
|
||||
leftComponent={<Icon name='menu' color="#fff" onPress={() => this.props.navigation.navigate('DrawerToggle') }/>}
|
||||
centerComponent={{ text: this.state.final_balance + ' BTC', style: { color: '#fff', fontSize: 25 } }}
|
||||
rightComponent={<Icon name='refresh' color="#fff" onPress={() => this.refresh() }/>}
|
||||
leftComponent={
|
||||
<Icon
|
||||
name="menu"
|
||||
color="#fff"
|
||||
onPress={() => this.props.navigation.navigate('DrawerToggle')}
|
||||
/>
|
||||
}
|
||||
centerComponent={{
|
||||
text: this.state.final_balance + ' BTC',
|
||||
style: { color: '#fff', fontSize: 25 },
|
||||
}}
|
||||
rightComponent={
|
||||
<Icon name="refresh" color="#fff" onPress={() => this.refresh()} />
|
||||
}
|
||||
/>
|
||||
<BlueCard title='My Transactions' >
|
||||
<BlueText style={{marginBottom: 10}}>
|
||||
<BlueCard title="My Transactions">
|
||||
<BlueText style={{ marginBottom: 10 }}>
|
||||
A list of ingoing or outgoing transactions of your wallets
|
||||
</BlueText>
|
||||
|
||||
<BlueList>
|
||||
<ListView style={{ height: 360 }}
|
||||
enableEmptySections={true}
|
||||
dataSource={this.state.dataSource}
|
||||
renderRow={(rowData) => {
|
||||
return (
|
||||
<BlueListItem
|
||||
avatar={
|
||||
<Icon color={(() => {return rowData.confirmations && (rowData.value < 0 && "#900" || "#080") || "#ebebeb" })()}
|
||||
name={(() => {return rowData.value < 0 && 'call-made' || 'call-received'})()} />
|
||||
}
|
||||
title={rowData.value/100000000 + " BTC" + this.txMemo(rowData.hash)}
|
||||
subtitle={rowData.received.replace(['T'], ' ').replace(['Z'], ' ').split('.')[0] + ' | conf: ' + rowData.confirmations + "\nYOLO"}
|
||||
|
||||
onPress={() =>
|
||||
{
|
||||
navigate('TransactionDetails', {hash: rowData.hash})
|
||||
}
|
||||
}
|
||||
|
||||
/>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</BlueList>
|
||||
<BlueList>
|
||||
<ListView
|
||||
style={{ height: 360 }}
|
||||
enableEmptySections
|
||||
dataSource={this.state.dataSource}
|
||||
renderRow={rowData => {
|
||||
return (
|
||||
<BlueListItem
|
||||
avatar={
|
||||
<Icon
|
||||
color={(() => {
|
||||
return (
|
||||
(rowData.confirmations &&
|
||||
((rowData.value < 0 && '#900') || '#080')) ||
|
||||
'#ebebeb'
|
||||
);
|
||||
})()}
|
||||
name={(() => {
|
||||
return (
|
||||
(rowData.value < 0 && 'call-made') ||
|
||||
'call-received'
|
||||
);
|
||||
})()}
|
||||
/>
|
||||
}
|
||||
title={
|
||||
rowData.value / 100000000 +
|
||||
' BTC' +
|
||||
this.txMemo(rowData.hash)
|
||||
}
|
||||
subtitle={
|
||||
rowData.received
|
||||
.replace(['T'], ' ')
|
||||
.replace(['Z'], ' ')
|
||||
.split('.')[0] +
|
||||
' | conf: ' +
|
||||
rowData.confirmations +
|
||||
'\nYOLO'
|
||||
}
|
||||
onPress={() => {
|
||||
navigate('TransactionDetails', { hash: rowData.hash });
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</BlueList>
|
||||
</BlueCard>
|
||||
|
||||
</SafeBlueArea>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,26 @@
|
||||
let BlueApp = require('../../BlueApp')
|
||||
import { AppStorage, LegacyWallet, SegwitBech32Wallet, SegwitP2SHWallet } from '../../class'
|
||||
let BlueApp = require('../../BlueApp');
|
||||
import {
|
||||
AppStorage,
|
||||
LegacyWallet,
|
||||
SegwitBech32Wallet,
|
||||
SegwitP2SHWallet,
|
||||
} from '../../class';
|
||||
import React, { Component } from 'react';
|
||||
import { ActivityIndicator, View } from 'react-native';
|
||||
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||
import { SafeAreaView, } from 'react-navigation';
|
||||
import { Button } from 'react-native-elements'
|
||||
import { Icon, Card, Header} from 'react-native-elements'
|
||||
import { BlueSpacing, BlueButton, SafeBlueArea, BlueCard, BlueText, BlueListItem, BlueHeader } from '../../BlueComponents'
|
||||
let EV = require('../../events')
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
import { Button } from 'react-native-elements';
|
||||
import { Icon, Card, Header } from 'react-native-elements';
|
||||
import {
|
||||
BlueSpacing,
|
||||
BlueButton,
|
||||
SafeBlueArea,
|
||||
BlueCard,
|
||||
BlueText,
|
||||
BlueListItem,
|
||||
BlueHeader,
|
||||
} from '../../BlueComponents';
|
||||
let EV = require('../../events');
|
||||
|
||||
/*
|
||||
<Button
|
||||
@ -16,10 +29,9 @@ large icon={{name: 'qrcode', type: 'font-awesome'}} title='Scan QR WIF as Legacy
|
||||
onPress={() => {
|
||||
this.props.navigation.navigate('ScanQrWifLegacyAddress')
|
||||
}}
|
||||
/>*/
|
||||
/> */
|
||||
|
||||
export default class WalletsAdd extends Component {
|
||||
|
||||
static navigationOptions = {
|
||||
tabBarLabel: 'Wallets',
|
||||
tabBarIcon: ({ tintColor, focused }) => (
|
||||
@ -29,76 +41,80 @@ export default class WalletsAdd extends Component {
|
||||
style={{ color: tintColor }}
|
||||
/>
|
||||
),
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
isLoading: true,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
const {navigate} = this.props.navigation;
|
||||
const { navigate } = this.props.navigation;
|
||||
|
||||
if (this.state.isLoading) {
|
||||
return (
|
||||
<View style={{flex: 1, paddingTop: 20}}>
|
||||
<View style={{ flex: 1, paddingTop: 20 }}>
|
||||
<ActivityIndicator />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<SafeBlueArea forceInset={{ horizontal: 'always' }} style={{flex: 1, paddingTop: 40}}>
|
||||
<BlueSpacing/>
|
||||
<SafeBlueArea
|
||||
forceInset={{ horizontal: 'always' }}
|
||||
style={{ flex: 1, paddingTop: 40 }}
|
||||
>
|
||||
<BlueSpacing />
|
||||
<BlueCard title="Add Wallet">
|
||||
<BlueText>You can either scan backup paper wallet (in WIF - Wallet Import Format), or create a new wallet. Segwit wallets supported by default.</BlueText>
|
||||
<BlueText>
|
||||
You can either scan backup paper wallet (in WIF - Wallet Import
|
||||
Format), or create a new wallet. Segwit wallets supported by
|
||||
default.
|
||||
</BlueText>
|
||||
|
||||
<BlueButton
|
||||
large icon={{name: 'qrcode', type: 'font-awesome'}} title='Scan'
|
||||
onPress={() => {
|
||||
this.props.navigation.navigate('ScanQrWifSegwitP2SHAddress')
|
||||
}}
|
||||
large
|
||||
icon={{ name: 'qrcode', type: 'font-awesome' }}
|
||||
title="Scan"
|
||||
onPress={() => {
|
||||
this.props.navigation.navigate('ScanQrWifSegwitP2SHAddress');
|
||||
}}
|
||||
/>
|
||||
|
||||
<BlueButton
|
||||
large icon={{name: 'bitcoin', type: 'font-awesome'}} title='Create'
|
||||
onPress={() => {
|
||||
this.props.navigation.goBack()
|
||||
setTimeout(async ()=> {
|
||||
let w = new SegwitP2SHWallet()
|
||||
w.setLabel('New SegWit')
|
||||
w.generate()
|
||||
BlueApp.wallets.push(w)
|
||||
await BlueApp.saveToDisk()
|
||||
EV(EV.enum.WALLETS_COUNT_CHANGED)
|
||||
}, 1)
|
||||
}
|
||||
}
|
||||
large
|
||||
icon={{ name: 'bitcoin', type: 'font-awesome' }}
|
||||
title="Create"
|
||||
onPress={() => {
|
||||
this.props.navigation.goBack();
|
||||
setTimeout(async () => {
|
||||
let w = new SegwitP2SHWallet();
|
||||
w.setLabel('New SegWit');
|
||||
w.generate();
|
||||
BlueApp.wallets.push(w);
|
||||
await BlueApp.saveToDisk();
|
||||
EV(EV.enum.WALLETS_COUNT_CHANGED);
|
||||
}, 1);
|
||||
}}
|
||||
/>
|
||||
</BlueCard>
|
||||
|
||||
<BlueButton
|
||||
icon={{name: 'arrow-left', type: 'octicon'}}
|
||||
title='Go Back'
|
||||
onPress={() => {
|
||||
this.props.navigation.goBack()
|
||||
}
|
||||
}
|
||||
/>
|
||||
|
||||
<BlueButton
|
||||
icon={{ name: 'arrow-left', type: 'octicon' }}
|
||||
title="Go Back"
|
||||
onPress={() => {
|
||||
this.props.navigation.goBack();
|
||||
}}
|
||||
/>
|
||||
</SafeBlueArea>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,22 +1,29 @@
|
||||
/** @type {AppStorage} */
|
||||
|
||||
let BlueApp = require('../../BlueApp')
|
||||
let BlueApp = require('../../BlueApp');
|
||||
import React, { Component } from 'react';
|
||||
import { ActivityIndicator, TextInput, View } from 'react-native';
|
||||
import { ActivityIndicator, TextInput, View } from 'react-native';
|
||||
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||
import { SafeAreaView, } from 'react-navigation';
|
||||
import { Icon, Card, Header, } from 'react-native-elements'
|
||||
import { List, Button, ListItem } from 'react-native-elements'
|
||||
import { FormInput, Text, FormValidationMessage } from 'react-native-elements'
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
import { Icon, Card, Header } from 'react-native-elements';
|
||||
import { List, Button, ListItem } from 'react-native-elements';
|
||||
import { FormInput, Text, FormValidationMessage } from 'react-native-elements';
|
||||
import {
|
||||
BlueSpacing, BlueFormInput, BlueButton, SafeBlueArea, BlueCard, BlueText, BlueListItem, BlueHeader,
|
||||
BlueFormLabel, BlueListView
|
||||
} from '../../BlueComponents'
|
||||
let EV = require('../../events')
|
||||
BlueSpacing,
|
||||
BlueFormInput,
|
||||
BlueButton,
|
||||
SafeBlueArea,
|
||||
BlueCard,
|
||||
BlueText,
|
||||
BlueListItem,
|
||||
BlueHeader,
|
||||
BlueFormLabel,
|
||||
BlueListView,
|
||||
} from '../../BlueComponents';
|
||||
let EV = require('../../events');
|
||||
let BigNumber = require('bignumber.js');
|
||||
|
||||
export default class WalletDetails extends Component {
|
||||
|
||||
static navigationOptions = {
|
||||
tabBarIcon: ({ tintColor, focused }) => (
|
||||
<Ionicons
|
||||
@ -25,98 +32,101 @@ export default class WalletDetails extends Component {
|
||||
style={{ color: tintColor }}
|
||||
/>
|
||||
),
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
let address = props.navigation.state.params.address
|
||||
let address = props.navigation.state.params.address;
|
||||
|
||||
/** @type {AbstractWallet} */
|
||||
let wallet
|
||||
let wallet;
|
||||
|
||||
for (let w of BlueApp.getWallets()){
|
||||
if (w.getAddress() === address) { // found our wallet
|
||||
wallet = w
|
||||
for (let w of BlueApp.getWallets()) {
|
||||
if (w.getAddress() === address) {
|
||||
// found our wallet
|
||||
wallet = w;
|
||||
}
|
||||
}
|
||||
|
||||
this.state = {
|
||||
confirmDelete: false,
|
||||
isLoading: true,
|
||||
wallet
|
||||
}
|
||||
wallet,
|
||||
};
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
async setLabel(text) {
|
||||
this.state.wallet.label = text
|
||||
this.state.wallet.label = text;
|
||||
this.setState({
|
||||
labelChanged: true
|
||||
}) /* also, a hack to make screen update new typed text*/
|
||||
labelChanged: true,
|
||||
}); /* also, a hack to make screen update new typed text */
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
const {navigate} = this.props.navigation;
|
||||
const { navigate } = this.props.navigation;
|
||||
|
||||
if (this.state.isLoading) {
|
||||
return (
|
||||
<View style={{flex: 1, paddingTop: 20}}>
|
||||
<View style={{ flex: 1, paddingTop: 20 }}>
|
||||
<ActivityIndicator />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<SafeBlueArea style={{flex: 1, paddingTop: 20,}}>
|
||||
<BlueSpacing/>
|
||||
<BlueCard title={"Wallet Details"} style={{alignItems: 'center', flex: 1}}>
|
||||
|
||||
|
||||
<SafeBlueArea style={{ flex: 1, paddingTop: 20 }}>
|
||||
<BlueSpacing />
|
||||
<BlueCard
|
||||
title={'Wallet Details'}
|
||||
style={{ alignItems: 'center', flex: 1 }}
|
||||
>
|
||||
<BlueFormLabel>Address:</BlueFormLabel>
|
||||
<BlueFormInput value={this.state.wallet.getAddress()} editable={false} />
|
||||
<BlueFormInput
|
||||
value={this.state.wallet.getAddress()}
|
||||
editable={false}
|
||||
/>
|
||||
|
||||
<BlueFormLabel>Type:</BlueFormLabel>
|
||||
<BlueFormInput value={this.state.wallet.getTypeReadable()} editable={false} />
|
||||
<BlueFormInput
|
||||
value={this.state.wallet.getTypeReadable()}
|
||||
editable={false}
|
||||
/>
|
||||
|
||||
<BlueFormLabel>Label:</BlueFormLabel>
|
||||
<BlueFormInput
|
||||
value={this.state.wallet.getLabel()}
|
||||
onChangeText={(text) => {this.setLabel(text)}}
|
||||
value={this.state.wallet.getLabel()}
|
||||
onChangeText={text => {
|
||||
this.setLabel(text);
|
||||
}}
|
||||
/>
|
||||
|
||||
</BlueCard>
|
||||
|
||||
|
||||
{(() => {
|
||||
if (this.state.confirmDelete) {
|
||||
return (
|
||||
<View style={{alignItems: 'center',}}>
|
||||
<View style={{ alignItems: 'center' }}>
|
||||
<BlueText h4>Are you sure?</BlueText>
|
||||
<BlueButton
|
||||
icon={{name: 'stop', type: 'octicon'}}
|
||||
onPress={async () =>
|
||||
{
|
||||
BlueApp.deleteWallet(this.state.wallet)
|
||||
await BlueApp.saveToDisk()
|
||||
EV(EV.enum.TRANSACTIONS_COUNT_CHANGED)
|
||||
EV(EV.enum.WALLETS_COUNT_CHANGED)
|
||||
this.props.navigation.goBack()
|
||||
}
|
||||
}
|
||||
icon={{ name: 'stop', type: 'octicon' }}
|
||||
onPress={async () => {
|
||||
BlueApp.deleteWallet(this.state.wallet);
|
||||
await BlueApp.saveToDisk();
|
||||
EV(EV.enum.TRANSACTIONS_COUNT_CHANGED);
|
||||
EV(EV.enum.WALLETS_COUNT_CHANGED);
|
||||
this.props.navigation.goBack();
|
||||
}}
|
||||
title="Yes, delete"
|
||||
/>
|
||||
<BlueButton
|
||||
onPress={async () => {
|
||||
this.setState({confirmDelete : false})
|
||||
this.setState({ confirmDelete: false });
|
||||
}}
|
||||
title="No, cancel"
|
||||
/>
|
||||
@ -125,48 +135,37 @@ export default class WalletDetails extends Component {
|
||||
} else {
|
||||
return (
|
||||
<View>
|
||||
<BlueButton
|
||||
icon={{name: 'stop', type: 'octicon'}}
|
||||
onPress={async () => {
|
||||
this.setState({confirmDelete : true})
|
||||
}}
|
||||
title="Delete this wallet"
|
||||
/>
|
||||
<BlueButton
|
||||
icon={{ name: 'stop', type: 'octicon' }}
|
||||
onPress={async () => {
|
||||
this.setState({ confirmDelete: true });
|
||||
}}
|
||||
title="Delete this wallet"
|
||||
/>
|
||||
<BlueButton
|
||||
onPress={() =>
|
||||
this.props.navigation.navigate('WalletExport', {address: this.state.wallet.getAddress()} )
|
||||
this.props.navigation.navigate('WalletExport', {
|
||||
address: this.state.wallet.getAddress(),
|
||||
})
|
||||
}
|
||||
title="Export / backup"
|
||||
/>
|
||||
<BlueButton
|
||||
icon={{name: 'arrow-left', type: 'octicon'}}
|
||||
onPress={async () =>
|
||||
{
|
||||
|
||||
icon={{ name: 'arrow-left', type: 'octicon' }}
|
||||
onPress={async () => {
|
||||
if (this.state.labelChanged) {
|
||||
await BlueApp.saveToDisk()
|
||||
EV(EV.enum.WALLETS_COUNT_CHANGED) // TODO: some other event type?
|
||||
await BlueApp.saveToDisk();
|
||||
EV(EV.enum.WALLETS_COUNT_CHANGED); // TODO: some other event type?
|
||||
}
|
||||
this.props.navigation.goBack()
|
||||
}
|
||||
}
|
||||
this.props.navigation.goBack();
|
||||
}}
|
||||
title="Go back"
|
||||
/>
|
||||
|
||||
</View>
|
||||
|
||||
)
|
||||
);
|
||||
}
|
||||
})()}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</SafeBlueArea>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,19 +1,32 @@
|
||||
/** @type {AppStorage} */
|
||||
let BlueApp = require('../../BlueApp')
|
||||
let BlueApp = require('../../BlueApp');
|
||||
import React, { Component } from 'react';
|
||||
import { ActivityIndicator, TextInput, View } from 'react-native';
|
||||
import { ActivityIndicator, TextInput, View } from 'react-native';
|
||||
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||
import { SafeAreaView, } from 'react-navigation';
|
||||
import { Icon, Card, Header, } from 'react-native-elements'
|
||||
import { List, Button, ListItem } from 'react-native-elements'
|
||||
import { Divider, FormLabel, FormInput, Text, FormValidationMessage } from 'react-native-elements'
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
import { Icon, Card, Header } from 'react-native-elements';
|
||||
import { List, Button, ListItem } from 'react-native-elements';
|
||||
import {
|
||||
Divider,
|
||||
FormLabel,
|
||||
FormInput,
|
||||
Text,
|
||||
FormValidationMessage,
|
||||
} from 'react-native-elements';
|
||||
import QRCode from 'react-native-qrcode';
|
||||
import { BlueSpacing, BlueButton, SafeBlueArea, BlueCard, BlueText, BlueListItem, BlueHeader } from '../../BlueComponents'
|
||||
let EV = require('../../events')
|
||||
import {
|
||||
BlueSpacing,
|
||||
BlueButton,
|
||||
SafeBlueArea,
|
||||
BlueCard,
|
||||
BlueText,
|
||||
BlueListItem,
|
||||
BlueHeader,
|
||||
} from '../../BlueComponents';
|
||||
let EV = require('../../events');
|
||||
let BigNumber = require('bignumber.js');
|
||||
|
||||
export default class WalletExport extends Component {
|
||||
|
||||
static navigationOptions = {
|
||||
tabBarIcon: ({ tintColor, focused }) => (
|
||||
<Ionicons
|
||||
@ -22,40 +35,39 @@ export default class WalletExport extends Component {
|
||||
style={{ color: tintColor }}
|
||||
/>
|
||||
),
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
let address = props.navigation.state.params.address
|
||||
let wallet
|
||||
let address = props.navigation.state.params.address;
|
||||
let wallet;
|
||||
|
||||
for (let w of BlueApp.getWallets()){
|
||||
if (w.getAddress() === address) { // found our wallet
|
||||
wallet = w
|
||||
for (let w of BlueApp.getWallets()) {
|
||||
if (w.getAddress() === address) {
|
||||
// found our wallet
|
||||
wallet = w;
|
||||
}
|
||||
}
|
||||
|
||||
this.state = {
|
||||
isLoading: true,
|
||||
wallet
|
||||
}
|
||||
wallet,
|
||||
};
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
const {navigate} = this.props.navigation;
|
||||
const { navigate } = this.props.navigation;
|
||||
|
||||
if (this.state.isLoading) {
|
||||
return (
|
||||
<View style={{flex: 1, paddingTop: 20}}>
|
||||
<View style={{ flex: 1, paddingTop: 20 }}>
|
||||
<ActivityIndicator />
|
||||
</View>
|
||||
);
|
||||
@ -72,10 +84,12 @@ export default class WalletExport extends Component {
|
||||
*/
|
||||
|
||||
return (
|
||||
<SafeBlueArea style={{flex: 1, paddingTop: 20}}>
|
||||
<BlueSpacing/>
|
||||
<BlueCard title={"Wallet Export"} style={{alignItems: 'center', flex: 1}}>
|
||||
|
||||
<SafeBlueArea style={{ flex: 1, paddingTop: 20 }}>
|
||||
<BlueSpacing />
|
||||
<BlueCard
|
||||
title={'Wallet Export'}
|
||||
style={{ alignItems: 'center', flex: 1 }}
|
||||
>
|
||||
<BlueText>Address: {this.state.wallet.getAddress()}</BlueText>
|
||||
<BlueText>WIF: {this.state.wallet.getSecret()}</BlueText>
|
||||
|
||||
@ -83,22 +97,16 @@ export default class WalletExport extends Component {
|
||||
value={this.state.wallet.getSecret()}
|
||||
size={312}
|
||||
bgColor={'white'}
|
||||
fgColor={BlueApp.settings.brandingColor}/>
|
||||
fgColor={BlueApp.settings.brandingColor}
|
||||
/>
|
||||
</BlueCard>
|
||||
|
||||
<BlueButton
|
||||
icon={{name: 'arrow-left', type: 'octicon'}}
|
||||
onPress={() =>
|
||||
this.props.navigation.goBack()
|
||||
}
|
||||
icon={{ name: 'arrow-left', type: 'octicon' }}
|
||||
onPress={() => this.props.navigation.goBack()}
|
||||
title="Go back"
|
||||
/>
|
||||
|
||||
|
||||
|
||||
</SafeBlueArea>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,21 +1,33 @@
|
||||
/** @type {AppStorage} */
|
||||
let BlueApp = require('../../BlueApp')
|
||||
let BlueApp = require('../../BlueApp');
|
||||
import React, { Component } from 'react';
|
||||
import { ActivityIndicator, StyleSheet, ListView, Text, View } from 'react-native';
|
||||
import {
|
||||
ActivityIndicator,
|
||||
StyleSheet,
|
||||
ListView,
|
||||
Text,
|
||||
View,
|
||||
} from 'react-native';
|
||||
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||
import {
|
||||
BlueLoading, BlueSpacing20, BlueList, BlueButton, SafeBlueArea, BlueCard, BlueText, BlueListItem, BlueHeader,
|
||||
BlueFormInput, BlueSpacing
|
||||
} from '../../BlueComponents'
|
||||
import { Icon,Header, List, ListItem, Avatar } from 'react-native-elements'
|
||||
let EV = require('../../events')
|
||||
BlueLoading,
|
||||
BlueSpacing20,
|
||||
BlueList,
|
||||
BlueButton,
|
||||
SafeBlueArea,
|
||||
BlueCard,
|
||||
BlueText,
|
||||
BlueListItem,
|
||||
BlueHeader,
|
||||
BlueFormInput,
|
||||
BlueSpacing,
|
||||
} from '../../BlueComponents';
|
||||
import { Icon, Header, List, ListItem, Avatar } from 'react-native-elements';
|
||||
let EV = require('../../events');
|
||||
|
||||
|
||||
|
||||
let ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2,});
|
||||
let ds = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 });
|
||||
|
||||
export default class WalletsList extends Component {
|
||||
|
||||
static navigationOptions = {
|
||||
tabBarLabel: 'Wallets',
|
||||
tabBarIcon: ({ tintColor, focused }) => (
|
||||
@ -25,93 +37,103 @@ export default class WalletsList extends Component {
|
||||
style={{ color: tintColor }}
|
||||
/>
|
||||
),
|
||||
}
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
isLoading: true,
|
||||
}
|
||||
EV(EV.enum.WALLETS_COUNT_CHANGED, this.refreshFunction.bind(this))
|
||||
};
|
||||
EV(EV.enum.WALLETS_COUNT_CHANGED, this.refreshFunction.bind(this));
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
console.log('wallets/list - componentDidMount')
|
||||
this.refreshFunction()
|
||||
console.log('wallets/list - componentDidMount');
|
||||
this.refreshFunction();
|
||||
} // end of componendDidMount
|
||||
|
||||
refreshFunction () {
|
||||
this.setState({
|
||||
isLoading: true,
|
||||
}, () => {
|
||||
setTimeout(() => {
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
dataSource: ds.cloneWithRows(BlueApp.getWallets()),
|
||||
})
|
||||
}, 1)
|
||||
})
|
||||
refreshFunction() {
|
||||
this.setState(
|
||||
{
|
||||
isLoading: true,
|
||||
},
|
||||
() => {
|
||||
setTimeout(() => {
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
dataSource: ds.cloneWithRows(BlueApp.getWallets()),
|
||||
});
|
||||
}, 1);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
const {navigate} = this.props.navigation;
|
||||
const { navigate } = this.props.navigation;
|
||||
|
||||
if (this.state.isLoading) {
|
||||
return (
|
||||
<BlueLoading/>
|
||||
);
|
||||
return <BlueLoading />;
|
||||
}
|
||||
|
||||
return (
|
||||
<SafeBlueArea>
|
||||
<BlueHeader
|
||||
leftComponent={<Icon name='menu' color="#fff" onPress={() => this.props.navigation.navigate('DrawerToggle') }/>}
|
||||
centerComponent={{ text: 'Blue Wallet', style: { color: '#fff', fontSize: 25 }}}
|
||||
leftComponent={
|
||||
<Icon
|
||||
name="menu"
|
||||
color="#fff"
|
||||
onPress={() => this.props.navigation.navigate('DrawerToggle')}
|
||||
/>
|
||||
}
|
||||
centerComponent={{
|
||||
text: 'Blue Wallet',
|
||||
style: { color: '#fff', fontSize: 25 },
|
||||
}}
|
||||
/>
|
||||
<BlueCard title='My Bitcoin Wallets' >
|
||||
<BlueText style={{marginBottom: 10}}>
|
||||
A wallet represents a pair of a secret (private key) and an address you can share to receive coins.
|
||||
<BlueCard title="My Bitcoin Wallets">
|
||||
<BlueText style={{ marginBottom: 10 }}>
|
||||
A wallet represents a pair of a secret (private key) and an address
|
||||
you can share to receive coins.
|
||||
</BlueText>
|
||||
|
||||
<BlueList>
|
||||
<ListView
|
||||
enableEmptySections={true}
|
||||
enableEmptySections
|
||||
maxHeight={290}
|
||||
dataSource={this.state.dataSource}
|
||||
renderRow={(rowData) => {
|
||||
return (
|
||||
<BlueListItem
|
||||
onPress={() =>
|
||||
{
|
||||
navigate('WalletDetails', {address : rowData.getAddress()})
|
||||
}}
|
||||
leftIcon={{name: 'bitcoin', type: 'font-awesome', color: '#fff'}}
|
||||
|
||||
title={rowData.getLabel() + ' | ' + rowData.getBalance() + " BTC" }
|
||||
subtitle={rowData.getShortAddress()}
|
||||
hideChevron={false}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
renderRow={rowData => {
|
||||
return (
|
||||
<BlueListItem
|
||||
onPress={() => {
|
||||
navigate('WalletDetails', {
|
||||
address: rowData.getAddress(),
|
||||
});
|
||||
}}
|
||||
leftIcon={{
|
||||
name: 'bitcoin',
|
||||
type: 'font-awesome',
|
||||
color: '#fff',
|
||||
}}
|
||||
title={
|
||||
rowData.getLabel() + ' | ' + rowData.getBalance() + ' BTC'
|
||||
}
|
||||
subtitle={rowData.getShortAddress()}
|
||||
hideChevron={false}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</BlueList>
|
||||
</BlueList>
|
||||
</BlueCard>
|
||||
|
||||
|
||||
|
||||
<BlueButton
|
||||
icon={{name: 'plus-small', type: 'octicon'}}
|
||||
icon={{ name: 'plus-small', type: 'octicon' }}
|
||||
onPress={() => {
|
||||
navigate('AddWallet')
|
||||
navigate('AddWallet');
|
||||
}}
|
||||
title="Add Wallet"
|
||||
/>
|
||||
|
||||
|
||||
|
||||
</SafeBlueArea>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,18 @@
|
||||
let BlueApp = require('../../BlueApp')
|
||||
let BlueApp = require('../../BlueApp');
|
||||
import React from 'react';
|
||||
import { Text, ActivityIndicator, Button, View, TouchableOpacity } from 'react-native';
|
||||
import {
|
||||
Text,
|
||||
ActivityIndicator,
|
||||
Button,
|
||||
View,
|
||||
TouchableOpacity,
|
||||
} from 'react-native';
|
||||
import { Camera, Permissions } from 'expo';
|
||||
import { AppStorage, LegacyWallet } from '../../class'
|
||||
import { AppStorage, LegacyWallet } from '../../class';
|
||||
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||
let EV = require('../../events')
|
||||
let EV = require('../../events');
|
||||
|
||||
export default class CameraExample extends React.Component {
|
||||
|
||||
static navigationOptions = {
|
||||
tabBarLabel: 'Wallets',
|
||||
tabBarIcon: ({ tintColor, focused }) => (
|
||||
@ -17,46 +22,52 @@ export default class CameraExample extends React.Component {
|
||||
style={{ color: tintColor }}
|
||||
/>
|
||||
),
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
state = {
|
||||
isLoading : false,
|
||||
isLoading: false,
|
||||
hasCameraPermission: null,
|
||||
type: Camera.Constants.Type.back,
|
||||
};
|
||||
|
||||
async onBarCodeRead (ret) {
|
||||
for (let w of BlueApp.wallets) { // lookig for duplicates
|
||||
async onBarCodeRead(ret) {
|
||||
for (let w of BlueApp.wallets) {
|
||||
// lookig for duplicates
|
||||
if (w.getSecret() === ret.data) {
|
||||
return // duplicate, not adding
|
||||
return; // duplicate, not adding
|
||||
}
|
||||
}
|
||||
|
||||
let newWallet = new LegacyWallet()
|
||||
newWallet.setSecret(ret.data)
|
||||
let newWallet = new LegacyWallet();
|
||||
newWallet.setSecret(ret.data);
|
||||
|
||||
if (newWallet.getAddress() === false) return; // bad WIF
|
||||
|
||||
|
||||
|
||||
this.setState({
|
||||
isLoading: true
|
||||
}, async () => {
|
||||
newWallet.setLabel('NEW2')
|
||||
BlueApp.wallets.push(newWallet)
|
||||
await BlueApp.saveToDisk()
|
||||
this.props.navigation.navigate('WalletsList')
|
||||
EV(EV.enum.WALLETS_COUNT_CHANGED)
|
||||
alert('Imported WIF ' + ret.data + ' with address ' + newWallet.getAddress())
|
||||
})
|
||||
this.setState(
|
||||
{
|
||||
isLoading: true,
|
||||
},
|
||||
async () => {
|
||||
newWallet.setLabel('NEW2');
|
||||
BlueApp.wallets.push(newWallet);
|
||||
await BlueApp.saveToDisk();
|
||||
this.props.navigation.navigate('WalletsList');
|
||||
EV(EV.enum.WALLETS_COUNT_CHANGED);
|
||||
alert(
|
||||
'Imported WIF ' +
|
||||
ret.data +
|
||||
' with address ' +
|
||||
newWallet.getAddress(),
|
||||
);
|
||||
},
|
||||
);
|
||||
} // end
|
||||
|
||||
async componentWillMount() {
|
||||
const { status } = await Permissions.askAsync(Permissions.CAMERA);
|
||||
this.setState({
|
||||
hasCameraPermission: status === 'granted',
|
||||
onCameraReady: function () {
|
||||
onCameraReady: function() {
|
||||
alert('onCameraReady');
|
||||
},
|
||||
barCodeTypes: [Camera.Constants.BarCodeType.qr],
|
||||
@ -64,10 +75,9 @@ export default class CameraExample extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
if (this.state.isLoading) {
|
||||
return (
|
||||
<View style={{flex: 1, paddingTop: 20}}>
|
||||
<View style={{ flex: 1, paddingTop: 20 }}>
|
||||
<ActivityIndicator />
|
||||
</View>
|
||||
);
|
||||
@ -81,14 +91,18 @@ export default class CameraExample extends React.Component {
|
||||
} else {
|
||||
return (
|
||||
<View style={{ flex: 1 }}>
|
||||
<Camera style={{ flex: 1 }} type={this.state.type}
|
||||
onBarCodeRead={this.onBarCodeRead.bind(this)}>
|
||||
<Camera
|
||||
style={{ flex: 1 }}
|
||||
type={this.state.type}
|
||||
onBarCodeRead={this.onBarCodeRead.bind(this)}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
backgroundColor: 'transparent',
|
||||
flexDirection: 'row',
|
||||
}}>
|
||||
}}
|
||||
>
|
||||
<TouchableOpacity
|
||||
style={{
|
||||
flex: 0.2,
|
||||
@ -97,17 +111,17 @@ export default class CameraExample extends React.Component {
|
||||
}}
|
||||
onPress={() => {
|
||||
this.setState({
|
||||
type: this.state.type === Camera.Constants.Type.back
|
||||
? Camera.Constants.Type.front
|
||||
: Camera.Constants.Type.back,
|
||||
type:
|
||||
this.state.type === Camera.Constants.Type.back
|
||||
? Camera.Constants.Type.front
|
||||
: Camera.Constants.Type.back,
|
||||
});
|
||||
}}>
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
style={{ fontSize: 18, marginBottom: 10 }}
|
||||
title='Go back'
|
||||
onPress={() =>
|
||||
this.props.navigation.goBack()
|
||||
}
|
||||
title="Go back"
|
||||
onPress={() => this.props.navigation.goBack()}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
@ -116,4 +130,4 @@ export default class CameraExample extends React.Component {
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,18 @@
|
||||
let BlueApp = require('../../BlueApp')
|
||||
let BlueApp = require('../../BlueApp');
|
||||
import React from 'react';
|
||||
import { Text, ActivityIndicator, Button, View, TouchableOpacity } from 'react-native';
|
||||
import {
|
||||
Text,
|
||||
ActivityIndicator,
|
||||
Button,
|
||||
View,
|
||||
TouchableOpacity,
|
||||
} from 'react-native';
|
||||
import { Camera, Permissions } from 'expo';
|
||||
import { AppStorage, LegacyWallet, SegwitP2SHWallet } from '../../class'
|
||||
import { AppStorage, LegacyWallet, SegwitP2SHWallet } from '../../class';
|
||||
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||
let EV = require('../../events')
|
||||
let EV = require('../../events');
|
||||
|
||||
export default class CameraExample extends React.Component {
|
||||
|
||||
static navigationOptions = {
|
||||
tabBarLabel: 'Wallets',
|
||||
tabBarIcon: ({ tintColor, focused }) => (
|
||||
@ -17,44 +22,52 @@ export default class CameraExample extends React.Component {
|
||||
style={{ color: tintColor }}
|
||||
/>
|
||||
),
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
state = {
|
||||
isLoading : false,
|
||||
isLoading: false,
|
||||
hasCameraPermission: null,
|
||||
type: Camera.Constants.Type.back,
|
||||
};
|
||||
|
||||
async onBarCodeRead (ret) {
|
||||
for (let w of BlueApp.wallets) { // lookig for duplicates
|
||||
async onBarCodeRead(ret) {
|
||||
for (let w of BlueApp.wallets) {
|
||||
// lookig for duplicates
|
||||
if (w.getSecret() === ret.data) {
|
||||
return // duplicate, not adding
|
||||
return; // duplicate, not adding
|
||||
}
|
||||
}
|
||||
|
||||
let newWallet = new SegwitP2SHWallet()
|
||||
newWallet.setSecret(ret.data)
|
||||
let newWallet = new SegwitP2SHWallet();
|
||||
newWallet.setSecret(ret.data);
|
||||
|
||||
if (newWallet.getAddress() === false) return; // bad WIF
|
||||
|
||||
this.setState({
|
||||
isLoading: true
|
||||
}, async () => {
|
||||
newWallet.setLabel('New SegWit')
|
||||
BlueApp.wallets.push(newWallet)
|
||||
await BlueApp.saveToDisk()
|
||||
this.props.navigation.navigate('WalletsList')
|
||||
EV(EV.enum.WALLETS_COUNT_CHANGED)
|
||||
alert('Imported WIF ' + ret.data + ' with address ' + newWallet.getAddress())
|
||||
})
|
||||
this.setState(
|
||||
{
|
||||
isLoading: true,
|
||||
},
|
||||
async () => {
|
||||
newWallet.setLabel('New SegWit');
|
||||
BlueApp.wallets.push(newWallet);
|
||||
await BlueApp.saveToDisk();
|
||||
this.props.navigation.navigate('WalletsList');
|
||||
EV(EV.enum.WALLETS_COUNT_CHANGED);
|
||||
alert(
|
||||
'Imported WIF ' +
|
||||
ret.data +
|
||||
' with address ' +
|
||||
newWallet.getAddress(),
|
||||
);
|
||||
},
|
||||
);
|
||||
} // end
|
||||
|
||||
async componentWillMount() {
|
||||
const { status } = await Permissions.askAsync(Permissions.CAMERA);
|
||||
this.setState({
|
||||
hasCameraPermission: status === 'granted',
|
||||
onCameraReady: function () {
|
||||
onCameraReady: function() {
|
||||
alert('onCameraReady');
|
||||
},
|
||||
barCodeTypes: [Camera.Constants.BarCodeType.qr],
|
||||
@ -62,10 +75,9 @@ export default class CameraExample extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
if (this.state.isLoading) {
|
||||
return (
|
||||
<View style={{flex: 1, paddingTop: 20}}>
|
||||
<View style={{ flex: 1, paddingTop: 20 }}>
|
||||
<ActivityIndicator />
|
||||
</View>
|
||||
);
|
||||
@ -79,14 +91,18 @@ export default class CameraExample extends React.Component {
|
||||
} else {
|
||||
return (
|
||||
<View style={{ flex: 1 }}>
|
||||
<Camera style={{ flex: 1 }} type={this.state.type}
|
||||
onBarCodeRead={this.onBarCodeRead.bind(this)}>
|
||||
<Camera
|
||||
style={{ flex: 1 }}
|
||||
type={this.state.type}
|
||||
onBarCodeRead={this.onBarCodeRead.bind(this)}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
backgroundColor: 'transparent',
|
||||
flexDirection: 'row',
|
||||
}}>
|
||||
}}
|
||||
>
|
||||
<TouchableOpacity
|
||||
style={{
|
||||
flex: 0.2,
|
||||
@ -95,17 +111,17 @@ export default class CameraExample extends React.Component {
|
||||
}}
|
||||
onPress={() => {
|
||||
this.setState({
|
||||
type: this.state.type === Camera.Constants.Type.back
|
||||
? Camera.Constants.Type.front
|
||||
: Camera.Constants.Type.back,
|
||||
type:
|
||||
this.state.type === Camera.Constants.Type.back
|
||||
? Camera.Constants.Type.front
|
||||
: Camera.Constants.Type.back,
|
||||
});
|
||||
}}>
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
style={{ fontSize: 18, marginBottom: 10 }}
|
||||
title='Go back'
|
||||
onPress={() =>
|
||||
this.props.navigation.goBack()
|
||||
}
|
||||
title="Go back"
|
||||
onPress={() => this.props.navigation.goBack()}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
@ -114,4 +130,4 @@ export default class CameraExample extends React.Component {
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
20
shim.js
20
shim.js
@ -1,23 +1,23 @@
|
||||
/* global __DEV__, localStorage */
|
||||
if (typeof __dirname === 'undefined') global.__dirname = '/'
|
||||
if (typeof __filename === 'undefined') global.__filename = ''
|
||||
if (typeof __dirname === 'undefined') global.__dirname = '/';
|
||||
if (typeof __filename === 'undefined') global.__filename = '';
|
||||
if (typeof process === 'undefined') {
|
||||
global.process = require('process')
|
||||
global.process = require('process');
|
||||
} else {
|
||||
const bProcess = require('process')
|
||||
const bProcess = require('process');
|
||||
for (var p in bProcess) {
|
||||
if (!(p in process)) {
|
||||
process[p] = bProcess[p]
|
||||
process[p] = bProcess[p];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
process.browser = false
|
||||
if (typeof Buffer === 'undefined') global.Buffer = require('buffer').Buffer
|
||||
process.browser = false;
|
||||
if (typeof Buffer === 'undefined') global.Buffer = require('buffer').Buffer;
|
||||
|
||||
// global.location = global.location || { port: 80 }
|
||||
const isDev = typeof __DEV__ === 'boolean' && __DEV__
|
||||
process.env['NODE_ENV'] = isDev ? 'development' : 'production'
|
||||
const isDev = typeof __DEV__ === 'boolean' && __DEV__;
|
||||
process.env['NODE_ENV'] = isDev ? 'development' : 'production';
|
||||
if (typeof localStorage !== 'undefined') {
|
||||
localStorage.debug = isDev ? '*' : ''
|
||||
localStorage.debug = isDev ? '*' : '';
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user