mirror of
https://github.com/kremalicious/blog.git
synced 2024-12-22 17:23:50 +01:00
refactor web3
This commit is contained in:
parent
5426c3b646
commit
32faba15eb
15880
package-lock.json
generated
15880
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -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",
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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}>
|
||||
|
72
src/components/molecules/Web3Donation/connectors.tsx
Normal file
72
src/components/molecules/Web3Donation/connectors.tsx
Normal 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
|
||||
}
|
@ -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;
|
||||
|
@ -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
|
||||
// }
|
||||
// })
|
||||
// })
|
||||
// }
|
||||
|
@ -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]
|
||||
|
@ -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%;
|
||||
|
||||
|
@ -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')
|
||||
)
|
||||
@ -45,22 +47,32 @@ export default function Thanks() {
|
||||
<header>
|
||||
<h1 className={styles.title}>Say Thanks</h1>
|
||||
</header>
|
||||
|
||||
<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
|
||||
fallback={<div className={styles.loading}>Loading...</div>}
|
||||
address={author.ether}
|
||||
/>
|
||||
<Web3Donation fallback={<div className={styles.loading}>Loading...</div>} address={author.ether} />
|
||||
</div>
|
||||
|
||||
<div className={styles.coins}>
|
||||
<header>
|
||||
<h4>Any other wallets</h4>
|
||||
<p>Send Bitcoin or Ether from any wallet.</p>
|
||||
</header>
|
||||
<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>
|
||||
{coins.map((address: string) => (
|
||||
<Coin
|
||||
key={shortid.generate()}
|
||||
address={address}
|
||||
author={author}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</Web3Provider>
|
||||
</article>
|
||||
</>
|
||||
)
|
||||
|
105
src/pages/thanks.tsx.orig
Normal file
105
src/pages/thanks.tsx.orig
Normal 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>
|
||||
</>
|
||||
)
|
||||
}
|
Loading…
Reference in New Issue
Block a user