import React from "react" import PropTypes from "prop-types" import { Alert, Button } from "react-bootstrap" import { NETWORKS, humanReadableDerivationPath, maskKey, } from "@swan-bitcoin/xpub-lib" import { ExportExtendedPublicKey, PENDING, ACTIVE, UNSUPPORTED, } from "unchained-wallets" class ExtPubKeyImporter extends React.Component { constructor(props) { super(props) this.state = { keystoreState: this.interaction().isSupported() ? PENDING : UNSUPPORTED, extPubKey: "", error: "", } this.importExtPubKey = this.importExtPubKey.bind(this) } interaction() { const { network, bip32Path, keystore } = this.props return ExportExtendedPublicKey({ keystore, network, bip32Path }) } async importExtPubKey() { this.setState({ keystoreState: ACTIVE }) try { // This is where we actually talk to the hardware wallet. const extPubKey = await this.interaction().run() // If we succeed, reset the keystore state // and store the imported public key. this.setState({ keystoreState: PENDING, extPubKey }) } catch (e) { // Something went wrong; revert the keystore // state and track the error message. this.setState({ keystoreState: PENDING, error: e.message }) } } renderMessages() { const { keystoreState } = this.state // Here we grab just the messages relevant for the // current keystore state, but more complex filtering is possible... const messages = this.interaction().messagesFor({ state: keystoreState }) return messages.map(ExtPubKeyImporter.renderMessage) } static renderMessage(message, i) { // The `message` object will always have a `text` property // but may have additional properties useful for display. return ( <Alert variant="info" key={i}> {message.text} </Alert> ) } render() { const { keystoreState, extPubKey, error } = this.state const { bip32Path } = this.props return ( <div> <h3> {humanReadableDerivationPath({ bip32Path })} <code>{bip32Path}</code> </h3> {extPubKey ? ( <div> <Alert key={bip32Path} variant="success" dismissible> Imported {humanReadableDerivationPath({ bip32Path })} </Alert> <p> <code>{maskKey(extPubKey)}</code> <Button variant="light" title="Copy to clipboard" onClick={() => { navigator.clipboard.writeText(extPubKey) }} > <span role="img" aria-label="Copy to clipboard"> 📋 </span> </Button> </p> </div> ) : ( <div> {this.renderMessages()} {error && <Alert type="danger">{error}</Alert>} <Button variant="outline-primary" disabled={keystoreState !== PENDING} onClick={this.importExtPubKey} title={humanReadableDerivationPath({ bip32Path })} > Import {bip32Path} </Button> </div> )} <hr /> </div> ) } } ExtPubKeyImporter.propTypes = { network: PropTypes.oneOf(Object.values(NETWORKS)).isRequired, bip32Path: PropTypes.string.isRequired, keystore: PropTypes.string.isRequired, } export { ExtPubKeyImporter }