@@ -0,0 +1,222 @@
1+import { Just, Nothing } from 'folktale/maybe'
2+import React from 'react'
3+import { pour } from 'sigil-js'
4+import * as ob from 'urbit-ob'
5+import * as azimuth from 'azimuth-js'
6+
7+import {
8+ EthereumWallet,
9+ addressFromSecp256k1Public,
10+ urbitWalletFromTicket,
11+ addHexPrefix,
12+ WALLET_NAMES
13+} from '../lib/wallet'
14+
15+import ReactSVGComponents from '../components/ReactSVGComponents'
16+import KeysAndMetadata from './Point/KeysAndMetadata'
17+import Actions from './Point/Actions'
18+import { BRIDGE_ERROR } from '../lib/error'
19+import { Row, Col, Warning, Button, H1, H3 } from '../components/Base'
20+import StatelessTransaction from '../components/StatelessTransaction'
21+
22+// for wallet generation
23+import * as kg from '../../../node_modules/urbit-key-generation/dist/index'
24+import * as more from 'more-entropy'
25+import lodash from 'lodash'
26+import { PLANET_ENTROPY_BITS } from '../../walletgen/lib/constants'
27+
28+// for transaction generation and signing
29+import {
30+ signTransaction,
31+ sendSignedTransaction,
32+ waitForTransactionConfirm,
33+ isTransactionConfirmed
34+} from '../lib/txn'
35+import * as tank from '../lib/tank'
36+import Tx from 'ethereumjs-tx'
37+
38+//TODO needs more work to include email sending in the process
39+class InvitesSend extends React.Component {
40+
41+ constructor(props) {
42+ super(props)
43+
44+ this.state = {
45+ invitesAvailable: Nothing(),
46+ fromPool: Nothing(),
47+ haveInvited: Nothing(),
48+ randomPlanet: Nothing(),
49+ inviteWallet: Nothing()
50+ }
51+
52+ this.findInvited = this.findInvited.bind(this);
53+ this.findRandomPlanet = this.findRandomPlanet.bind(this);
54+ this.generateWallet = this.generateWallet.bind(this);
55+ this.canGenerate = this.canGenerate.bind(this);
56+ }
57+
58+ componentDidMount() {
59+ this.point = this.props.pointCursor.matchWith({
60+ Just: (pt) => parseInt(pt.value, 10),
61+ Nothing: () => {
62+ throw BRIDGE_ERROR.MISSING_POINT
63+ }
64+ });
65+ this.contracts = this.props.contracts.matchWith({
66+ Just: cs => cs.value,
67+ Nothing: _ => {
68+ throw BRIDGE_ERROR.MISSING_CONTRACTS
69+ }
70+ });
71+
72+ azimuth.delegatedSending.getPool(this.contracts, this.point)
73+ .then(pool => {
74+ this.setState({fromPool: Just(pool)});
75+ azimuth.delegatedSending.invitesInPool(this.contracts, pool)
76+ .then(count => {
77+ this.setState({invitesAvailable: Just(count)});
78+ });
79+ });
80+ this.findInvited();
81+ this.findRandomPlanet();
82+ this.generateWallet();
83+ }
84+
85+ componentDidUpdate(prevProps) {
86+ //
87+ }
88+
89+ async findInvited() {
90+ let invited = await azimuth.delegatedSending.getInvited(
91+ this.contracts,
92+ this.point
93+ );
94+ invited.map(async point => {
95+ const active = await azimuth.azimuth.isActive(this.contracts, point);
96+ console.log('point active', point, active);
97+ return {point: Number(point), active};
98+ });
99+ invited = await Promise.all(invited);
100+ this.setState({haveInvited: Just(invited)});
101+ }
102+
103+ async findRandomPlanet() {
104+ let res = Nothing();
105+ const kids = azimuth.azimuth.getUnspawnedChildren(
106+ this.contracts,
107+ azimuth.azimuth.getPrefix(this.point)
108+ );
109+ if (kids.length > 0) {
110+ const i = Math.floor(Math.random() * kids.length);
111+ res = Just(Number(kids[i]));
112+ }
113+ this.setState({randomPlanet: res});
114+ return res;
115+ }
116+
117+ //TODO pulled from walletgen/views/Generate, put into lib
118+ async generateWallet() {
119+ const makeTicket = () => {
120+
121+ const bits = PLANET_ENTROPY_BITS
122+
123+ const bytes = bits / 8
124+ const some = new Uint8Array(bytes)
125+ window.crypto.getRandomValues(some)
126+
127+ const gen = new more.Generator()
128+
129+ return new Promise((resolve, reject) => {
130+ gen.generate(bits, result => {
131+ const chunked = lodash.chunk(result, 2)
132+ const desired = chunked.slice(0, bytes) // only take required entropy
133+ const more = lodash.flatMap(desired, arr => arr[0] ^ arr[1])
134+ const entropy = lodash.zipWith(some, more, (x, y) => x ^ y)
135+ const buf = Buffer.from(entropy)
136+ const patq = ob.hex2patq(buf.toString('hex'))
137+ resolve(patq)
138+ reject('Entropy generation failed')
139+ })
140+ })
141+ };
142+
143+ const ticket = await makeTicket(0x10000); // planet-sized ticket
144+ const wallet = await kg.generateWallet({ticket, ship:0});
145+ console.log('found ticket', ticket, wallet, wallet.ownership.keys.address);
146+ this.setState({inviteWallet:
147+ Just({ticket, owner:wallet.ownership.keys.address})
148+ });
149+ }
150+
151+ canGenerate() {
152+ //TODO and canSend()
153+ console.log('can generate', this.state.invitesAvailable, this.state.randomPlanet,);
154+ let res = this.state.invitesAvailable.matchWith({
155+ Nothing: () => false,
156+ Just: invites => ((invites.value > 0)
157+ && Just.hasInstance(this.state.randomPlanet)
158+ && Just.hasInstance(this.state.inviteWallet))
159+ });
160+ return res;
161+ }
162+
163+ render() {
164+
165+ const inviteStatus = this.state.invitesAvailable.matchWith({
166+ Nothing: () => 'Loading...',
167+ Just: (invites) => {
168+ let res = `${invites.value} invites available`;
169+ return res + this.state.fromPool.matchWith({
170+ Nothing: () => '',
171+ Just: (pool) => (pool.value == this.point)
172+ ? ''
173+ : ` (from ${ob.patp(pool.value)})`
174+ });
175+ }
176+ });
177+
178+
179+ const inviteList = this.state.haveInvited.matchWith({
180+ Nothing: () => (<li>{'Loading...'}</li>),
181+ Just: (invited) => invited.value.map(i => {
182+ return (<li>
183+ <span class="invitee">{ob.patp(i.point)}</span>
184+ <span class="status">{i.active ? 'accepted' : 'pending'}</span>
185+ </li>);
186+ })
187+ });
188+
189+ return (
190+ <Row>
191+ <Col>
192+
193+ <p>{ 'send invites here, for planets' }</p>
194+
195+ <p>{ inviteStatus }</p>
196+
197+ <ul>{ inviteList }</ul>
198+
199+ <StatelessTransaction
200+ // Upper scope
201+ web3={this.props.web3}
202+ contracts={this.props.contracts}
203+ wallet={this.props.wallet}
204+ walletType={this.props.walletType}
205+ walletHdPath={this.props.walletHdPath}
206+ networkType={this.props.networkType}
207+ setTxnHashCursor={this.props.setTxnHashCursor}
208+ setTxnConfirmations={this.props.setTxnConfirmations}
209+ popRoute={this.props.popRoute}
210+ pushRoute={this.props.pushRoute}
211+ // Other
212+ canGenerate={this.canGenerate()}
213+ createUnsignedTxn={this.createUnsignedTxn}
214+ ref={this.statelessRef} />
215+
216+ </Col>
217+ </Row>
218+ )
219+ }
220+}
221+
222+export default InvitesSend