mirror of
https://github.com/stronk-dev/RandomChad.git
synced 2025-07-05 18:35:10 +02:00
301 lines
6.7 KiB
JavaScript
301 lines
6.7 KiB
JavaScript
import { useState, useEffect } from "react"
|
|
import { log, setListenerAndReturnUnlistener } from './helpers'
|
|
|
|
// Ethers and web3 sdk
|
|
import { ethers } from "ethers"
|
|
|
|
// Convenience objects
|
|
const { providers: { Web3Provider }, Contract } = ethers
|
|
export const provider = window.ethereum && new Web3Provider( window.ethereum )
|
|
export const signer = provider && provider.getSigner()
|
|
|
|
// ///////////////////////////////
|
|
// Chain interactors
|
|
// ///////////////////////////////
|
|
|
|
// Get address through metamask
|
|
export async function getAddress() {
|
|
|
|
// Check if web3 is exposed
|
|
if( !window.ethereum ) throw new Error( 'No web3 provider detected, please install metamask' )
|
|
|
|
// Get the first address ( which is the selected address )
|
|
const [ address ] = await window.ethereum.request( { method: 'eth_requestAccounts' } )
|
|
|
|
return address
|
|
|
|
}
|
|
|
|
// Address hook
|
|
export function useAddress() {
|
|
|
|
const [ address, setAddress ] = useState( undefined )
|
|
|
|
// Set initial value if known
|
|
useEffect( f => {
|
|
log( 'useAddress setting: ', window.ethereum && window.ethereum.selectedAddress, ` based on `, window.ethereum )
|
|
if( window.ethereum && window.ethereum.selectedAddress ) setAddress( window.ethereum.selectedAddress )
|
|
}, [] )
|
|
|
|
// Create listener to accounts change
|
|
useEffect( f => setListenerAndReturnUnlistener( window.ethereum, 'accountsChanged', addresses => {
|
|
log( 'Addresses changed to ', addresses )
|
|
setAddress( addresses[0] )
|
|
} ), [ ] )
|
|
|
|
|
|
return address
|
|
|
|
}
|
|
|
|
export function useTotalSupply() {
|
|
|
|
const [ supply, setSupply ] = useState( 'loading' )
|
|
const contract = useContract( )
|
|
|
|
// Create listener to minting
|
|
useEffect( f => {
|
|
|
|
// Do nothing if there is not contract object
|
|
if( !contract ) return
|
|
|
|
// Load initial supply value
|
|
( async ( ) => {
|
|
|
|
try {
|
|
|
|
const supply = await contract.totalSupply()
|
|
log( 'Initial supply detected: ', supply )
|
|
setSupply( supply.toString() )
|
|
|
|
} catch( e ) {
|
|
|
|
log( 'Error getting initial supply: ', e )
|
|
|
|
}
|
|
|
|
} )( )
|
|
|
|
// Listen to token transfers andor mints
|
|
return setListenerAndReturnUnlistener( contract, 'Transfer', async ( from, to, amount, event ) => {
|
|
|
|
try {
|
|
|
|
log( `Transfer ${ from } sent to ${ to } `, amount, event )
|
|
const supply = await contract.totalSupply()
|
|
log( 'Got supply from contract: ', supply )
|
|
setSupply( supply.toString() )
|
|
|
|
} catch( e ) {
|
|
log( 'Error getting supply from contract: ', e )
|
|
}
|
|
|
|
} )
|
|
|
|
|
|
}, [ contract ] )
|
|
|
|
return supply
|
|
|
|
}
|
|
|
|
export function useBalanceOf() {
|
|
|
|
const [ balance, setBalance ] = useState( 'loading' )
|
|
const contract = useContract( )
|
|
const address = useAddress()
|
|
|
|
// Create listener to minting
|
|
useEffect( f => {
|
|
|
|
// Do nothing if there is not contract object
|
|
if( !contract || !address ) return
|
|
|
|
// Load initial supply value
|
|
( async ( ) => {
|
|
|
|
try {
|
|
|
|
const balance = await contract.balanceOf( address )
|
|
log( 'Balance detected: ', balance, `(${ balance.toString() })` )
|
|
setBalance( balance.toString() )
|
|
|
|
} catch( e ) {
|
|
|
|
log( 'Error getting initial supply: ', e )
|
|
|
|
}
|
|
|
|
} )( )
|
|
|
|
|
|
}, [ contract, address ] )
|
|
|
|
return balance
|
|
|
|
}
|
|
|
|
// Chain ID hook
|
|
export function useChainId() {
|
|
|
|
const [ chain, setChain ] = useState( undefined )
|
|
|
|
// Create listener to chain change
|
|
useEffect( f => setListenerAndReturnUnlistener( window.ethereum, 'chainChanged', chainId => {
|
|
log( 'Chain changed to ', chainId )
|
|
setChain( chainId )
|
|
} ), [] )
|
|
|
|
// Initial chain detection
|
|
useEffect( f => {
|
|
|
|
// Check for initial chain and set to state
|
|
( async () => {
|
|
|
|
if( !window.ethereum ) return
|
|
const initialChain = await window.ethereum.request( { method: 'eth_chainId' } )
|
|
log( 'Initial chain detected as ', initialChain )
|
|
setChain( initialChain )
|
|
|
|
} )( )
|
|
|
|
}, [] )
|
|
|
|
return chain
|
|
|
|
}
|
|
|
|
// ///////////////////////////////
|
|
// Contract interactors
|
|
// ///////////////////////////////
|
|
const contractAddressByChainId = {
|
|
'0x1': '',
|
|
// '0x4': '0x2829ba9d76e675b8867E1707A9aB49B280D916c6', // Old
|
|
'0x4': '0x89D9f02D2877A35E8323DC1b578FD1f6014B04d0'
|
|
}
|
|
|
|
// Contract ABI with only totalSupply, balanceOf and Transfer
|
|
const ABI = [
|
|
{
|
|
"inputs": [],
|
|
"name": "totalSupply",
|
|
"outputs": [
|
|
{
|
|
"internalType": "uint256",
|
|
"name": "",
|
|
"type": "uint256"
|
|
}
|
|
],
|
|
"stateMutability": "view",
|
|
"type": "function",
|
|
"constant": true
|
|
},
|
|
{
|
|
"inputs": [
|
|
{
|
|
"internalType": "address",
|
|
"name": "owner",
|
|
"type": "address"
|
|
}
|
|
],
|
|
"name": "balanceOf",
|
|
"outputs": [
|
|
{
|
|
"internalType": "uint256",
|
|
"name": "",
|
|
"type": "uint256"
|
|
}
|
|
],
|
|
"stateMutability": "view",
|
|
"type": "function",
|
|
"constant": true
|
|
},
|
|
{
|
|
"anonymous": false,
|
|
"inputs": [
|
|
{
|
|
"indexed": true,
|
|
"internalType": "address",
|
|
"name": "from",
|
|
"type": "address"
|
|
},
|
|
{
|
|
"indexed": true,
|
|
"internalType": "address",
|
|
"name": "to",
|
|
"type": "address"
|
|
},
|
|
{
|
|
"indexed": true,
|
|
"internalType": "uint256",
|
|
"name": "tokenId",
|
|
"type": "uint256"
|
|
}
|
|
],
|
|
"name": "Transfer",
|
|
"type": "event"
|
|
},
|
|
{
|
|
"inputs": [
|
|
{
|
|
"internalType": "address",
|
|
"name": "_to",
|
|
"type": "address"
|
|
}
|
|
],
|
|
"name": "spawnRocketeer",
|
|
"outputs": [],
|
|
"stateMutability": "nonpayable",
|
|
"type": "function"
|
|
}
|
|
]
|
|
|
|
// Contract custom hook
|
|
export function useContract() {
|
|
|
|
const chainId = useChainId()
|
|
const [ contract, setContract ] = useState( undefined )
|
|
const address = useAddress()
|
|
|
|
useEffect( f => {
|
|
|
|
try {
|
|
|
|
// If no chain id is known, stop
|
|
if( !chainId ) return
|
|
|
|
// Generate contract interface for this chain ID
|
|
log( `Generating new contract with chain ${ chainId } and address `, contractAddressByChainId[ chainId ] )
|
|
const newContract = new Contract( contractAddressByChainId[ chainId ], ABI, signer )
|
|
|
|
// Set new contract to state
|
|
setContract( newContract )
|
|
log( 'New contract interface initialised: ', newContract )
|
|
|
|
} catch( e ) {
|
|
alert( `Blockchain error: ${ e.message || JSON.stringify( e ) }` )
|
|
log( 'Error generating contract: ', e )
|
|
setContract( undefined )
|
|
}
|
|
|
|
}, [ chainId, address ] )
|
|
|
|
return contract
|
|
|
|
}
|
|
|
|
export function rocketeerCollectionUriOnOpensea( chainId ) {
|
|
|
|
// Opensea collection link depending on network
|
|
return `${ chainId === '0x01' ? '' : 'testnets.' }opensea.io/collection/rocketeer`
|
|
|
|
}
|
|
|
|
export function rocketeerUriOnOpensea( chainId, tokenId ) {
|
|
|
|
// Opensea specific link depending on network
|
|
return `https://${ chainId === '0x01' ? '' : 'testnets.' }opensea.io/assets/${ contractAddressByChainId[ chainId ] }/${ tokenId }`
|
|
|
|
}
|
|
|