1
0
mirror of https://github.com/kremalicious/blog.git synced 2024-11-26 11:49:04 +01:00

refactor web3

This commit is contained in:
Matthias Kretschmann 2019-11-21 21:32:55 +01:00
parent 5426c3b646
commit 32faba15eb
Signed by: m
GPG Key ID: 606EEEF3C479A91F
11 changed files with 15225 additions and 1275 deletions

15880
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -82,7 +82,7 @@
"remark-react": "^6.0.0",
"slugify": "^1.3.6",
"use-dark-mode": "^2.3.1",
"web3": "^1.2.4"
"web3-react": "^5.0.5"
},
"devDependencies": {
"@babel/node": "^7.7.0",

View File

@ -1,5 +1,5 @@
import React, { PureComponent } from 'react'
import { getFiat, Logger } from './utils'
import { getFiat } from './utils'
import styles from './Conversion.module.scss'
export default class Conversion extends PureComponent<
@ -28,7 +28,7 @@ export default class Conversion extends PureComponent<
const { dollar, euro } = await getFiat(this.props.amount)
this.setState({ euro, dollar })
} catch (error) {
Logger.error(error.message)
console.error(error.message)
}
}

View File

@ -29,7 +29,7 @@ export default function InputGroup({
<span>ETH</span>
</div>
</div>
<button className="btn btn-primary" onClick={sendTransaction}>
<button className="btn btn-primary" onClick={() => sendTransaction()}>
Make it rain
</button>
<div className={styles.infoline}>

View File

@ -0,0 +1,72 @@
import { Connectors } from 'web3-react'
// import TrezorApi from 'trezor-connect'
// import WalletConnectApi from '@walletconnect/web3-subprovider'
// import FortmaticApi from 'fortmatic'
// import PortisApi from '@portis/web3'
const {
InjectedConnector
// NetworkOnlyConnector,
// TrezorConnector,
// LedgerConnector,
// WalletConnectConnector,
// FortmaticConnector,
// PortisConnector
} = Connectors
// const supportedNetworkURLs = {
// 1: 'https://mainnet.infura.io/v3/60ab76e16df54c808e50a79975b4779f',
// 4: 'https://rinkeby.infura.io/v3/60ab76e16df54c808e50a79975b4779f'
// }
// const defaultNetwork = 1
const MetaMask = new InjectedConnector({
supportedNetworks: [1]
})
// const Network = new NetworkOnlyConnector({
// providerURL: supportedNetworkURLs[1]
// })
// const Trezor = new TrezorConnector({
// api: TrezorApi,
// supportedNetworkURLs,
// defaultNetwork,
// manifestEmail: 'noahwz@gmail.com',
// manifestAppUrl: 'https://codesandbox.io/s/6v5nrq2nqw'
// })
// const Ledger = new LedgerConnector({
// supportedNetworkURLs,
// defaultNetwork
// })
// const WalletConnect = new WalletConnectConnector({
// api: WalletConnectApi,
// bridge: 'https://bridge.walletconnect.org',
// supportedNetworkURLs,
// defaultNetwork
// })
// const Fortmatic = new FortmaticConnector({
// api: FortmaticApi,
// apiKey: 'pk_live_F95FEECB1BE324B5',
// logoutOnDeactivation: false
// })
// const Portis = new PortisConnector({
// api: PortisApi,
// dAppId: '211b48db-e8cc-4b68-82ad-bf781727ea9e',
// network: 'mainnet'
// })
export default {
MetaMask
// Network,
// Trezor,
// Ledger,
// WalletConnect,
// Fortmatic,
// Portis
}

View File

@ -1,20 +1,6 @@
@import 'variables';
.web3 {
width: 100%;
text-align: center;
margin-top: $spacer / 2;
margin-bottom: $spacer;
padding-bottom: $spacer;
small {
color: darken($alert-info, 60%);
margin-top: -($spacer / 2);
display: block;
}
}
.web3Row {
min-height: 77px;
display: flex;
align-items: center;

View File

@ -1,210 +1,109 @@
import React, { PureComponent } from 'react'
import Web3 from 'web3'
import React, { useEffect, useState } from 'react'
import { useWeb3Context } from 'web3-react'
import InputGroup from './InputGroup'
import Alerts, { alertMessages } from './Alerts'
import styles from './index.module.scss'
import { getWeb3, getAccounts, getNetwork } from './utils'
const ONE_SECOND = 1000
const ONE_MINUTE = ONE_SECOND * 60
const correctNetwork = 1
export default function Web3Donation({ address }: { address: string }) {
const {
setFirstValidConnector,
error,
library,
active,
account
} = useWeb3Context()
const [amount, setAmount] = useState(0.03)
const [message, setMessage] = useState()
interface Web3DonationState {
netId: number
networkName: string
accounts: string[]
selectedAccount: string
amount: number
transactionHash: string
receipt: string
message: {
status?: string
text?: string
}
inTransaction: boolean
}
useEffect(() => {
setFirstValidConnector(['MetaMask'])
}, [])
export default class Web3Donation extends PureComponent<
{ address: string },
Web3DonationState
> {
state = {
netId: 0,
networkName: '',
accounts: [''],
selectedAccount: '',
amount: 0.01,
transactionHash: '',
receipt: '',
message: {},
inTransaction: false
}
web3: Web3 = null
interval: any = null
networkInterval: any = null
componentDidMount() {
this.initWeb3()
}
componentWillUnmount() {
this.resetAllTheThings()
}
initWeb3 = async () => {
this.setState({ message: { text: 'Checking' } })
try {
this.web3 = await getWeb3()
this.web3
? this.initAllTheTings()
: this.setState({
message: {
status: 'error',
text: alertMessages().noWeb3
}
})
} catch (error) {
this.setState({
message: { status: 'error', text: error }
})
}
}
async initAllTheTings() {
this.fetchAccounts()
this.fetchNetwork()
this.initAccountsPoll()
this.initNetworkPoll()
}
resetAllTheThings() {
clearInterval(this.interval)
clearInterval(this.networkInterval)
}
initAccountsPoll() {
if (!this.interval) {
this.interval = setInterval(this.fetchAccounts, ONE_SECOND * 10)
}
}
initNetworkPoll() {
if (!this.networkInterval) {
this.networkInterval = setInterval(this.fetchNetwork, ONE_MINUTE)
}
}
fetchNetwork = async () => {
const { web3 } = this
const { netId, networkName } = await getNetwork(web3)
if (netId === correctNetwork) {
this.setState({ netId, networkName })
} else {
this.setState({
message: {
status: 'error',
text: alertMessages(networkName).noCorrectNetwork
}
})
}
}
fetchAccounts = async () => {
const { web3 } = this
const accounts = await getAccounts(web3)
if (accounts[0]) {
this.setState({
accounts,
selectedAccount: accounts[0].toLowerCase()
})
} else {
this.setState({
message: {
status: 'error',
text: alertMessages().noAccount
}
})
}
}
sendTransaction = () => {
const { web3 } = this
this.setState({
inTransaction: true,
message: { text: alertMessages().waitingForUser }
error &&
setMessage({
status: 'error',
text: error.message
})
web3.eth
.sendTransaction({
from: this.state.selectedAccount,
to: this.props.address,
value: this.state.amount * 1e18 // ETH -> Wei
})
.once('transactionHash', transactionHash => {
this.setState({
transactionHash,
message: { text: alertMessages().waitingConfirmation }
})
})
.on('error', error =>
this.setState({
message: { status: 'error', text: error.message }
})
)
.then(() => {
this.setState({
message: {
status: 'success',
text: alertMessages().success
}
})
})
const [transactionHash, setTransactionHash] = useState(undefined)
async function sendTransaction() {
const signer = library.getSigner()
setMessage({
status: 'loading',
text: alertMessages().waitingForUser
})
const tx = await signer.sendTransaction({
to: address,
value: amount * 1e18 // ETH -> Wei
})
setTransactionHash(tx.hash)
setMessage({
status: 'loading',
text: alertMessages().waitingConfirmation
})
// setMessage({
// status: 'success',
// text: alertMessages().success
// })
}
onAmountChange = ({ target }: { target: any }) => {
this.setState({ amount: target.value })
const onAmountChange = ({ target }: { target: any }) => {
setAmount(target.value)
}
render() {
const {
selectedAccount,
amount,
transactionHash,
message,
inTransaction
} = this.state
return (
<div className={styles.web3}>
<header>
<h4>Web3 Wallet</h4>
<p>Send Ether with MetaMask or Brave.</p>
</header>
<div className={styles.web3Row}>
{selectedAccount &&
this.state.netId === correctNetwork &&
!inTransaction ? (
<InputGroup
selectedAccount={selectedAccount}
amount={amount}
onAmountChange={this.onAmountChange}
sendTransaction={this.sendTransaction}
/>
) : (
message && (
<Alerts message={message} transactionHash={transactionHash} />
)
)}
</div>
</div>
)
}
return (
<div className={styles.web3}>
{active && !message ? (
<InputGroup
selectedAccount={account}
amount={amount}
onAmountChange={onAmountChange}
sendTransaction={sendTransaction}
/>
) : (
message && (
<Alerts message={message} transactionHash={transactionHash} />
)
)}
</div>
)
}
// sendTransaction = () => {
// const { web3 } = this
// this.setState({
// inTransaction: true,
// message: { text: alertMessages().waitingForUser }
// })
// web3.eth
// .sendTransaction({
// from: this.state.selectedAccount,
// to: this.props.address,
// value: this.state.amount * 1e18 // ETH -> Wei
// })
// .once('transactionHash', transactionHash => {
// this.setState({
// transactionHash,
// message: { text: alertMessages().waitingConfirmation }
// })
// })
// .on('error', error =>
// this.setState({
// message: { status: 'error', text: error.message }
// })
// )
// .then(() => {
// this.setState({
// message: {
// status: 'success',
// text: alertMessages().success
// }
// })
// })
// }

View File

@ -1,34 +1,3 @@
import Web3 from 'web3'
declare global {
interface Window {
ethereum: any
web3: Web3
}
interface Console {
[key: string]: any
}
}
export class Logger {
static dispatch(verb: any, ...args: any) {
console[verb](...args)
}
static log(...args: any) {
Logger.dispatch('log', ...args)
}
static debug(...args: any) {
Logger.dispatch('debug', ...args)
}
static error(...args: any) {
Logger.dispatch('error', ...args)
}
}
export const getNetworkName = (netId: number) => {
let networkName
@ -55,53 +24,10 @@ export const getNetworkName = (netId: number) => {
return networkName
}
export const getWeb3 = async () => {
let web3
// Modern dapp browsers...
if (window.ethereum) {
web3 = new Web3(window.ethereum)
try {
// Request account access
await window.ethereum.enable()
return web3
} catch (error) {
// User denied account access...
Logger.error(error)
return error
}
}
// Legacy dapp browsers...
else if (window.web3) {
web3 = new Web3(window.web3.currentProvider)
return web3
}
// Non-dapp browsers...
else {
return
}
}
export const getAccounts = async (web3: Web3) => {
const ethAccounts = await web3.eth.getAccounts()
return ethAccounts
}
export const getNetwork = async (web3: Web3) => {
const netId = await web3.eth.net.getId()
const networkName = getNetworkName(netId)
return { netId, networkName }
}
export const getFiat = async (amount: number) => {
const url = 'https://api.coinmarketcap.com/v1/ticker/ethereum/?convert=EUR'
const response = await fetch(url)
if (!response.ok) Logger.error(response.statusText)
if (!response.ok) console.error(response.statusText)
const data = await response.json()
/* eslint-disable @typescript-eslint/camelcase */
const { price_usd, price_eur } = data[0]

View File

@ -61,6 +61,20 @@
font-size: $font-size-h2;
}
.web3 {
width: 100%;
text-align: center;
margin-top: $spacer / 2;
margin-bottom: $spacer * 2;
padding-bottom: $spacer;
small {
color: darken($alert-info, 60%);
margin-top: -($spacer / 2);
display: block;
}
}
.coins {
width: 100%;

View File

@ -6,8 +6,10 @@ import { Author } from '../@types/Site'
import { useSiteMetadata } from '../hooks/use-site-metadata'
import Qr from '../components/atoms/Qr'
import Icon from '../components/atoms/Icon'
import connectors from '../components/molecules/Web3Donation/connectors'
import styles from './thanks.module.scss'
const Web3Provider = loadable(() => import('web3-react'))
const Web3Donation = loadable(() =>
import('../components/molecules/Web3Donation')
)
@ -46,21 +48,31 @@ export default function Thanks() {
<h1 className={styles.title}>Say Thanks</h1>
</header>
<Web3Donation
fallback={<div className={styles.loading}>Loading...</div>}
address={author.ether}
/>
<Web3Provider connectors={connectors} libraryName={'ethers.js'}>
<div className={styles.web3}>
<header>
<h4>Web3 Wallet</h4>
<p>Send Ether with MetaMask or Brave.</p>
</header>
<div className={styles.coins}>
<header>
<h4>Any other wallets</h4>
<p>Send Bitcoin or Ether from any wallet.</p>
</header>
<Web3Donation fallback={<div className={styles.loading}>Loading...</div>} address={author.ether} />
</div>
{coins.map((address: string) => (
<Coin key={shortid.generate()} address={address} author={author} />
))}
</div>
<div className={styles.coins}>
<header>
<h4>Any other wallets</h4>
<p>Send Bitcoin or Ether from any wallet.</p>
</header>
{coins.map((address: string) => (
<Coin
key={shortid.generate()}
address={address}
author={author}
/>
))}
</div>
</Web3Provider>
</article>
</>
)

105
src/pages/thanks.tsx.orig Normal file
View File

@ -0,0 +1,105 @@
import React from 'react'
import loadable from '@loadable/component'
import shortid from 'shortid'
import Helmet from 'react-helmet'
import { Author } from '../@types/Site'
import { useSiteMetadata } from '../hooks/use-site-metadata'
import Qr from '../components/atoms/Qr'
import Icon from '../components/atoms/Icon'
import connectors from '../components/molecules/Web3Donation/connectors'
import styles from './thanks.module.scss'
<<<<<<< HEAD
const Web3Donation = loadable(() =>
import('../components/molecules/Web3Donation')
)
=======
const Web3Provider = lazy(() => import('web3-react'))
const Web3Donation = lazy(() => import('../components/molecules/Web3Donation'))
>>>>>>> refactor web3
const Coin = ({ address, author }: { address: string; author: Author }) => (
<div className={styles.coin}>
<Qr title={address} address={(author as any)[address]} />
</div>
)
const BackButton = () => (
<button
className={`link ${styles.buttonBack}`}
onClick={() => window.history.back()}
>
<Icon name="ChevronLeft" /> Go Back
</button>
)
export default function Thanks() {
const { author } = useSiteMetadata()
const coins = Object.keys(author).filter(
key => key === 'bitcoin' || key === 'ether'
)
return (
<>
<Helmet>
<title>Say thanks</title>
<meta name="robots" content="noindex,nofollow" />
</Helmet>
<article className={styles.thanks}>
<BackButton />
<header>
<h1 className={styles.title}>Say Thanks</h1>
</header>
<<<<<<< HEAD
<Web3Donation
fallback={<div className={styles.loading}>Loading...</div>}
address={author.ether}
/>
<div className={styles.coins}>
<header>
<h4>Any other wallets</h4>
<p>Send Bitcoin or Ether from any wallet.</p>
</header>
{coins.map((address: string) => (
<Coin key={shortid.generate()} address={address} author={author} />
))}
</div>
=======
{!isSSR && (
<Suspense fallback={<div className={styles.loading}>Loading...</div>}>
<Web3Provider connectors={connectors} libraryName={'ethers.js'}>
<div className={styles.web3}>
<header>
<h4>Web3 Wallet</h4>
<p>Send Ether with MetaMask or Brave.</p>
</header>
<Web3Donation address={author.ether} />
</div>
<div className={styles.coins}>
<header>
<h4>Any other wallets</h4>
<p>Send Bitcoin or Ether from any wallet.</p>
</header>
{coins.map((address: string) => (
<Coin
key={shortid.generate()}
address={address}
author={author}
/>
))}
</div>
</Web3Provider>
</Suspense>
)}
>>>>>>> refactor web3
</article>
</>
)
}