@@ -0,0 +1,138 @@
1+import React, { useState } from 'react';
2+import { Grid, Text } from 'indigo-react';
3+import { useWallet } from 'store/wallet';
4+import { usePointCursor } from 'store/pointCursor';
6+import { useLocalRouter } from 'lib/LocalRouter';
8+import ViewHeader from 'components/ViewHeader';
9+import View from 'components/View';
10+import WarningBox from 'components/WarningBox';
12+import CopiableAddressWrap from 'components/CopiableAddressWrap';
13+import Highlighted from 'components/Highlighted';
15+import { PsbtInput } from 'form/Inputs';
16+import BridgeForm from 'form/BridgeForm';
18+import * as need from 'lib/need';
19+import * as bitcoin from 'bitcoinjs-lib';
20+import ob from 'urbit-ob';
21+import { Buffer } from 'buffer';
22+import { composeValidator, buildPsbtValidator } from 'form/validators';
24+export default function Bitcoin() {
25+ const { pop } = useLocalRouter();
26+ const { urbitWallet } = useWallet();
27+ const { pointCursor } = usePointCursor();
29+ const empty = new bitcoin.Psbt();
31+ const [signedTx, setSignedTx] = useState('');
32+ const [psbt, setPsbt] = useState(empty);
34+ const pointName = ob.patp(need.point(pointCursor));
36+ const privKey = need.urbitWallet(urbitWallet).bitcoin.keys.private;
37+ const pubKey = need.urbitWallet(urbitWallet).bitcoin.keys.public;
38+ const chain = need.urbitWallet(urbitWallet).bitcoin.keys.chain;
40+ const hd = bitcoin.bip32.fromPrivateKey(
41+ Buffer.from(privKey, 'hex'),
42+ Buffer.from(chain, 'hex'),
43+ bitcoin.networks.bitcoin
46+ const xPub = bitcoin.bip32
48+ Buffer.from(pubKey, 'hex'),
49+ Buffer.from(chain, 'hex'),
50+ bitcoin.networks.bitcoin
54+ const validate = composeValidator({
55+ unsignedTransaction: buildPsbtValidator(hd),
58+ const onValues = ({ valid, values, form }) => {
60+ const newPsbt = bitcoin.Psbt.fromHex(values.unsignedTransaction);
64+ .extractTransaction()
67+ if (psbt.toHex() !== newPsbt.toHex()) {
77+ <View pop={pop} inset>
78+ <Grid className="mt4">
79+ <Grid.Item full as={ViewHeader}>
82+ <Grid.Item full as={WarningBox}>
83+ We do not recommend using this feature for significant amounts of
84+ money, since your private keys are exposed to the browser.
86+ <Grid.Item full className="mt4" as={Text}>
87+ Below is the bitcoin extended public key derived from your point
88+ {' ' + pointName}. You can paste it to Landscape to generate an
89+ unsigned transaction.
91+ <Grid.Item full className="mt4" as={Text}>
93+ <CopiableAddressWrap>{xPub}</CopiableAddressWrap>
96+ <Grid.Item full className="mt4" as={Text}>
97+ Next, paste the unsigned transaction below to sign it with your
100+ <BridgeForm validate={validate} onValues={onValues}>
105+ name="unsignedTransaction"
106+ label="Unsigned transaction"
112+ <Grid.Item full className="mt4" as={Text}>
113+ Transaction outputs:
117+ psbt.txOutputs.map(e => (
118+ <Grid.Item full className="mt4">
119+ <span>{e.address}</span>
120+ <div className="mt1 mono black f6">{e.value} Satoshis</div>
125+ <Grid.Item full className="mt4" as={ViewHeader}>
128+ <Grid.Item full as={Text}>
130+ <CopiableAddressWrap>{signedTx}</CopiableAddressWrap>