on cf73cee help sign in
bridge/src/views/CreateGalaxy.js
299 lines 8.3 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 chainId: '',
68 txInfo: '',
69 gasLimit: '600000',
70 txn: Maybe.Nothing(),
71 stx: Maybe.Nothing(),
72 }
74 this.handleAddressInput = this.handleAddressInput.bind(this)
75 this.handleGalaxyNameInput = this.handleGalaxyNameInput.bind(this)
76 this.confirmAvailability = this.confirmAvailability.bind(this)
77 this.handleSubmit = this.handleSubmit.bind(this)
78 }
80 componentDidMount() {
81 const { props } = this
82 const addr = props.wallet.matchWith({
83 Just: wal => addressFromSecp256k1Public(wal.value.publicKey),
84 Nothing: () => {
85 throw BRIDGE_ERROR.MISSING_WALLET
86 }
87 })
89 // getTxnInfo(props.web3.value, addr).then(txInfo => this.setState(txInfo))
90 props.web3.map(w3 => getTxnInfo(w3, addr)
91 .then(txInfo => this.setState(txInfo))
92 )
93 }
96 handleGalaxyNameInput = (galaxyName) => {
97 this.setState({ galaxyName, isAvailable: null })
98 this.clearTransaction()
99 }
101 handleAddressInput = (galaxyOwner) => {
102 this.setState({ galaxyOwner })
103 this.clearTransaction()
104 }
106 createUnsignedTxn = () => {
107 const { state, props } = this
108 if (isValidAddress(state.galaxyOwner) === false) return Maybe.Nothing()
109 if (state.isAvailable === false) return Maybe.Nothing()
110 if (canDecodePatp(state.galaxyName) === false) return Maybe.Nothing()
111 if (isValidGalaxy(state.galaxyName) === false) return Maybe.Nothing()
113 const validContracts = props.contracts.matchWith({
114 Just: (cs) => cs.value,
115 Nothing: () => {
116 throw BRIDGE_ERROR.MISSING_CONTRACTS
117 }
118 })
120 const galaxyDec = parseInt(ob.patp2dec(state.galaxyName), 10)
122 const txn = azimuth.ecliptic.createGalaxy(
123 validContracts,
124 galaxyDec,
125 state.galaxyOwner
126 )
128 this.setState({ txn: Maybe.Just(txn) })
129 }
132 handleSubmit = () => {
133 const { props, state } = this
134 sendSignedTransaction(props.web3.value, state.stx)
135 .then(sent => {
136 props.setTxnHashCursor(sent)
137 props.popRoute()
138 props.pushRoute(ROUTE_NAMES.SENT_TRANSACTION)
139 })
140 }
142 confirmAvailability = async () => {
143 const { state, props } = this
145 if (canDecodePatp(state.galaxyName) === false) {
146 this.setState({ isAvailable: false })
147 return
148 }
150 const validContracts = props.contracts.matchWith({
151 Just: (cs) => cs.value,
152 Nothing: () => {
153 throw BRIDGE_ERROR.MISSING_CONTRACTS
154 }
155 })
157 const galaxyDec = ob.patp2dec(state.galaxyName)
159 const currentOwner = await azimuth.azimuth.getOwner(
160 validContracts,
161 galaxyDec
162 )
164 const available = eqAddr(currentOwner, ETH_ZERO_ADDR)
166 this.setState({ isAvailable: available })
167 }
170 clearTransaction = () => {
171 this.setState({
172 txApproval: false,
173 txn: Maybe.Nothing(),
174 stx: Maybe.Nothing(),
175 })
176 }
178 render() {
179 const { props, state } = this
181 const validAddress = isValidAddress(state.galaxyOwner)
182 const validGalaxy = isValidGalaxy(state.galaxyName)
184 const esvisible =
185 props.networkType === NETWORK_NAMES.ROPSTEN ||
186 props.networkType === NETWORK_NAMES.MAINNET
188 const esdomain =
189 props.networkType === NETWORK_NAMES.ROPSTEN
190 ? "ropsten.etherscan.io"
191 : "etherscan.io"
193 return (
194 <Row>
195 <Col>
196 <H1> { 'Create a Galaxy' } </H1>
198 <P>
199 {
200 'Enter the galaxy to create and the address that will own ' +
201 'it (defaulting to this account, if not provided).'
202 }
203 </P>
205 <GalaxyInput
206 className='mono'
207 prop-size='lg'
208 prop-format='innerLabel'
209 autoFocus
210 placeholder='e.g. ~zod'
211 value={state.galaxyName}
212 onChange={v => this.handleGalaxyNameInput(v)}>
213 <InnerLabel>{ 'Galaxy Name' }</InnerLabel>
214 <ValidatedSigil
215 className='tr-0 mt-05 mr-0 abs'
216 patp={state.galaxyName}
217 size={76}
218 margin={8} />
219 </GalaxyInput>
221 <AddressInput
222 className='mono mt-8'
223 prop-size='lg'
224 prop-format='innerLabel'
225 value={ state.galaxyOwner }
226 onChange={ v => this.handleAddressInput(v) }>
227 <InnerLabel>
228 { 'Address that will own this galaxy' }
229 </InnerLabel>
230 <ShowBlockie
231 className={'mt-1'}
232 address={state.galaxyOwner} />
233 </AddressInput>
235 <Anchor
236 className={'mt-1'}
237 prop-size={'sm'}
238 prop-disabled={!validAddress || !esvisible}
239 target={'_blank'}
240 href={`https://${esdomain}/address/${state.galaxyOwner}`}>
241 {'View on Etherscan ↗'}
242 </Anchor>
244 <Button
245 prop-size='lg wide'
246 className='mt-8'
247 prop-color={buttonTriState(state.isAvailable)}
248 disabled={!validGalaxy}
249 onClick={() => this.confirmAvailability()}>
250 {buttonTriStateText(state.isAvailable)}
251 </Button>
253 <StatelessTransaction
254 address={state.galaxyOwner}
255 shipName={state.galaxyName}
256 isAvailable={state.isAvailable}
257 web3={props.web3}
258 contracts={props.contracts}
259 wallet={props.wallet}
260 walletType={props.walletType}
261 walletHdPath={props.walletHdPath}
262 networkType={props.networkType}
263 // Tx
264 txApproval={state.txApproval}
265 txn={state.txn}
266 stx={state.stx}
267 nonce={state.nonce}
268 gasPrice={state.gasPrice}
269 chainId={state.chainId}
270 gasLimit={state.gasLimit}
271 canGenerate={
272 validAddress === true &&
273 validGalaxy === true &&
274 state.isAvailable === true
275 }
276 canSign={!Maybe.Nothing.hasInstance(state.txn)}
277 canSend={!Maybe.Nothing.hasInstance(state.stx)}
278 // Methods
279 createUnsignedTxn={() => this.createUnsignedTxn()}
280 clearTransaction={() => this.clearTransaction()}
281 setApproval={() => this.setState({txApproval: !state.txApproval})}
282 setTxn={txn => this.setState({txn})}
283 setStx={stx => this.setState({stx})}
284 setNonce={nonce => this.setState({nonce})}
285 setChainId={chainId => this.setState({chainId})}
286 setGasPrice={gasPrice => this.setState({gasPrice})}
287 setGasLimit={gasLimit => this.setState({gasLimit})}
288 handleSubmit={this.handleSubmit} />
290 </Col>
291 </Row>
292 )
293 }
299export default CreateGalaxy