1import Maybe from 'folktale/maybe'
2import React from 'react'
3import * as azimuth from 'azimuth-js'
4import * as ob from 'urbit-ob'
6import { Row, Col, H1, InnerLabel, ShowBlockie, P, Anchor } from '../components/Base'
7import { AddressInput, Warning, H3 } from '../components/Base'
8import StatelessTransaction from '../components/StatelessTransaction'
10import { BRIDGE_ERROR } from '../lib/error'
11import { NETWORK_NAMES } from '../lib/network'
12import { ROUTE_NAMES } from '../lib/router'
15 sendSignedTransaction,
21 addressFromSecp256k1Public
22 } from '../lib/wallet'
24class Transfer extends React.Component {
28 const issuingPoint = props.pointCursor.matchWith({
29 Just: (pt) => pt.value,
31 throw BRIDGE_ERROR.MISSING_POINT
36 txError: Maybe.Nothing(),
38 issuingPoint: issuingPoint,
47 this.handleAddressInput = this.handleAddressInput.bind(this)
49 this.handleCreateUnsignedTxn = this.handleCreateUnsignedTxn.bind(this)
50 this.handleSubmit = this.handleSubmit.bind(this)
51 this.handleSetUserApproval = this.handleSetUserApproval.bind(this)
52 this.handleSetTxn = this.handleSetTxn.bind(this)
53 this.handleSetStx = this.handleSetStx.bind(this)
54 this.handleSetNonce = this.handleSetNonce.bind(this)
55 this.handleSetChainId = this.handleSetChainId.bind(this)
56 this.handleSetGasPrice = this.handleSetGasPrice.bind(this)
57 this.handleSetGasLimit = this.handleSetGasLimit.bind(this)
62 const { props } = this
64 const addr = props.wallet.matchWith({
65 Just: wal => addressFromSecp256k1Public(wal.value.publicKey),
67 throw BRIDGE_ERROR.MISSING_WALLET
71 props.web3.matchWith({
74 const validWeb3 = w3.value
76 const getTxMetadata = [
77 validWeb3.eth.getTransactionCount(addr),
78 validWeb3.eth.net.getId(),
79 validWeb3.eth.getGasPrice()
82 Promise.all(getTxMetadata).then(r => {
86 gasPrice: fromWei(r[2], 'gwei'),
89 this.setState({...txMetadata})
99 handleAddressInput(receivingAddress) {
100 this.setState({ receivingAddress })
101 this.handleClearTxn()
106 handleConfirmAvailability() {
107 this.confirmPointAvailability().then(r => {
108 this.setState({ isAvailable: r })
114 handleCreateUnsignedTxn() {
115 const txn = this.createUnsignedTxn()
116 this.setState({ txn })
120 handleSetUserApproval(){
122 this.setState({ userApproval: !state.userApproval })
128 this.setState({ txn })
142 handleSetNonce(nonce){
143 this.setState({ nonce })
144 this.handleClearStx()
149 handleSetChainId(chainId){
150 this.setState({ chainId })
151 this.handleClearStx()
156 handleSetGasPrice(gasPrice){
157 this.setState({ gasPrice })
158 this.handleClearStx()
163 handleSetGasLimit(gasLimit){
164 this.setState({ gasLimit })
165 this.handleClearStx()
173 stx: Maybe.Nothing(),
182 txn: Maybe.Nothing(),
183 stx: Maybe.Nothing(),
189 handleClearTransaction() {
192 txn: Maybe.Nothing(),
193 stx: Maybe.Nothing(),
200 const { props, state } = this
201 sendSignedTransaction(props.web3.value, state.stx)
203 props.setTxnCursor(sent)
205 props.pushRoute(ROUTE_NAMES.SENT_TRANSACTION)
208 // Note that value.value is due to wrapped Maybe.Just + Result.Error
209 this.setState({ txError: Maybe.Just(err.value.value) })
215 createUnsignedTxn() {
216 const { state, props } = this
218 const validContracts = props.contracts.matchWith({
219 Just: (cs) => cs.value,
221 throw BRIDGE_ERROR.MISSING_CONTRACTS
225 const validPoint = props.pointCursor.matchWith({
226 Just: (shp) => shp.value,
228 throw BRIDGE_ERROR.MISSING_POINTs
232 const txn = azimuth.ecliptic.setTransferProxy(
235 state.receivingAddress
238 return Maybe.Just(txn)
244 const { props, state } = this
246 const validAddress = isValidAddress(state.receivingAddress)
248 const canGenerate = validAddress === true
250 const canSign = !Maybe.Nothing.hasInstance(state.txn)
251 const canApprove = !Maybe.Nothing.hasInstance(state.stx)
252 const canSend = !Maybe.Nothing.hasInstance(state.stx) && state.userApproval === true
255 props.networkType === NETWORK_NAMES.ROPSTEN ||
256 props.networkType === NETWORK_NAMES.MAINNET
259 props.networkType === NETWORK_NAMES.ROPSTEN
260 ? "ropsten.etherscan.io"
267 { 'Transfer'} <code>{ ` ${ob.patp(state.issuingPoint)} ` }</code>
273 `Please provide the Ethereum address of the new owner. You own these
274 points until the recipient accepts the incoming transfer.
275 You may cancel the transfer until the transfer is accepted.`
280 className={'mono mt-8'}
282 prop-format='innerLabel'
283 value={ state.receivingAddress }
284 placeholder={ `e.g. 0x84295d5e054d8cff5a22428b195f5a1615bd644f` }
285 onChange={ v => this.handleAddressInput(v) }>
286 <InnerLabel>{ 'New ownership address' }</InnerLabel>
287 <ShowBlockie className={'mt-1'} address={state.receivingAddress} />
293 prop-disabled={!isValidAddress(state.receivingAddress) || !esvisible}
295 href={`https://${esdomain}/address/${state.receivingAddress}`}>
296 {'View on Etherscan ↗'}
299 <StatelessTransaction
302 contracts={props.contracts}
303 wallet={props.wallet}
304 walletType={props.walletType}
305 walletHdPath={props.walletHdPath}
306 networkType={props.networkType}
312 gasPrice={state.gasPrice}
313 chainId={state.chainId}
314 gasLimit={state.gasLimit}
316 userApproval={state.userApproval}
317 canGenerate={ canGenerate }
319 canApprove={ canApprove }
322 createUnsignedTxn={this.handleCreateUnsignedTxn}
323 setUserApproval={this.handleSetUserApproval}
324 setTxn={this.handleSetTxn}
325 setStx={this.handleSetStx}
326 setNonce={this.handleSetNonce}
327 setChainId={this.handleSetChainId}
328 setGasPrice={this.handleSetGasPrice}
329 setGasLimit={this.handleSetGasLimit}
330 handleSubmit={this.handleSubmit} />
333 Maybe.Nothing.hasInstance(state.txError)
335 : <Warning className={'mt-8'}>
336 <H3 style={{marginTop: 0, paddingTop: 0}}>
338 'There was an error sending your transaction.'
341 { state.txError.value }
351export default Transfer
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list