@@ -1,6 +1,6 @@
1−import Maybe from 'folktale/maybe'
1+import { Just, Nothing } from 'folktale/maybe'
2import React from 'react'
2import React from 'react'
3−import * as azimuth from 'azimuth-js'
3+import { azimuth, ecliptic } from 'azimuth-js'
4import * as ob from 'urbit-ob'
4import * as ob from 'urbit-ob'
6import { Row, Col, H1, H3, P, Anchor, Warning } from '../components/Base'
6import { Row, Col, H1, H3, P, Anchor, Warning } from '../components/Base'
@@ -13,11 +13,7 @@ import { ROUTE_NAMES } from '../lib/router'
13import { NETWORK_NAMES } from '../lib/network'
13import { NETWORK_NAMES } from '../lib/network'
14import { BRIDGE_ERROR } from '../lib/error'
14import { BRIDGE_ERROR } from '../lib/error'
15import { getSpawnCandidate } from '../lib/child'
15import { getSpawnCandidate } from '../lib/child'
18− sendSignedTransaction,
16+import { canDecodePatp, sendSignedTransaction, fromWei } from '../lib/txn'
23 ETH_ZERO_ADDR,
19 ETH_ZERO_ADDR,
@@ -30,7 +26,6 @@ class IssueChild extends React.Component {
30 constructor(props) {
26 constructor(props) {
31 super(props)
27 super(props)
34 const issuingPoint = props.pointCursor.matchWith({
29 const issuingPoint = props.pointCursor.matchWith({
35 Just: (pt) => parseInt(pt.value, 10),
30 Just: (pt) => parseInt(pt.value, 10),
36 Nothing: () => {
31 Nothing: () => {
@@ -48,25 +43,24 @@ class IssueChild extends React.Component {
50 this.state = {
45 this.state = {
51− txError: Maybe.Nothing(),
46+ txError: Nothing(),
52 receivingAddress: '',
47 receivingAddress: '',
53 issuingPoint: issuingPoint,
48 issuingPoint: issuingPoint,
54 desiredPoint: '',
49 desiredPoint: '',
55− isAvailable: Maybe.Nothing(), // allow attempt when offline
50+ isAvailable: Nothing(), // use Nothing to allow attempt when offline
56 userApproval: false,
51 userApproval: false,
57 nonce: '',
52 nonce: '',
58 gasPrice: '5',
53 gasPrice: '5',
59 chainId: '',
54 chainId: '',
60 gasLimit: '600000',
55 gasLimit: '600000',
61− txn: Maybe.Nothing(),
56+ txn: Nothing(),
62− stx: Maybe.Nothing(),
57+ stx: Nothing(),
63 suggestions: suggestions,
58 suggestions: suggestions,
66 this.handlePointInput = this.handlePointInput.bind(this)
61 this.handlePointInput = this.handlePointInput.bind(this)
67 this.handleAddressInput = this.handleAddressInput.bind(this)
62 this.handleAddressInput = this.handleAddressInput.bind(this)
68 this.handleConfirmAvailability = this.handleConfirmAvailability.bind(this)
63 this.handleConfirmAvailability = this.handleConfirmAvailability.bind(this)
70 this.handleCreateUnsignedTxn = this.handleCreateUnsignedTxn.bind(this)
64 this.handleCreateUnsignedTxn = this.handleCreateUnsignedTxn.bind(this)
71 this.handleSubmit = this.handleSubmit.bind(this)
65 this.handleSubmit = this.handleSubmit.bind(this)
72 this.handleSetUserApproval = this.handleSetUserApproval.bind(this)
66 this.handleSetUserApproval = this.handleSetUserApproval.bind(this)
@@ -97,20 +91,20 @@ class IssueChild extends React.Component {
97 validWeb3.eth.getTransactionCount(addr),
91 validWeb3.eth.getTransactionCount(addr),
98 validWeb3.eth.net.getId(),
92 validWeb3.eth.net.getId(),
99 validWeb3.eth.getGasPrice()
93 validWeb3.eth.getGasPrice()
102 Promise.all(getTxMetadata).then(r => {
96 Promise.all(getTxMetadata).then(r => {
103 const txMetadata = {
97 const txMetadata = {
104 nonce: r[0],
98 nonce: r[0],
105 chainId: r[1],
99 chainId: r[1],
106 gasPrice: fromWei(r[2], 'gwei'),
100 gasPrice: fromWei(r[2], 'gwei'),
109 this.setState({...txMetadata})
103 this.setState({...txMetadata})
@@ -127,7 +121,7 @@ class IssueChild extends React.Component {
127 if (desiredPoint.length < 15) {
121 if (desiredPoint.length < 15) {
128 this.setState({
122 this.setState({
129 desiredPoint,
123 desiredPoint,
130− isAvailable: Maybe.Nothing()
124+ isAvailable: Nothing()
132 this.handleClearTxn()
126 this.handleClearTxn()
@@ -205,7 +199,7 @@ class IssueChild extends React.Component {
205 handleClearStx() {
199 handleClearStx() {
206 this.setState({
200 this.setState({
207 userApproval: false,
201 userApproval: false,
208− stx: Maybe.Nothing(),
202+ stx: Nothing(),
@@ -214,8 +208,8 @@ class IssueChild extends React.Component {
214 handleClearTxn() {
208 handleClearTxn() {
215 this.setState({
209 this.setState({
216 userApproval: false,
210 userApproval: false,
217− txn: Maybe.Nothing(),
211+ txn: Nothing(),
218− stx: Maybe.Nothing(),
212+ stx: Nothing(),
@@ -224,8 +218,8 @@ class IssueChild extends React.Component {
224 handleClearTransaction() {
218 handleClearTransaction() {
225 this.setState({
219 this.setState({
226 userApproval: false,
220 userApproval: false,
227− txn: Maybe.Nothing(),
221+ txn: Nothing(),
228− stx: Maybe.Nothing(),
222+ stx: Nothing(),
@@ -244,40 +238,48 @@ class IssueChild extends React.Component {
249 async confirmPointAvailability() {
241 async confirmPointAvailability() {
250− const { state, props } = this
242+ const { contracts } = this.props
251−
243+ const { desiredPoint } = this.state
252− if (canDecodePatp(state.desiredPoint) === false) return Maybe.Just(false)
254− const validContracts = props.contracts.matchWith({
245+ const validContracts = contracts.matchWith({
255− Just: (cs) => cs.value,
246+ Just: cs => cs.value,
256− Nothing: () => {
247+ Nothing: _ => {
257 throw BRIDGE_ERROR.MISSING_CONTRACTS
248 throw BRIDGE_ERROR.MISSING_CONTRACTS
261− const pointDec = ob.patp2dec(state.desiredPoint)
252+ if (canDecodePatp(desiredPoint) === false) {
263− const owner = await azimuth.azimuth.getOwner(
256+ const point = ob.patp2dec(desiredPoint)
264− validContracts,
257+ const pointSize = azimuth.getPointSize(point)
268− if (eqAddr(owner, ETH_ZERO_ADDR)) return Maybe.Just(true)
259+ const prefix = azimuth.getPrefix(point)
260+ const prefixSize = azimuth.getPointSize(prefix)
262+ // NB (jtobin): this prevents galaxies from attempting to spawn planets
264+ if (pointSize !== prefixSize + 1) {
270− return Maybe.Just(false)
265+ return Just(false)
268+ const owner = await azimuth.getOwner(validContracts, point)
270+ if (eqAddr(owner, ETH_ZERO_ADDR)) {
275 createUnsignedTxn() {
277 createUnsignedTxn() {
276 const { state, props } = this
278 const { state, props } = this
278− if (isValidAddress(state.receivingAddress) === false) return Maybe.Nothing()
280+ if (isValidAddress(state.receivingAddress) === false) return Nothing()
279− if (state.isAvailable === false) return Maybe.Nothing()
281+ if (state.isAvailable === false) return Nothing()
280− if (canDecodePatp(state.desiredPoint) === false) return Maybe.Nothing()
282+ if (canDecodePatp(state.desiredPoint) === false) return Nothing()
282 const validContracts = props.contracts.matchWith({
284 const validContracts = props.contracts.matchWith({
283 Just: (cs) => cs.value,
285 Just: (cs) => cs.value,
@@ -288,20 +290,20 @@ class IssueChild extends React.Component {
289 const pointDec = ob.patp2dec(state.desiredPoint)
291 const pointDec = ob.patp2dec(state.desiredPoint)
291− const txn = azimuth.ecliptic.spawn(
293+ const txn = ecliptic.spawn(
292 validContracts,
294 validContracts,
293 pointDec,
295 pointDec,
294 state.receivingAddress
296 state.receivingAddress
297− return Maybe.Just(txn)
299+ return Just(txn)
302 buttonTriState() {
304 buttonTriState() {
303 const a = this.state.isAvailable
305 const a = this.state.isAvailable
304− if (Maybe.Nothing.hasInstance(a)) return 'blue'
306+ if (Nothing.hasInstance(a)) return 'blue'
305 if (a.value === false) return 'yellow'
307 if (a.value === false) return 'yellow'
306 if (a.value === true) return 'green'
308 if (a.value === true) return 'green'
@@ -310,7 +312,7 @@ class IssueChild extends React.Component {
311 buttonTriStateText() {
313 buttonTriStateText() {
312 const a = this.state.isAvailable
314 const a = this.state.isAvailable
313− if (Maybe.Nothing.hasInstance(a)) return 'Confirm Availablility'
315+ if (Nothing.hasInstance(a)) return 'Confirm Availablility'
314 if (a.value === false) return 'Point is Not Available'
316 if (a.value === false) return 'Point is Not Available'
315 if (a.value === true) return 'Available'
317 if (a.value === true) return 'Available'
@@ -352,9 +354,11 @@ class IssueChild extends React.Component {
355− const canSign = !Maybe.Nothing.hasInstance(state.txn)
357+ const canSign = Just.hasInstance(state.txn)
356− const canApprove = !Maybe.Nothing.hasInstance(state.stx)
358+ const canApprove = Just.hasInstance(state.stx)
360+ Just.hasInstance(state.stx)
357− const canSend = !Maybe.Nothing.hasInstance(state.stx) && state.userApproval === true
361+ && state.userApproval === true
359 const esvisible =
363 const esvisible =
360 props.networkType === NETWORK_NAMES.ROPSTEN ||
364 props.networkType === NETWORK_NAMES.ROPSTEN ||
@@ -494,7 +498,7 @@ class IssueChild extends React.Component {
494 handleSubmit={this.handleSubmit} />
498 handleSubmit={this.handleSubmit} />
497− Maybe.Nothing.hasInstance(state.txError)
501+ Nothing.hasInstance(state.txError)
499 : <Warning className={'mt-8'}>
503 : <Warning className={'mt-8'}>
500 <H3 style={{marginTop: 0, paddingTop: 0}}>
504 <H3 style={{marginTop: 0, paddingTop: 0}}>