on 36b05fc help sign in
bridge/src/views/CreateGalaxy.js
288 lines 8.0 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 {
14 sendSignedTransaction,
15 getTxnInfo,
16 canDecodePatp
17} from '../lib/txn'
19import { ROUTE_NAMES } from '../lib/router'
21import {
22 addressFromSecp256k1Public,
23 ETH_ZERO_ADDR,
24 isValidAddress,
25 eqAddr
26} from '../lib/wallet'
28import {
29 isValidGalaxy
30} from '../lib/lib'
33const buttonTriState = status => {
34 if (status === null) return 'blue'
35 if (status === false) return 'yellow'
36 if (status === true) return 'green'
39const buttonTriStateText = status => {
40 if (status === null) return 'Confirm Galaxy Availablility'
41 if (status === false) return 'Galaxy is Not Available'
42 if (status === true) return 'Galaxy is Available'
47class CreateGalaxy extends React.Component {
48 constructor(props) {
49 super(props)
51 const galaxyOwner = props.wallet.matchWith({
52 Just: (wal) => addressFromSecp256k1Public(wal.value.publicKey),
53 Nothing: () => {
54 throw BRIDGE_ERROR.MISSING_WALLET
55 }
56 })
58 this.state = {
59 galaxyOwner: galaxyOwner,
60 galaxyName: '',
61 isAvailable: null,
62 txApproval: false,
63 nonce: '',
64 gasPrice: '5',
65 chainId: '',
66 txInfo: '',
67 gasLimit: '600000',
68 txn: Maybe.Nothing(),
69 stx: Maybe.Nothing(),
70 }
72 this.handleAddressInput = this.handleAddressInput.bind(this)
73 this.handleGalaxyNameInput = this.handleGalaxyNameInput.bind(this)
74 this.confirmAvailability = this.confirmAvailability.bind(this)
75 this.handleSubmit = this.handleSubmit.bind(this)
76 }
78 componentDidMount() {
79 const { props } = this
80 const addr = props.wallet.matchWith({
81 Just: wal => addressFromSecp256k1Public(wal.value.publicKey),
82 Nothing: () => {
83 throw BRIDGE_ERROR.MISSING_WALLET
84 }
85 })
87 // getTxnInfo(props.web3.value, addr).then(txInfo => this.setState(txInfo))
88 props.web3.map(w3 => getTxnInfo(w3, addr)
89 .then(txInfo => this.setState(txInfo))
90 )
91 }
94 handleGalaxyNameInput = (galaxyName) => {
95 this.setState({ galaxyName, isAvailable: null })
96 this.clearTransaction()
97 }
99 handleAddressInput = (galaxyOwner) => {
100 this.setState({ galaxyOwner })
101 this.clearTransaction()
102 }
104 createUnsignedTxn = () => {
105 const { state, props } = this
106 if (isValidAddress(state.galaxyOwner) === false) return Maybe.Nothing()
107 if (state.isAvailable === false) return Maybe.Nothing()
108 if (canDecodePatp(state.galaxyName) === false) return Maybe.Nothing()
109 if (isValidGalaxy(state.galaxyName) === false) return Maybe.Nothing()
111 const validContracts = props.contracts.matchWith({
112 Just: (cs) => cs.value,
113 Nothing: () => {
114 throw BRIDGE_ERROR.MISSING_CONTRACTS
115 }
116 })
118 const galaxyDec = parseInt(ob.patp2dec(state.galaxyName), 10)
120 const txn = azimuth.ecliptic.createGalaxy(
121 validContracts,
122 galaxyDec,
123 state.galaxyOwner
124 )
126 this.setState({ txn: Maybe.Just(txn) })
127 }
130 handleSubmit = () => {
131 const { props, state } = this
132 sendSignedTransaction(props.web3.value, state.stx)
133 .then(sent => {
134 props.setTxnCursor(sent)
135 props.popRoute()
136 props.pushRoute(ROUTE_NAMES.SENT_TRANSACTION)
137 })
138 }
140 confirmAvailability = async () => {
141 const { state, props } = this
143 if (canDecodePatp(state.galaxyName) === false) {
144 this.setState({ isAvailable: false })
145 return
146 }
148 const validContracts = props.contracts.matchWith({
149 Just: (cs) => cs.value,
150 Nothing: () => {
151 throw BRIDGE_ERROR.MISSING_CONTRACTS
152 }
153 })
155 const galaxyDec = ob.patp2dec(state.galaxyName)
157 const currentOwner = await azimuth.azimuth.getOwner(
158 validContracts,
159 galaxyDec
160 )
162 const available = eqAddr(currentOwner, ETH_ZERO_ADDR)
164 this.setState({ isAvailable: available })
165 }
168 clearTransaction = () => {
169 this.setState({
170 txApproval: false,
171 txn: Maybe.Nothing(),
172 stx: Maybe.Nothing(),
173 })
174 }
176 render() {
177 const { props, state } = this
179 const validAddress = isValidAddress(state.galaxyOwner)
180 const validGalaxy = isValidGalaxy(state.galaxyName)
183 return (
184 <Row>
185 <Col>
186 <H1> { 'Create a Galaxy' } </H1>
188 <P>
189 {
190 'Enter the galaxy to create and the address that will own ' +
191 'it (defaulting to this account, if not provided).'
192 }
193 </P>
195 <GalaxyInput
196 className='mono'
197 prop-size='lg'
198 prop-format='innerLabel'
199 autoFocus
200 placeholder='e.g. ~zod'
201 value={state.galaxyName}
202 onChange={v => this.handleGalaxyNameInput(v)}>
203 <InnerLabel>{ 'Galaxy Name' }</InnerLabel>
204 <ValidatedSigil
205 className='tr-0 mt-05 mr-0 abs'
206 patp={state.galaxyName}
207 size={76}
208 margin={8} />
209 </GalaxyInput>
211 <AddressInput
212 className='mono mt-8'
213 prop-size='lg'
214 prop-format='innerLabel'
215 value={ state.galaxyOwner }
216 onChange={ v => this.handleAddressInput(v) }>
217 <InnerLabel>
218 { 'Address that will own this galaxy' }
219 </InnerLabel>
220 <ShowBlockie
221 className={'mt-1'}
222 address={state.galaxyOwner} />
223 </AddressInput>
225 <Anchor
226 className={'mt-1'}
227 prop-size={'sm'}
228 prop-disabled={!validAddress}
229 target={'_blank'}
230 href={`https://etherscan.io/address/${state.galaxyOwner}`}>
231 {'View on Etherscan ↗'}
232 </Anchor>
234 <Button
235 prop-size='lg wide'
236 className='mt-8'
237 prop-color={buttonTriState(state.isAvailable)}
238 disabled={!validGalaxy}
239 onClick={() => this.confirmAvailability()}>
240 {buttonTriStateText(state.isAvailable)}
241 </Button>
243 <StatelessTransaction
244 address={state.galaxyOwner}
245 shipName={state.galaxyName}
246 isAvailable={state.isAvailable}
247 web3={props.web3}
248 contracts={props.contracts}
249 wallet={props.wallet}
250 walletType={props.walletType}
251 walletHdPath={props.walletHdPath}
252 // Tx
253 txApproval={state.txApproval}
254 txn={state.txn}
255 stx={state.stx}
256 nonce={state.nonce}
257 gasPrice={state.gasPrice}
258 chainId={state.chainId}
259 gasLimit={state.gasLimit}
260 canGenerate={
261 validAddress === true &&
262 validGalaxy === true &&
263 state.isAvailable === true
264 }
265 canSign={!Maybe.Nothing.hasInstance(state.txn)}
266 canSend={!Maybe.Nothing.hasInstance(state.stx)}
267 // Methods
268 createUnsignedTxn={() => this.createUnsignedTxn()}
269 clearTransaction={() => this.clearTransaction()}
270 setApproval={() => this.setState({txApproval: !state.txApproval})}
271 setTxn={txn => this.setState({txn})}
272 setStx={stx => this.setState({stx})}
273 setNonce={nonce => this.setState({nonce})}
274 setChainId={chainId => this.setState({chainId})}
275 setGasPrice={gasPrice => this.setState({gasPrice})}
276 setGasLimit={gasLimit => this.setState({gasLimit})}
277 handleSubmit={this.handleSubmit} />
279 </Col>
280 </Row>
281 )
282 }
288export default CreateGalaxy