Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import SendPsbtScreen from './screen/send-psbt';
import SendConfirmScreen from './screen/send-confirm';
import SendSuccessScreen from './screen/send-success';
import SettingsScreen from './screen/settings';
import CosignerExportScreen from './screen/cosigner-export';
import EmailSetScreen from './screen/email-set';
import EmailPinScreen from './screen/email-pin';
import EmailVerifyScreen from './screen/email-verify';
Expand All @@ -35,6 +36,7 @@ const PinChangeStack = createStackNavigator();
const PinCheckStack = createStackNavigator();
const RestoreStack = createStackNavigator();
const EmailSetStack = createStackNavigator();
const CosignerExportStack = createStackNavigator();
const MainStack = createBottomTabNavigator();
const RootStack = createStackNavigator();

Expand Down Expand Up @@ -139,6 +141,21 @@ const PinChangeStackScreen = () => (
</PinChangeStack.Navigator>
);

const CosignerExportStackScreen = () => (
<CosignerExportStack.Navigator>
<CosignerExportStack.Screen
name="CosignerExport"
component={CosignerExportScreen}
options={{
title: 'Export Cosigner',
headerLeft: () => (
<HeaderBackButton label="Settings" onPress={() => nav.goBack()} />
),
}}
/>
</CosignerExportStack.Navigator>
);

const PinCheckStackScreen = () => (
<PinCheckStack.Navigator>
<PinCheckStack.Screen
Expand Down Expand Up @@ -284,6 +301,11 @@ const App = () => (
component={PinChangeStackScreen}
options={{headerShown: false}}
/>
<RootStack.Screen
name="CosignerExport"
component={CosignerExportStackScreen}
options={{headerShown: false}}
/>
</RootStack.Navigator>
</NavigationContainer>
);
Expand Down
53 changes: 51 additions & 2 deletions src/action/multisig.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,54 @@ import RNFS from 'react-native-fs';
import {MultisigHDWallet} from '@photon-sdk/photon-lib';

import store from '../store';
import * as nav from './nav';
import * as alert from './alert';
import {getWallet, getMultisigWallet, walletStore} from './wallet';

const PATH = "m/48'/0'/0'/2'";

//
// Export Cosigner
//

function _loadCosignerExport() {
const mnemonic = walletStore.wallets[0].getSecret();
const msWallet = new MultisigHDWallet();
msWallet.setDerivationPath(PATH);
const xpub = MultisigHDWallet.seedToXpub(mnemonic, PATH);
const Zpub = msWallet.convertXpubToMultisignatureXpub(xpub);
const xfp = MultisigHDWallet.seedToFingerprint(mnemonic);
store.cosignerExport = JSON.stringify({xfp, xpub: Zpub, path: PATH});
}

export function initCosignerExport() {
_loadCosignerExport();
nav.goTo('CosignerExport');
}

export async function shareCosigner() {
try {
await _shareCosigner();
} catch (err) {
alert.error({err});
}
}

async function _shareCosigner() {
const xfp = JSON.parse(store.cosignerExport).xfp;
const filePath = `${RNFS.DocumentDirectoryPath}/mmxp-${xfp}.json`;
await RNFS.writeFile(filePath, store.cosignerExport, 'utf8');
await RNShare.open({
url: `file://${filePath}`,
type: 'application/json',
});
await RNFS.unlink(filePath);
}

//
// Import ColdCard
//

export async function importColdCard() {
try {
await _importColdCardFile();
Expand Down Expand Up @@ -37,7 +82,7 @@ async function _createMultiSig() {
if (multisig) {
throw new Error('Multisig wallet already exists!');
}
const mnemonic = await getWallet().getSecret();
const mnemonic = getWallet().getSecret();
const msWallet = new MultisigHDWallet();
msWallet.addCosigner(mnemonic);
if (!store.cosigners.length) {
Expand All @@ -46,12 +91,16 @@ async function _createMultiSig() {
store.cosigners.forEach(cosigner => {
msWallet.addCosigner(cosigner.xpub, cosigner.fingerprint);
});
msWallet.setDerivationPath("m/48'/0'/0'/2'");
msWallet.setDerivationPath(PATH);
msWallet.setM(2);
walletStore.wallets.push(msWallet);
await walletStore.saveToDisk();
}

//
// Export Multisig.txt
//

export async function exportTxtFile() {
try {
await _exportMultiSigTxt();
Expand Down
52 changes: 52 additions & 0 deletions src/screen/cosigner-export.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React from 'react';
import {StyleSheet, View} from 'react-native';
import {observer} from 'mobx-react';

import {QRCode} from '../component/qrcode';
import {PillButton} from '../component/button';
import {LargeSpinner} from '../component/spinner';
import {font} from '../component/style';

import store from '../store';
import * as wallet from '../action/wallet';
import * as multisig from '../action/multisig';

const styles = StyleSheet.create({
wrapper: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
padding: 25,
},
codeWrapper: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
addressText: {
marginTop: 20,
fontSize: font.sizeSub,
lineHeight: font.lineHeightSub,
},
});

const CosignerExportScreen = ({navigation}) => {
return (
<View style={styles.wrapper}>
{store.cosignerExport ? <Cosigner /> : <LargeSpinner />}
</View>
);
};

const Cosigner = () => (
<View>
<View style={styles.codeWrapper}>
<QRCode size={260}>{store.cosignerExport}</QRCode>
</View>
<PillButton onPress={() => multisig.shareCosigner()}>
Share Cosigner
</PillButton>
</View>
);

export default observer(CosignerExportScreen);
8 changes: 7 additions & 1 deletion src/screen/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const styles = StyleSheet.create({
padding: 15,
},
btnWrapper: {
marginTop: 50,
marginTop: 40,
alignItems: 'center',
},
});
Expand All @@ -31,6 +31,12 @@ const SettingsScreen = () => (
<View style={styles.btnWrapper}>
<Button title="Change PIN" onPress={() => backup.initPinChange()} />
</View>
<View style={styles.btnWrapper}>
<Button
title="Export Cosigner"
onPress={() => multisig.initCosignerExport()}
/>
</View>
<View style={styles.btnWrapper}>
<Button
title="Import ColdCard"
Expand Down
1 change: 1 addition & 0 deletions src/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const store = observable({
balanceRefreshing: false,
transactions: [],
nextAddress: null,
cosignerExport: null,
cosigners: [],

// screens
Expand Down