diff --git a/App.js b/App.js
index 66013ed..c1e6ccc 100644
--- a/App.js
+++ b/App.js
@@ -15,7 +15,7 @@ import {
import { createAppContainer, createMaterialTopTabNavigator, createStackNavigator } from 'react-navigation';
import Apps, {Foam, Fork, Mintbase, Test} from './src/Apps'
import CameraScreen from './src/AliceCore/Screens/Camera';
-import Profile from './src/AliceCore/Screens/Profile';
+import Tokens from './src/AliceCore/Screens/Tokens';
import MapboxGL from '@react-native-mapbox-gl/maps';
MapboxGL.setAccessToken('pk.eyJ1IjoibWFya3BlcmVpciIsImEiOiJjancwNDg4eWswNzk1NGJ0Z3V5OGtxZWltIn0.gZ7ev6fQETAFa4J9kao10w');
//TODO: change API key on release to TestFlight
@@ -64,8 +64,8 @@ const AppTabNavigator = createMaterialTopTabNavigator({
)
}
},
- Profile: {
- screen: Profile,
+ Tokens: {
+ screen: Tokens,
navigationOptions: {
tabBarLabel: 'Settings',
tabBarIcon: ({ focused }) => (
@@ -86,8 +86,8 @@ const AppTabNavigator = createMaterialTopTabNavigator({
}
}
}, {
- initialRouteName: 'Profile',
- order: ['Home', 'Apps', 'Profile', 'Activity'],
+ initialRouteName: 'Tokens',
+ order: ['Home', 'Apps', 'Tokens', 'Activity'],
tabBarPosition: 'bottom',
animationEnabled: true,
tabBarOptions: {
diff --git a/EmbeddedView.js b/EmbeddedView.js
index 0a483ab..2f33e42 100644
--- a/EmbeddedView.js
+++ b/EmbeddedView.js
@@ -10,6 +10,7 @@ export default class SimpleView extends React.Component{
return (
{this.props.children}
+ TEST
);
}
diff --git a/ios b/ios
index 4dd9a5a..fcfa1ee 160000
--- a/ios
+++ b/ios
@@ -1 +1 @@
-Subproject commit 4dd9a5a448778c375b023ff0b20c6059b1da84a3
+Subproject commit fcfa1eea2c59139d19ea3629617edc601c639395
diff --git a/src/AliceComponents/TransactionModal/CameraModal.js b/src/AliceComponents/TransactionModal/CameraModal.js
new file mode 100644
index 0000000..bb11c3f
--- /dev/null
+++ b/src/AliceComponents/TransactionModal/CameraModal.js
@@ -0,0 +1,113 @@
+'use strict';
+
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+import {View, StyleSheet, TouchableOpacity, Text} from 'react-native'
+import Modal from "react-native-modal";
+import Camera from "../../AliceSDK/Camera";
+import ReactNativeHaptic from 'react-native-haptic-feedback';
+import _ from "lodash";
+// const Web3 = require('web3');
+// const web3 = new Web3();
+// web3.setProvider(new web3.providers.HttpProvider('https://ropsten.infura.io/rqmgop6P5BDFqz6yfGla'));
+// const privKey = 'cf06f0b35515af10b5dfef470e3a1e743470bf9033d06f198b4e829cb2e7ef05';
+
+export default class CameraModal extends Component {
+ static propTypes = {
+ visible: PropTypes.bool,
+ modalControl: PropTypes.func
+ };
+
+ static defaultProps = {
+ screen: false
+ };
+
+ constructor(props) {
+ super(props);
+ this.camera = null;
+ this.state = {
+ exchangeRate: 0,
+ account: 'alpha',
+ visibleModal: null,
+ publicAddress: '',
+ txCount: 0,
+ balance: 0,
+ privKey: false,
+ pubKey: false,
+ mode: 'loading',
+ transaction: null,
+ result: null,
+ signedTx: null,
+ phoneUid: '',
+ showInput: false,
+ socketId: '',
+ cameraType: 'back',
+ flash: false,
+ };
+ }
+
+ // _signKey = async (msg, socketId) => {
+ // // ReactNativeHaptic.generate('selection');
+ // const account = await web3.eth.accounts.privateKeyToAccount(privKey)
+ // .sign(msg);
+ //
+ // console.log('PHONE ID: ', this.state.phoneUid);
+ // fetch(`https://login.tenzorum.app/login/${socketId}/${this.state.phoneUid}/${msg}/${account.signature}`)
+ // .then((res) => {
+ // console.log('RES: ', res)
+ // })
+ // };
+ //
+ _onBarcodeRead = (read) => {
+ if (read) {
+ console.log('READ PUBLIC ADDRESS', read.data)
+ this.props.addressScan(read.data)
+ this.props.modalControl();
+ // const dataArray = read.data.split('.');
+ // TouchID.authenticate('verify user')
+ // .then(success => {
+ // this._signKey(dataArray[0], dataArray[1]);
+ // this.setState({socketId: dataArray[1]})
+ // })
+ // .catch(error => {
+ // console.log('ERROR: ', error);
+ // });
+ }
+ };
+
+ render () {
+ return (
+
+
+
+ x
+
+
+ )
+ }
+}
+
+const styles = StyleSheet.create({
+ modal: {
+ width: 250,
+ height: 250,
+ borderRadius: 15,
+ backgroundColor: 'white',
+ padding: 10,
+ alignItems: 'center',
+ justifyContent: 'center'
+ },
+ rectangleContainer: {
+ flex: 1,
+ alignItems: 'center',
+ justifyContent: 'center',
+ backgroundColor: 'transparent'
+ }
+ })
+
+
diff --git a/src/AliceComponents/TransactionModal/Input.js b/src/AliceComponents/TransactionModal/Input.js
new file mode 100644
index 0000000..278e8b9
--- /dev/null
+++ b/src/AliceComponents/TransactionModal/Input.js
@@ -0,0 +1,88 @@
+import React, { Component } from 'react';
+import {
+ AlertIOS,
+ AppRegistry,
+ Dimensions,
+ Image,
+ ScrollView,
+ StyleSheet,
+ Text,
+ TextInput,
+ TouchableOpacity,
+ View,
+} from 'react-native';
+
+
+let {height, width} = Dimensions.get('window');
+
+export default class Input extends Component {
+ constructor() {
+ super();
+ this.state = {
+ visibleModal: null
+ };
+ }
+
+ render() {
+ const {} = this.state;
+ const {onChangeText, _this, placeholder, keyboardType, autoCapitalize, value} = this.props;
+ return (
+
+
+
+ )
+ }
+}
+
+
+const styles = StyleSheet.create({
+ inputContainer: {
+ width: '100%',
+ height: 40,
+ borderRadius: 10,
+ backgroundColor: '#ccc',
+ },
+ input: {
+ flex: 1,
+ backgroundColor: 'transparent',
+ // borderColor: '#ccc',
+ // borderWidth: 1,
+ // borderRadius: 10,
+ paddingLeft: 4,
+ overflow: 'hidden',
+ // shadowColor: 'rgba(0,0,0,0.5)',
+ // shadowRadius: 1,
+ // shadowOpacity: 1,
+ // shadowOffset: {
+ // width: 0,
+ // height: 0
+ // },
+ },
+ inputStyle: {
+ marginLeft: 10,
+ backgroundColor: "transparent",
+ height: 35,
+ width: '100%',
+ padding: 5,
+ fontWeight: '900',
+ fontSize: 20,
+ color: '#333',
+ },
+ topNavText: {
+ fontFamily: 'DIN Condensed',
+ color: 'white',
+ fontSize: 16,
+ },
+});
+
diff --git a/src/AliceComponents/TransactionModal/QrModal.js b/src/AliceComponents/TransactionModal/QrModal.js
new file mode 100644
index 0000000..7978a71
--- /dev/null
+++ b/src/AliceComponents/TransactionModal/QrModal.js
@@ -0,0 +1,56 @@
+'use strict';
+
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+import {
+ Clipboard,
+ StyleSheet,
+ Text,
+ TouchableOpacity
+} from 'react-native'
+import QRCode from 'react-native-qrcode-svg'
+import Modal from 'react-native-modal'
+
+export default class QrModal extends Component {
+ static propTypes = {
+ value: PropTypes.string.isRequired,
+ isVisible: PropTypes.bool,
+ };
+
+ static defaultProps = {
+ screen: false
+ };
+
+ render () {
+ return (
+
+ Clipboard.setString(this.props.value)} style={styles.modal}>
+
+ {this.props.value}
+
+
+ x
+
+
+
+ )
+ }
+}
+
+const styles = StyleSheet.create({
+ modal: {
+ width: 250,
+ height: 350,
+ borderRadius: 15,
+ backgroundColor: 'white',
+ padding: 10,
+ alignItems: 'center',
+ justifyContent: 'center'
+ },
+ rectangleContainer: {
+ flex: 1,
+ alignItems: 'center',
+ justifyContent: 'center',
+ backgroundColor: 'transparent'
+ }
+})
diff --git a/src/AliceComponents/TransactionModal/index.js b/src/AliceComponents/TransactionModal/index.js
new file mode 100644
index 0000000..0f2edfc
--- /dev/null
+++ b/src/AliceComponents/TransactionModal/index.js
@@ -0,0 +1,325 @@
+import React, { Component } from 'react';
+import {
+ Alert,
+ AppRegistry,
+ Clipboard,
+ StyleSheet,
+ Text,
+ View,
+ Image,
+ Dimensions,
+ KeyboardAvoidingView,
+ Keyboard,
+ ScrollView,
+ TouchableOpacity,
+ Platform,
+ TouchableWithoutFeedback,
+} from 'react-native';
+
+import Modal from 'react-native-modal';
+// import FeatherIcon from 'react-native-vector-icons/Feather'
+// import MaterialCommIcon from "react-native-vector-icons/MaterialCommunityIcons";
+// import { RoundButton } from 'react-native-button-component';
+// import * as Animatable from 'react-native-animatable';
+//
+// const Web3 = require('web3');
+// const web3 = new Web3();
+// web3.setProvider(new web3.providers.HttpProvider('https://ropsten.infura.io/'));
+
+import Input from './Input'
+import {color} from "../../AliceUtils/themes";
+import {addressResolver, checkSubdomainOwner, newSubdomain} from "../../AliceUtils/ensFunctions";
+
+// import QrModal from './QrModal';
+import CameraModal from './CameraModal';
+import {shadow, text} from "../../AliceUtils/themes";
+import {navigate} from "../../AliceUtils/navigationWrapper";
+
+const personalWalletAddress = "0xf8894138aa4d7b54b7d49afa9d5600cdb5178721";
+
+const emptyAddress = '0x0000000000000000000000000000000000000000';
+
+const publicAddress = "0xb78197a43836e084bE4ff1F4c84d7557EA11F214";
+
+// import { transferEtherNoReward, transferTokensNoReward, transferTokensWithTokenReward, transferEtherWithEtherReward } from 'tenzorum'
+import {Wallet} from "../../AliceSDK";
+// import {getBalance, getTenzBalance} from "../../utils/ether";
+
+
+const cryptoCurrencies = [
+ { name: 'Tenzorum', symbol: 'TENZ', abi: [], imageUrl: require('../../AliceAssets/localethereum.png'), type: "token", balance: 0, address: "0xB07C36074b8333B01e38A307df804FDc6c37e0eC", },
+ { name: 'Ethereum', symbol: 'ETH', abi: [], imageUrl: require('../../AliceAssets/localethereum.png'), type: "cryptoCurrency", balance: '0', },
+ { name: 'DAI', symbol: 'DAI', abi: [], imageUrl: require('../../AliceAssets/localethereum.png'), type: "token", balance: 52, },
+ { name: 'FOAM', symbol: 'FOAM', abi: [], imageUrl: require('../../AliceAssets/localethereum.png'), type: "token", balance: 1000, },
+ { name: 'Akropolis', symbol: 'AKR', abi: [], imageUrl: require('../../AliceAssets/localethereum.png'), type: "token", balance: 0, },
+];
+
+let {height, width} = Dimensions.get('window');
+
+type Props = {};
+export default class TransactionModal extends Component {
+ constructor(props){
+ super(props);
+ this.state = {
+ buttonState: 'upload',
+ cryptoBalance: '',
+ ensDomain: '',
+ ensAvailable: false,
+ publicAddress: '',
+ ensMessage: 'Enter a public address or ENS username',
+ addressChecked: false,
+ cameraModalVisible: false,
+ qrModalVisible: false,
+ currentCrypto: { name: 'Select Currency' },
+ tenzBalance: 2,
+ ethBalance: 0,
+ amount: '',
+ reward: '',
+ }
+ }
+
+ handleTextRef = ref => this.text = ref;
+
+ async componentDidMount() {
+ this.setState({publicAddress: await Wallet.getAddress()});
+ Wallet.getBalance().then(bal => this.setState({ethBalance: bal}));
+ }
+
+ _navigateToWebView = (uri) => {
+ uri = uri || '0x08b79a6a11624e666d21420e9a2bdcdbf9ecfb43b4537e346bf8b35530f0750e';
+ this.setState({ buttonState: 'upload' });
+ navigate('WebView', {uri: 'https://ropsten.etherscan.io/search?q='+uri})
+ this.props.modalControl();
+ };
+
+ // _sendTransaction = async () => {
+ // const {reward, amount, currentCrypto, publicAddress} = this.state;
+ // let response;
+ // Keyboard.dismiss();
+ // try {
+ // if (currentCrypto.type === "token") {
+ // if (reward) {
+ // response = await transferTokensWithTokenReward(currentCrypto.address, web3.utils.toWei(amount, "ether"), publicAddress, web3.utils.toWei(reward, "ether"));
+ // console.log('PAYLOAD: ', response);
+ // } else {
+ // response = await transferTokensNoReward(currentCrypto.address, web3.utils.toWei(amount, "ether"), publicAddress);
+ // console.log('PAYLOAD: ', response);
+ // }
+ // } else if (currentCrypto.type === "cryptoCurrency") {
+ // if (reward) {
+ // response = await transferEtherWithEtherReward(web3.utils.toWei(amount, "ether"), publicAddress, web3.utils.toWei(reward, "ether"));
+ // console.log('PAYLOAD: ', response);
+ // } else {
+ // response = await transferEtherNoReward(web3.utils.toWei(amount, "ether"), publicAddress);
+ // console.log('PAYLOAD: ', response);
+ // }
+ // } else {
+ // console.log("set currency")
+ // }
+ // if (response.txHash) {
+ // this.setState({ buttonState: 'success' })
+ // Alert.alert(
+ // 'Transaction Submitted',
+ // 'View on etherscan?',
+ // [
+ // {text: 'View', onPress: () => this._navigateToWebView(response.txHash)},
+ // {text: 'Close', onPress: () => this.props.modalControl(), style: 'cancel'},
+ // ],
+ // { cancelable: false }
+ // )
+ // }
+ // return response;
+ //
+ // } catch(e) {
+ // this.setState({ buttonState: 'upload' })
+ // console.log("Unable to make token transfer with no reward")
+ // }
+ // };
+
+ _resolveAddress = async (ensUsername) => {
+ const {publicAddress} = this.state;
+ this.setState({addressChecked: true});
+ if (ensUsername.length === 0) {
+ this.setState({ensAvailable: false, ensMessage: 'Enter a valid or unempty username'});
+ } else if (true === true) {
+ if (ensUsername === emptyAddress) {
+ this.setState({ensAvailable: false, ensMessage: 'Invalid address'});
+ } else if(ensUsername === publicAddress) {
+ this.setState({ensAvailable: true, ensMessage: "It's your domain!"});
+ } else {
+ console.log(this.state.publicAddress)
+ this.setState({publicAddress: ensUsername});
+ this.setState({ensAvailable: true, ensMessage: "Valid address: " + ensUsername});
+ }
+ return ensUsername;
+
+ } else {
+ this.setState({ensDomain: ensUsername});
+ const {ensDomain} = this.state;
+ const addr = await addressResolver(ensUsername);
+ this.setState({publicAddress: addr});
+ if (addr === emptyAddress) {
+ this.setState({ensAvailable: false, ensMessage: 'Invalid address'});
+ } else if(addr === publicAddress) {
+ this.setState({ensAvailable: true, ensMessage: "It's your domain!"});
+ } else {
+ this.setState({ensAvailable: true, ensMessage: "Valid address: " + this.state.publicAddress});
+ }
+ return addr;
+ }
+
+ };
+
+ _chooseBalance = (crypto) => {
+ switch(crypto) {
+ case "Tenzorum":
+ return this.state.tenzBalance;
+ case "Ethereum":
+ return this.state.ethBalance;
+ default:
+ return;
+ }
+ };
+
+ _addressScan = async (address) => {
+ const resolve = await this._resolveAddress(address);
+ if (resolve) this.setState({publicAddress: address, ensDomain: address});
+ }
+
+ render() {
+ const { ensDomain, ensAvailable, ensMessage, cameraModalVisible, qrModalVisible, reward, amount } = this.state;
+ const { isVisible } = this.props;
+ return (
+
+
+
+
+ x
+
+
+
+
+
+ {cryptoCurrencies.map((currency, key) => {
+ let amount = this._chooseBalance(currency.name);
+ const {imageUrl, balance} = currency;
+ let selectStyle = this.state.selected === key ? {backgroundColor: '#cbc7ef'} : {};
+ return ( this.setState({currentCrypto: currency, selected: key})}>
+ {amount || balance}
+ {currency.symbol}
+
+ )
+ })}
+
+ {this.state.currentCrypto.name}
+
+
+
+ this.setState({cameraModalVisible: !cameraModalVisible})} style={styles.squareButton}>
+
+
+
+
+
+ {ensMessage}
+
+
+
+ this.setState({amount})} autoCapitalize="none" value={amount}/>
+
+
+
+ this.setState({reward})} autoCapitalize="none" value={reward}/>
+
+
+
+
+ this.setState({cameraModalVisible: false})} addressScan={this._addressScan}/>
+
+ )
+ }
+}
+
+
+const styles = StyleSheet.create({
+ mainContainer: {
+ backgroundColor: color.component,
+ borderRadius: 10,
+ height: 160,
+ padding: 20,
+ width: width - 40,
+ },
+ closeButtonContainer: {
+ flexDirection: 'row',
+ alignItems: 'flex-end',
+ justifyContent: 'flex-end',
+ width: width-50,
+ height: 60,
+ },
+ button: {
+ height: 40,
+ width: 40,
+ borderRadius: 10,
+ marginBottom: 10,
+ alignItems: 'center',
+ justifyContent: 'center',
+ backgroundColor: 'rgba(0,0,0,0.5)'
+ },
+ actionButtonIcon: {
+ fontSize: 20,
+ height: 22,
+ color: 'white',
+ },
+ container: {
+ flex: 1,
+ padding: 20,
+ backgroundColor: '#d3e4ee',
+ },
+ cryptoBox: {
+ width: 80,
+ alignItems: 'center',
+ justifyContent: 'space-around',
+ height: 120,
+ borderRadius: 15,
+ backgroundColor: 'white',
+ marginLeft: 10,
+ ...shadow
+ },
+ header: {
+ height: 100,
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'space-between',
+ },
+ inputAndButton: {
+ flexDirection: 'row',
+ width: 265,
+ },
+ sendButton: {
+ marginLeft: 10,
+ borderRadius: 10,
+ height: 40,
+ width: 80,
+ backgroundColor: '#a25cee',
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ squareButton: {
+ marginLeft: 10,
+ borderRadius: 10,
+ height: 40,
+ width: 40,
+ backgroundColor: '#3f69ee',
+ alignItems: 'center',
+ justifyContent: 'center',
+ ...shadow
+ },
+ transactionBox: {
+ width: width - 40,
+ height: 410,
+ padding: 10,
+ borderRadius: 15,
+ backgroundColor: 'white',
+ ...shadow
+ },
+});
diff --git a/src/AliceCore/Screens/Activity.js b/src/AliceCore/Screens/Activity.js
index aa4182b..134a3c9 100644
--- a/src/AliceCore/Screens/Activity.js
+++ b/src/AliceCore/Screens/Activity.js
@@ -31,54 +31,55 @@ export default class ActivityClass extends Component {
}
getTokenInfo = async () => {
- // let activity;
- // try {
- // activity = await ThreeBoxActivity.get('0xA1b02d8c67b0FDCF4E379855868DeB470E169cfB');
- // const categorizedActivity = await addDataType(activity);
- // let feed = categorizedActivity.internal
- // .concat(categorizedActivity.txs)
- // .concat(categorizedActivity.token);
- // // if timestamp is undefined, give it the timestamp of the previous entry
- // feed.map((item, i) => {
- // const feedItem = item;
- // if (!feedItem.timeStamp) {
- // const deletedTime = parseInt(feed[i - 1].timeStamp, 10) + 1;
- // feedItem.timeStamp = deletedTime.toString();
- // }
- // return feedItem;
- // });
- //
- // // order feed chronologically
- // feed.sort((a, b) => b.timeStamp - a.timeStamp);
- //
- // // order feed by address
- // let feedByAddress = [];
- // feed.forEach((item) => {
- // // group feed by 3box or counterparty address activity
- // if (feedByAddress.length > 0 &&
- // Object.keys(feedByAddress[feedByAddress.length - 1])[0] === othersAddress) {
- // feedByAddress[feedByAddress.length - 1][othersAddress].push(item);
- // } else if (feedByAddress.length > 0 && Object.keys(feedByAddress[feedByAddress.length - 1])[0] === 'threeBox' && !item.spaceName && (item.dataType === 'Public' || item.dataType === 'Private')) {
- // feedByAddress[feedByAddress.length - 1].threeBox.push(item);
- // } else if (feedByAddress.length > 0 && Object.keys(feedByAddress[feedByAddress.length - 1])[0] === item.spaceName) {
- // feedByAddress[feedByAddress.length - 1][item.spaceName].push(item);
- // } else if (item.spaceName) {
- // feedByAddress.push({
- // [item.spaceName]: [item],
- // });
- // } else if ((item.dataType === 'Public' || item.dataType === 'Private') && !item.spaceName) {
- // feedByAddress.push({
- // threeBox: [item],
- // });
- // } else {
- // console.log('meh others address')
- // }
- // });
- //
- // this.setState({activity, fetching: false, categorizedActivity, feed});
- // } catch(e) {
- // console.log('ACTIVITY ERROR: ', e);
- // }
+ let activity;
+ try {
+ activity = await ThreeBoxActivity.get('0xA1b02d8c67b0FDCF4E379855868DeB470E169cfB');
+ console.log('ACTIVITY: ', activity)
+ const categorizedActivity = await addDataType(activity);
+ let feed = categorizedActivity.internal
+ .concat(categorizedActivity.txs)
+ .concat(categorizedActivity.token);
+ // if timestamp is undefined, give it the timestamp of the previous entry
+ feed.map((item, i) => {
+ const feedItem = item;
+ if (!feedItem.timeStamp) {
+ const deletedTime = parseInt(feed[i - 1].timeStamp, 10) + 1;
+ feedItem.timeStamp = deletedTime.toString();
+ }
+ return feedItem;
+ });
+
+ // order feed chronologically
+ feed.sort((a, b) => b.timeStamp - a.timeStamp);
+
+ // order feed by address
+ let feedByAddress = [];
+ feed.forEach((item) => {
+ // group feed by 3box or counterparty address activity
+ if (feedByAddress.length > 0 &&
+ Object.keys(feedByAddress[feedByAddress.length - 1])[0] === othersAddress) {
+ feedByAddress[feedByAddress.length - 1][othersAddress].push(item);
+ } else if (feedByAddress.length > 0 && Object.keys(feedByAddress[feedByAddress.length - 1])[0] === 'threeBox' && !item.spaceName && (item.dataType === 'Public' || item.dataType === 'Private')) {
+ feedByAddress[feedByAddress.length - 1].threeBox.push(item);
+ } else if (feedByAddress.length > 0 && Object.keys(feedByAddress[feedByAddress.length - 1])[0] === item.spaceName) {
+ feedByAddress[feedByAddress.length - 1][item.spaceName].push(item);
+ } else if (item.spaceName) {
+ feedByAddress.push({
+ [item.spaceName]: [item],
+ });
+ } else if ((item.dataType === 'Public' || item.dataType === 'Private') && !item.spaceName) {
+ feedByAddress.push({
+ threeBox: [item],
+ });
+ } else {
+ console.log('meh others address')
+ }
+ });
+
+ this.setState({activity, fetching: false, categorizedActivity, feed});
+ } catch(e) {
+ console.log('ACTIVITY ERROR: ', e);
+ }
};
@@ -87,12 +88,13 @@ export default class ActivityClass extends Component {
};
render() {
+ console.log('STATE: ', this.state)
return (
- navigate('Profile')}>
+ navigate('Tokens')}>
diff --git a/src/AliceCore/Screens/Dapps.js b/src/AliceCore/Screens/Dapps.js
new file mode 100644
index 0000000..90e4c5d
--- /dev/null
+++ b/src/AliceCore/Screens/Dapps.js
@@ -0,0 +1,190 @@
+/*
+ * This is the ExampleMaps Registrar for Alice
+ * Register your app by:
+ * 1. Creating a folder in the src/Apps directory which contains your React Native app
+ * 2. Exporting your app in the ExampleMaps Export Section
+ * 3. Adding your app to the list of apps in the Apps List Section
+*/
+
+import React, { Component } from 'react';
+import {
+ StyleSheet, Text, TouchableOpacity, Keyboard, TouchableWithoutFeedback, Image, View, Modal, Dimensions, WebView,
+} from 'react-native';
+import Icon from '../../AliceComponents/IconComponent';
+import {navigate} from "../../AliceUtils/navigationWrapper";
+import AppIcon from "../../AliceComponents/AppIcon";
+import {Settings} from "../../AliceSDK/Web3";
+
+import { AppRegistry } from './../../Apps';
+import ReactNativeHapticFeedback from "react-native-haptic-feedback";
+
+const options = {
+ enableVibrateFallback: true,
+ ignoreAndroidSystemSettings: false
+};
+
+const WEBVIEW = 'WEBVIEW';
+
+const { height, width } = Dimensions.get('window');
+
+type Props = {};
+export default class AppsScreen extends Component {
+ static navigationOptions = ({ navigation }) => {
+ const { navigate } = navigation;
+ return {
+ tabBarIcon: ({ tintColor }) => ,
+ };
+ };
+
+ state = {
+ modalVisible: false,
+ };
+
+ openBrowser = () => {
+ ReactNativeHapticFeedback.trigger("impactLight", options);
+ Settings.openBrowser()
+ };
+
+ back = () => {
+ this.refs[WEBVIEW].goBack()
+ };
+ forward = () => {
+ this.refs[WEBVIEW].goForward()
+ };
+ reload = () => {
+ this.refs[WEBVIEW].reload()
+ };
+ stopLoading = () => {
+ this.refs[WEBVIEW].stopLoading()
+ };
+
+ render() {
+ return (
+
+ <>
+
+ navigate('Tokens')}>
+
+
+
+
+
+
+
+
+ {AppRegistry.map((app, i) => {
+ return ()
+ })
+ }
+
+
+ {
+ Alert.alert('Modal has been closed.');
+ }}>
+
+ console.log('message: ', e.nativeEvent.data)}
+ injectedJavaScript="window.onscroll=(e) => {window.postMessage('hello')};"
+ // injectedJavaScript={'(function(){return "Send me back!"}());'}
+ // injectedJavaScript="window.onscroll=function(e){window.postMessage(e)}';"
+ >
+
+
+
+ {'<'}
+
+
+ {'>'}
+
+
+ C
+
+
+ X
+
+
+
+
+ >
+
+ );
+ }
+}
+
+const styles = StyleSheet.create({
+ H1: {
+ fontWeight: 'bold',
+ color: 'black',
+ fontSize: 17,
+ },
+ appIcon: {
+ alignItems: 'center',
+ height: 84,
+ margin: 10,
+ maxWidth: 84,
+ justifyContent: 'space-between',
+ },
+ appsContainer: {
+ alignItems: 'center',
+ flexDirection: 'row',
+ flexWrap: 'wrap',
+ paddingBottom: 10,
+ paddingTop: 10,
+ width: width - 20,
+
+ },
+ appSquare: {
+ alignItems: 'center',
+ backgroundColor: '#43fd9c',
+ borderRadius: 32.5,
+ height: 65,
+ justifyContent: 'center',
+ width: 65,
+ shadowColor: '#212121',
+ shadowOffset: {
+ width: 0,
+ height: 3,
+ },
+ shadowRadius: 10,
+ shadowOpacity: 0.1,
+ },
+ appText: {
+ color: 'black',
+ fontSize: 10,
+ // fontFamily: 'Graphik',
+ },
+ container: {
+ flex: 1,
+ padding: 20,
+ flexDirection: 'column',
+ justifyContent: 'flex-start',
+ alignItems: 'flex-start',
+ backgroundColor: 'white',
+ },
+ headingText: {
+ color: 'black',
+ fontSize: 20,
+ // fontFamily: 'Graphik',
+ fontWeight: '500'
+ },
+ welcome: {
+ fontSize: 20,
+ textAlign: 'center',
+ margin: 10,
+ },
+ instructions: {
+ textAlign: 'center',
+ color: '#333333',
+ marginBottom: 5,
+ },
+});
diff --git a/src/AliceCore/Screens/Profile.js b/src/AliceCore/Screens/Tokens.js
similarity index 89%
rename from src/AliceCore/Screens/Profile.js
rename to src/AliceCore/Screens/Tokens.js
index bd56cea..4bcaeb7 100644
--- a/src/AliceCore/Screens/Profile.js
+++ b/src/AliceCore/Screens/Tokens.js
@@ -24,11 +24,12 @@ import QRCode from 'react-native-qrcode-svg';
import {Wallet} from '../../AliceSDK/Web3'
import AppIcon from "../../AliceComponents/AppIcon";
import {AppRegistry} from "../../Apps";
+import TransactionModal from '../../AliceComponents/TransactionModal'
//TODO: needs api key
-export default class Profile extends Component {
+export default class Tokens extends Component {
constructor(props) {
super(props);
@@ -40,6 +41,7 @@ export default class Profile extends Component {
nfts: [],
profileModalVisible: false,
tokenModalVisible: false,
+ transactionModalVisible: false,
address: ''
};
@@ -60,7 +62,7 @@ export default class Profile extends Component {
onData(JSON.parse(this.responseText));
}
});
- xhr.open("GET", "https://api.ethplorer.io/getAddressInfo/0xA1b02d8c67b0FDCF4E379855868DeB470E169cfB?apiKey=freekey");
+ xhr.open("GET", "https://api.ethplorer.io/getAddressInfo/"+await Wallet.getAddress()+"?apiKey=freekey");
xhr.send(data);
};
@@ -70,7 +72,8 @@ export default class Profile extends Component {
};
openTokenModal = (tokenInfo, token) => {
- this.setState({tokenModalVisible: !this.state.tokenModalVisible, tokenInfo, token})
+ this.setState({transactionModalVisible: !this.state.transactionModalVisible, tokenInfo, token})
+ // this.setState({transactionModalVisible: !this.state.transactionModalVisible, tokenModalVisible: !this.state.tokenModalVisible, tokenInfo, token})
};
closeTokenModal = () => {
@@ -88,13 +91,14 @@ export default class Profile extends Component {
onData(JSON.parse(this.responseText));
}
});
- xhr.open("GET", "https://api.opensea.io/api/v1/assets?owner=0xA1b02d8c67b0FDCF4E379855868DeB470E169cfB");
+ xhr.open("GET", "https://api.opensea.io/api/v1/assets?owner="+await Wallet.getAddress());
xhr.send(data);
};
render() {
- console.log('ADDRESS: ', this.state.address)
+ console.log('ADDRESS: ', this.state.address);
+ const { transactionModalVisible } = this.state;
return (
{this.state.address}
@@ -174,6 +178,7 @@ export default class Profile extends Component {
+ this.setState({transactionModalVisible: !transactionModalVisible})}/>
);
}
diff --git a/src/AliceSDK/Web3/index.js b/src/AliceSDK/Web3/index.js
index fa35497..cb8552f 100644
--- a/src/AliceSDK/Web3/index.js
+++ b/src/AliceSDK/Web3/index.js
@@ -1,6 +1,6 @@
import { NativeModules, NativeEventEmitter } from "react-native";
import {ethers, Contract as EthersContract} from 'ethers';
-let infuraProvider = new ethers.providers.InfuraProvider('ropsten');
+let infuraProvider = new ethers.providers.InfuraProvider('mainnet');
// const getAddress = (cb) => NativeModules.WalletModule.getAddress(cb);
@@ -29,6 +29,14 @@ const sendTransaction = async ({to, value, data}) => {
}
};
+const sendTransactionWithDapplet = async ({to, value, data}) => {
+ try {
+ return await NativeModules.WalletModule.sendTransactionWithDapplet(to, value, data);
+ } catch(e) {
+ return "Send transaction failed with error: " + e
+ }
+};
+
const signTransaction = async ({to, value, data}) => {
try {
return await NativeModules.WalletModule.signTransaction(to, value, data);
@@ -39,18 +47,18 @@ const signTransaction = async ({to, value, data}) => {
const signMessage = async (message) => {
try {
- return await NativeModules.WalletModule.signMessage(message);
+ return await NativeModules.WalletModule.signMessage(ethers.utils.formatBytes32String(message));
} catch(e) {
return "Sign message failed with error: " + e
}
-}
+};
const settingsPopUp = () => NativeModules.NativeVCModule.setting();
-const openBrowser = () => NativeModules.NativeVCModule.browser('foam.space');
+const openBrowser = (url) => url ? NativeModules.NativeVCModule.browser(url) : NativeModules.NativeVCModule.browser('duckduckgo.com');
const sendToken = () => {
-
+ return "Coming Soon!"
};
const write = async ({contractAddress, abi, functionName, parameters, value, data}) => {
@@ -59,7 +67,6 @@ const write = async ({contractAddress, abi, functionName, parameters, value, dat
} catch(e) {
return "Write to contract failed with error: " + e
}
-
};
const read = async ({contractAddress, abi, functionName, parameters}) => {
@@ -69,12 +76,19 @@ const read = async ({contractAddress, abi, functionName, parameters}) => {
} else if (parameters.length > 0) {
return contract[functionName](...parameters);
}
+};
+const resolve = async (ensName) => {
+ if (ensName.slice(-4) === '.eth') {
+ try {
+ return await infuraProvider.resolveName(ensName);
+ } catch (e) {
+ return "ENS resolver error: " + e;
+ }
+ }
};
const walletChangeEvent = () => {
- console.log('Native Event Emitter: ', NativeEventEmitter)
- console.log('Native Modules: ', NativeModules)
return new NativeEventEmitter(NativeModules.CallRNModule);
};
@@ -91,9 +105,14 @@ export const Wallet = {
signMessage,
sendToken,
walletChangeEvent,
+ sendTransactionWithDapplet
};
export const Contract = {
write,
read
};
+
+export const ENS = {
+ resolve
+}
diff --git a/src/AliceSDK/index.js b/src/AliceSDK/index.js
index 8e5f3d5..a0d18e4 100644
--- a/src/AliceSDK/index.js
+++ b/src/AliceSDK/index.js
@@ -1,7 +1,11 @@
import Map from "@react-native-mapbox-gl/maps";
import {RNCamera as Camera} from 'react-native-camera';
+import {Wallet, Settings, Contract} from "./Web3";
export default {
Map,
Camera,
+ Wallet,
+ Settings,
+ Contract
}
diff --git a/src/AliceUtils/Styles/index.js b/src/AliceUtils/Styles/index.js
new file mode 100644
index 0000000..e69de29
diff --git a/src/AliceUtils/ensFunctions.js b/src/AliceUtils/ensFunctions.js
new file mode 100644
index 0000000..7ee76ad
--- /dev/null
+++ b/src/AliceUtils/ensFunctions.js
@@ -0,0 +1,138 @@
+// import {Wallet} from "../AliceSDK/Web3";
+// //
+// // const Web3 = require('web3');
+// // const web3 = new Web3();
+// // web3.setProvider(new web3.providers.HttpProvider('https://ropsten.infura.io/rqmgop6P5BDFqz6yfGla'));
+// // const sha3 = require('sha3');
+//
+// let factoryContract = null;
+// const factoryAbi = [{"constant":true,"inputs":[],"name":"resolver","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_subdomain","type":"string"},{"name":"_domain","type":"string"},{"name":"_topdomain","type":"string"}],"name":"subdomainOwner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_registry","type":"address"}],"name":"updateRegistry","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_node","type":"bytes32"},{"name":"_owner","type":"address"}],"name":"transferDomainOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_domain","type":"string"},{"name":"_topdomain","type":"string"}],"name":"domainOwner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_subdomain","type":"string"},{"name":"_domain","type":"string"},{"name":"_topdomain","type":"string"}],"name":"subdomainTarget","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"registry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"lockDomainOwnershipTransfers","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"}],"name":"transferContractOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_subdomain","type":"string"},{"name":"_domain","type":"string"},{"name":"_topdomain","type":"string"},{"name":"_owner","type":"address"},{"name":"_target","type":"address"}],"name":"newSubdomain","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"locked","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_resolver","type":"address"}],"name":"updateResolver","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_registry","type":"address"},{"name":"_resolver","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"creator","type":"address"},{"indexed":true,"name":"owner","type":"address"},{"indexed":false,"name":"subdomain","type":"string"},{"indexed":false,"name":"domain","type":"string"},{"indexed":false,"name":"topdomain","type":"string"}],"name":"SubdomainCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousRegistry","type":"address"},{"indexed":true,"name":"newRegistry","type":"address"}],"name":"RegistryUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousResolver","type":"address"},{"indexed":true,"name":"newResolver","type":"address"}],"name":"ResolverUpdated","type":"event"},{"anonymous":false,"inputs":[],"name":"DomainTransfersLocked","type":"event"}]
+//
+//
+// // Ropsten
+// const factoryAddress = "0x62d6C93DF120FCa09a08258f3a644B5059aa12f0";
+//
+// // Mainnet
+// //factoryAddress: "0x21aa8d3eee8be2333ed180e9a5a8c0729c9b652c",
+//
+// factoryContract = new web3.eth.Contract(factoryAbi, factoryAddress);
+// let currentAccount = getPubKey();
+//
+// var isChecksumAddress = function (address) {
+// // Check each case
+// address = address.replace('0x','');
+// var addressHash = sha3(address.toLowerCase());
+// for (var i = 0; i < 40; i++ ) {
+// console.log('sha checking')
+// // the nth letter should be uppercase if the nth digit of casemap is 1
+// if ((parseInt(addressHash[i], 16) > 7 && address[i].toUpperCase() !== address[i]) || (parseInt(addressHash[i], 16) <= 7 && address[i].toLowerCase() !== address[i])) {
+// return false;
+// }
+// }
+// return true;
+// };
+//
+// export const addressResolver = async (input) => {
+// if (input.substring(0,2) === "0x"){
+// if (!/^(0x)?[0-9a-f]{40}$/i.test(input)) {
+// console.log("Invalid address");
+// return "0x0000000000000000000000000000000000000000";
+// } else if (/^(0x)?[0-9a-f]{40}$/.test(input) || /^(0x)?[0-9A-F]{40}$/.test(input)) {
+// console.log("Valid address");
+// return input;
+// }
+// } else {
+// return await checkSubdomainOwner(input, 'tenz-id');
+// }
+// };
+//
+//
+// export const initWeb3 = () => {
+// if(typeof web3 !== 'undefined') {
+// // web3 = new Web3(web3.currentProvider);
+// console.log('[x] web3 object initialized.');
+// // initContracts();
+// } else {
+// //no web3 instance available show a popup
+// }
+// };
+//
+// export const init = () => {
+// console.log('[x] Initializing ');
+// initWeb3();
+// };
+//
+// export const loadAccount = () => {
+// web3.eth.getAccounts(function(error, accounts) {
+// if(error) {
+// console.log("[x] Error loading accounts", error);
+// } else {
+// currentAccount = accounts[0];
+// console.log("[x] Using account", currentAccount);
+// initActions();
+// }
+// });
+// };
+//
+// export const checkSubdomainOwner = async (subdomain, domain, topdomain) => {
+// if (subdomain && domain) {
+// try {
+// return await factoryContract.methods.subdomainOwner(subdomain, domain, 'xyz').call();
+// } catch(e) {
+// return "Error connecting to subdomain provider";
+// }
+// } else {
+// return "Enter both subdomain and domain"
+// }
+// };
+//
+// export const newSubdomain = (subdomain, domain, owner, target) => {
+// factoryContract.methods.newSubdomain(
+// subdomain, domain, owner, target).send(
+// {
+// gas: 150000,
+// from: currentAccount
+// },
+// function(error, result){
+// if(error){
+// console.log('[x] Error during execution', error);
+// } else {
+// console.log('[x] Result', result);
+// }
+// }
+// )
+// };
+//
+// export const setSubdomain = async () => {
+// const data = await factoryContract.methods.newSubdomain(subdomain, domain, owner, target).encodeABI();
+// const nonce = await web3.eth.getTransactionCount(currentAccount);
+// const chainId = await web3.eth.net.getId();
+//
+// const rawTx = {
+// "nonce": nonce,
+// "from": currentAccount,
+// "to": "0xdb0a1cf7ec068fd48a3f5869bf4f60b62e4ecb5e",
+// "value": "0x0",
+// "gas": 40000,
+// "gasPrice": 500000000000, // converts the gwei price to wei
+// "chainId": 3,
+// "data": web3.utils.toHex(data)
+// };
+//
+// const tx = new Tx(rawTx);
+// tx.sign(account1.privateKey);
+//
+// const serializedTx = tx.serialize();
+//
+// web3.eth.sendSignedTransaction('0x' + serializedTx.toString('hex'))
+// .on('transactionHash', (txHash) => {
+// console.log('Tokens transferred:' , txHash);
+// })
+// .on('confirmation', (conf, msg) => {
+// //after account gets money
+// if (conf === 0) {
+// console.log('& Confirmed:' , conf);
+// }
+// })
+// }
+//
diff --git a/src/AliceUtils/themes.js b/src/AliceUtils/themes.js
new file mode 100644
index 0000000..2af9a72
--- /dev/null
+++ b/src/AliceUtils/themes.js
@@ -0,0 +1,95 @@
+// @flow
+import { Platform, Dimensions } from 'react-native';
+
+// ==============================
+// APP STYLE CONSTANTS
+// ==============================
+
+// color
+const color = {
+ textGrey: '#a7a1a0',
+ green: '#03c845',
+ darkGrey: '#eae9e2',
+ lightGrey: '#f8f7f2',
+ yellow: '#FFFF00',
+ magenta: '#FF00EC',
+ blue: '#17DAD9',
+ component: 'white',
+ bg: '#1D1D1D',
+ bg_text: '#FFFFFF',
+ bg_text_sec: '#B4B5B0',
+ bg_positive: '#72E762',
+ bg_warning: '#FAE265',
+ bg_alert: '#ED332B',
+ bg_text_positive: '#72E762',
+ card_bg: '#F9F9F9',
+ card_text: '#1A1A1A',
+ card_bg_text_sec: '#B4B5B0'
+};
+
+// font sizes
+const fontSize = {
+ xsmall: 12,
+ small: 14,
+ default: 17,
+ large: 24,
+ xlarge: 32,
+};
+
+
+
+// text styles
+const text = {
+ greySmall: {
+ fontFamily: 'DIN Condensed',
+ color: color.textGrey,
+ fontSize: 10,
+ },
+ greyMedium: {
+ fontFamily: 'DIN Condensed',
+ color: color.textGrey,
+ },
+ blackSmall: {
+ fontFamily: 'DIN Condensed',
+ color: 'black',
+ fontSize: 10,
+ },
+ blackMedium: {
+ fontFamily: 'DIN Condensed',
+ color: 'black',
+ },
+};
+
+// Component Specific
+// ------------------------------
+
+// navbar
+const navbar = {
+ backgroundColor: 'white',
+ buttonColor: color.blue,
+ height: Platform.OS === 'ios' ? 64 : 44,
+ textColor: color.text,
+};
+
+// list header
+const listheader = {
+ height: 34,
+};
+
+// next up
+const nextup = {
+ height: Platform.OS === 'ios' ? 70 : 110,
+};
+
+const statusBarHeight = Platform.OS === 'ios' ? 20 : 24;
+const talkPaneAndroidMinScrollAreaHeight = Dimensions.get('window').height - 48;
+
+export {
+ color,
+ fontSize,
+ text,
+ navbar,
+ nextup,
+ listheader,
+ talkPaneAndroidMinScrollAreaHeight,
+};
diff --git a/src/Apps/Example/Screens/Home.js b/src/Apps/Example/Screens/Home.js
index 029e1b2..b6d32eb 100644
--- a/src/Apps/Example/Screens/Home.js
+++ b/src/Apps/Example/Screens/Home.js
@@ -1,7 +1,6 @@
import React from "react";
-import {Image, Text, NativeModules, TouchableOpacity, View} from "react-native";
+import { Text, TouchableOpacity, View } from "react-native";
import {Wallet, Contract} from "../../../AliceSDK/Web3";
-import Modalize from '../Components/Modalize'
import {FoodContractABI} from "../ABI";
import {NavigationBar} from "../../../AliceComponents/NavigationBar";
@@ -31,10 +30,6 @@ export default class ExampleHome extends React.Component {
}
- onClick = () => {
- this.child.current.openModal();
- };
-
getAddress = async () => {
try {
const address = await Wallet.getAddress();
@@ -69,6 +64,16 @@ export default class ExampleHome extends React.Component {
}
};
+ openDapplet = async () => {
+ try {
+ const txHash = await Wallet.sendTransactionWithDapplet({to: '0xE115012aA32a46F53b09e0A71CD0afa0658Da55F', value: '0.01'})
+ console.log('txHash: ', txHash);
+ this.setState({txHash})
+ } catch(e) {
+ console.log(e);
+ }
+ };
+
signTransaction = async () => {
try {
const signedTransaction = await Wallet.signTransaction({to: '0xE115012aA32a46F53b09e0A71CD0afa0658Da55F', value: '0.01', data: 'Hello'});
@@ -130,6 +135,10 @@ export default class ExampleHome extends React.Component {
Send Transaction
+ TransactionHash: {this.state.txHash}
+
+ Send Transaction with Dapplet
+
Signed Transaction: {this.state.signedTransaction}
Sign Transaction
@@ -151,16 +160,10 @@ export default class ExampleHome extends React.Component {
Read From Contract
Render Modal
-
- Pop Up
-
Get Balance: {this.state.balance}
Get Balance
-
-
-
);
}
diff --git a/src/Apps/index.js b/src/Apps/index.js
index 69a705f..fab20a9 100644
--- a/src/Apps/index.js
+++ b/src/Apps/index.js
@@ -141,7 +141,7 @@ export default class AppsScreen extends Component {
- navigate('Profile')}>
+ navigate('Tokens')}>