on 05c1914 help sign in
bridge/src/views/CreateGalaxy.js
309 lines 8.6 kB history raw
1import React from 'react'
2import Maybe from 'folktale/maybe'
3import * as azimuth from 'azimuth-js'
4import * as ob from 'urbit-ob'
6import { Button, } from '../components/Base'
7import { Row, Col, H1, P, Anchor } from '../components/Base'
8import { InnerLabel, GalaxyInput, AddressInput, ValidatedSigil, ShowBlockie } from '../components/Base'
9import StatelessTransaction from '../components/StatelessTransaction'
11import { BRIDGE_ERROR } from '../lib/error'
13import { NETWORK_NAMES } from '../lib/network'
15import {
16 sendSignedTransaction,
17 getTxnInfo,
18 canDecodePatp
19} from '../lib/txn'
21import { ROUTE_NAMES } from '../lib/router'
23import {
24 addressFromSecp256k1Public,
25 ETH_ZERO_ADDR,
26 isValidAddress,
27 eqAddr
28} from '../lib/wallet'
30import {
31 isValidGalaxy
32} from '../lib/lib'
35const buttonTriState = status => {
36 if (status === null) return 'blue'
37 if (status === false) return 'yellow'
38 if (status === true) return 'green'
41const buttonTriStateText = status => {
42 if (status === null) return 'Confirm Galaxy Availablility'
43 if (status === false) return 'Galaxy is Not Available'
44 if (status === true) return 'Galaxy is Available'
49class CreateGalaxy extends React.Component {
50 constructor(props) {
51 super(props)
53 const galaxyOwner = props.wallet.matchWith({
54 Just: (wal) => addressFromSecp256k1Public(wal.value.publicKey),
55 Nothing: () => {
56 throw BRIDGE_ERROR.MISSING_WALLET
57 }
58 })
60 this.state = {
61 galaxyOwner: galaxyOwner,
62 galaxyName: '',
63 isAvailable: null,
64 txApproval: false,
65 nonce: '',
66 gasPrice: '5',
67 showGasDetails: false,
68 chainId: '',
69 txInfo: '',
70 gasLimit: '600000',
71 txn: Maybe.Nothing(),
72 stx: Maybe.Nothing(),
73 }
75 this.handleAddressInput = this.handleAddressInput.bind(this)
76 this.handleGalaxyNameInput = this.handleGalaxyNameInput.bind(this)
77 this.confirmAvailability = this.confirmAvailability.bind(this)
78 this.handleSubmit = this.handleSubmit.bind(this)
79 this.toggleGasDetails = this.toggleGasDetails.bind(this)
80 }
82 toggleGasDetails() {
83 this.setState({
84 showGasDetails: !this.state.showGasDetails
85 })
86 }
88 componentDidMount() {
89 const { props } = this
90 const addr = props.wallet.matchWith({
91 Just: wal => addressFromSecp256k1Public(wal.value.publicKey),
92 Nothing: () => {
93 throw BRIDGE_ERROR.MISSING_WALLET
94 }
95 })
97 // getTxnInfo(props.web3.value, addr).then(txInfo => this.setState(txInfo))
98 props.web3.map(w3 => getTxnInfo(w3, addr)
99 .then(txInfo => this.setState(txInfo))
100 )
101 }
104 handleGalaxyNameInput = (galaxyName) => {
105 this.setState({ galaxyName, isAvailable: null })
106 this.clearTransaction()
107 }
109 handleAddressInput = (galaxyOwner) => {
110 this.setState({ galaxyOwner })
111 this.clearTransaction()
112 }
114 createUnsignedTxn = () => {
115 const { state, props } = this
116 if (isValidAddress(state.galaxyOwner) === false) return Maybe.Nothing()
117 if (state.isAvailable === false) return Maybe.Nothing()
118 if (canDecodePatp(state.galaxyName) === false) return Maybe.Nothing()
119 if (isValidGalaxy(state.galaxyName) === false) return Maybe.Nothing()
121 const validContracts = props.contracts.matchWith({
122 Just: (cs) => cs.value,
123 Nothing: () => {
124 throw BRIDGE_ERROR.MISSING_CONTRACTS
125 }
126 })
128 const galaxyDec = parseInt(ob.patp2dec(state.galaxyName), 10)
130 const txn = azimuth.ecliptic.createGalaxy(
131 validContracts,
132 galaxyDec,
133 state.galaxyOwner
134 )
136 this.setState({ txn: Maybe.Just(txn) })
137 }
140 handleSubmit = () => {
141 const { props, state } = this
142 sendSignedTransaction(props.web3.value, state.stx)
143 .then(sent => {
144 props.setTxnHashCursor(sent)
145 props.popRoute()
146 props.pushRoute(ROUTE_NAMES.SENT_TRANSACTION)
147 })
148 }
150 confirmAvailability = async () => {
151 const { state, props } = this
153 if (canDecodePatp(state.galaxyName) === false) {
154 this.setState({ isAvailable: false })
155 return
156 }
158 const validContracts = props.contracts.matchWith({
159 Just: (cs) => cs.value,
160 Nothing: () => {
161 throw BRIDGE_ERROR.MISSING_CONTRACTS
162 }
163 })
165 const galaxyDec = ob.patp2dec(state.galaxyName)
167 const currentOwner = await azimuth.azimuth.getOwner(
168 validContracts,
169 galaxyDec
170 )
172 const available = eqAddr(currentOwner, ETH_ZERO_ADDR)
174 this.setState({ isAvailable: available })
175 }
178 clearTransaction = () => {
179 this.setState({
180 txApproval: false,
181 txn: Maybe.Nothing(),
182 stx: Maybe.Nothing(),
183 })
184 }
186 render() {
187 const { props, state } = this
189 const validAddress = isValidAddress(state.galaxyOwner)
190 const validGalaxy = isValidGalaxy(state.galaxyName)
192 const esvisible =
193 props.networkType === NETWORK_NAMES.ROPSTEN ||
194 props.networkType === NETWORK_NAMES.MAINNET
196 const esdomain =
197 props.networkType === NETWORK_NAMES.ROPSTEN
198 ? "ropsten.etherscan.io"
199 : "etherscan.io"
201 return (
202 <Row>
203 <Col>
204 <H1> { 'Create a Galaxy' } </H1>
206 <P>
207 {
208 'Enter the galaxy to create and the address that will own ' +
209 'it (defaulting to this account, if not provided).'
210 }
211 </P>
213 <GalaxyInput
214 className='mono'
215 prop-size='lg'
216 prop-format='innerLabel'
217 autoFocus
218 placeholder='e.g. ~zod'
219 value={state.galaxyName}
220 onChange={v => this.handleGalaxyNameInput(v)}>
221 <InnerLabel>{ 'Galaxy Name' }</InnerLabel>
222 <ValidatedSigil
223 className='tr-0 mt-05 mr-0 abs'
224 patp={state.galaxyName}
225 size={76}
226 margin={8} />
227 </GalaxyInput>
229 <AddressInput
230 className='mono mt-8'
231 prop-size='lg'
232 prop-format='innerLabel'
233 value={ state.galaxyOwner }
234 onChange={ v => this.handleAddressInput(v) }>
235 <InnerLabel>
236 { 'Address that will own this galaxy' }
237 </InnerLabel>
238 <ShowBlockie
239 className={'mt-1'}
240 address={state.galaxyOwner} />
241 </AddressInput>
243 <Anchor
244 className={'mt-1'}
245 prop-size={'sm'}
246 prop-disabled={!validAddress || !esvisible}
247 target={'_blank'}
248 href={`https://${esdomain}/address/${state.galaxyOwner}`}>
249 {'View on Etherscan ↗'}
250 </Anchor>
252 <Button
253 prop-size='lg wide'
254 className='mt-8'
255 prop-color={buttonTriState(state.isAvailable)}
256 disabled={!validGalaxy}
257 onClick={() => this.confirmAvailability()}>
258 {buttonTriStateText(state.isAvailable)}
259 </Button>
261 <StatelessTransaction
262 address={state.galaxyOwner}
263 shipName={state.galaxyName}
264 isAvailable={state.isAvailable}
265 web3={props.web3}
266 contracts={props.contracts}
267 wallet={props.wallet}
268 walletType={props.walletType}
269 walletHdPath={props.walletHdPath}
270 networkType={props.networkType}
271 // Tx
272 txApproval={state.txApproval}
273 txn={state.txn}
274 stx={state.stx}
275 nonce={state.nonce}
276 gasPrice={state.gasPrice}
277 showGasDetails={state.showGasDetails}
278 toggleGasDetails={this.toggleGasDetails}
279 chainId={state.chainId}
280 gasLimit={state.gasLimit}
281 canGenerate={
282 validAddress === true &&
283 validGalaxy === true &&
284 state.isAvailable === true
285 }
286 canSign={Maybe.Just.hasInstance(state.txn)}
287 canSend={Maybe.Just.hasInstance(state.stx)}
288 // Methods
289 createUnsignedTxn={() => this.createUnsignedTxn()}
290 clearTransaction={() => this.clearTransaction()}
291 setApproval={() => this.setState({txApproval: !state.txApproval})}
292 setTxn={txn => this.setState({txn})}
293 setStx={stx => this.setState({stx})}
294 setNonce={nonce => this.setState({nonce})}
295 setChainId={chainId => this.setState({chainId})}
296 setGasPrice={gasPrice => this.setState({gasPrice})}
297 setGasLimit={gasLimit => this.setState({gasLimit})}
298 handleSubmit={this.handleSubmit} />
300 </Col>
301 </Row>
302 )
303 }
309export default CreateGalaxy