getting contracts integrated
parent
86d37ab5dc
commit
525ee783d8
@ -0,0 +1,297 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import { ethers, BigNumber } from 'ethers';
|
||||
import { useAccount, useContractReads, useContractRead, usePrepareContractWrite, useContractWrite, useWaitForTransaction, erc721ABI } from 'wagmi';
|
||||
import { NotificationContainer, NotificationManager } from 'react-notifications';
|
||||
import debounce from 'lodash';
|
||||
|
||||
import MainABI from '../abi/main.json';
|
||||
import '../styles/hero.css';
|
||||
import Unaboomer from '../img/unaboomer.png';
|
||||
import Mailbomb from '../img/mailbomb.png';
|
||||
import Explosion from '../img/explosion.png';
|
||||
import Arrow from '../img/arrow_right.png';
|
||||
|
||||
export function Hero(props) {
|
||||
const contractAddress = props.contractAddress;
|
||||
const [tokensMinted, setTokensMinted] = useState(() => {
|
||||
const saved = localStorage.getItem('tokensMinted-v1');
|
||||
return saved || JSON.stringify([])
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
localStorage.setItem('tokensMinted-v1', tokensMinted);
|
||||
}, [tokensMinted]);
|
||||
|
||||
const [options, setOptions] = useState({
|
||||
unaboomerAmount: 1,
|
||||
bombAmount: 1,
|
||||
sendBombAmount: 1,
|
||||
unaboomerPreviewAmount: 1,
|
||||
bombPreviewAmount: 1,
|
||||
sendBombPreviewAmount: 1,
|
||||
unaboomerPrice: 0,
|
||||
bombPrice: ethers.utils.parseEther('.01'),
|
||||
unaboomersMinted: 0,
|
||||
unaboomerBalance: 0,
|
||||
bombBalance: 0,
|
||||
unaboomersRadicalized: 0,
|
||||
bombsAssembled: 0,
|
||||
bombsExploded: 0,
|
||||
unaboomersKilled: 0,
|
||||
leaderboardPointer: 0,
|
||||
leaderAddress: '',
|
||||
leaderKillCount: 0,
|
||||
unaboomerMaxSupply: 0,
|
||||
unaboomerMaxSurvivorCount: 0,
|
||||
unaboomerMaxMintPerWallet: 0,
|
||||
readWTF: false,
|
||||
balancesFetched: false,
|
||||
unaboomersByAddress: []
|
||||
});
|
||||
function handleStateChange(obj) {
|
||||
setOptions(preState => ({...preState , ...obj}));
|
||||
}
|
||||
const { isConnected, address } = useAccount();
|
||||
const defOpt = {
|
||||
address: contractAddress,
|
||||
abi: MainABI,
|
||||
enabled: isConnected
|
||||
}
|
||||
// Fetch this stuff and cache aggressively since it doesn't change
|
||||
useContractReads({
|
||||
contracts: [
|
||||
{...defOpt, functionName: 'unaboomerPrice'},
|
||||
{...defOpt, functionName: 'bombPrice'},
|
||||
{...defOpt, functionName: 'unaboomerMaxSupply'},
|
||||
{...defOpt, functionName: 'unaboomerMaxSurvivorCount'},
|
||||
{...defOpt, functionName: 'unaboomerMaxMintPerWallet'}
|
||||
],
|
||||
watch: true,
|
||||
cacheTime: 30_000,
|
||||
onSuccess(data) {
|
||||
handleStateChange({
|
||||
unaboomerPrice: data[0].toString(),
|
||||
bombPrice: data[1].toString(),
|
||||
unaboomerMaxSupply: Number(data[2]),
|
||||
unaboomerMaxSurvivorCount: Number(data[3]),
|
||||
unaboomerMaxMintPerWallet: Number(data[4])
|
||||
});
|
||||
}
|
||||
});
|
||||
// Fetch this stuff more frequently as it updates constantly
|
||||
useContractReads({
|
||||
contracts: [
|
||||
{...defOpt, functionName: 'unaboomersMinted', args: [address]},
|
||||
{...defOpt, functionName: 'bombBalance', args: [address]},
|
||||
{...defOpt, functionName: 'unaboomersRadicalized'},
|
||||
{...defOpt, functionName: 'bombsAssembled'},
|
||||
{...defOpt, functionName: 'bombsExploded'},
|
||||
{...defOpt, functionName: 'unaboomersKilled'},
|
||||
{...defOpt, functionName: 'leaderboardPointer'},
|
||||
{...defOpt, functionName: 'unaboomerBalance', args: [address]}
|
||||
],
|
||||
watch: true,
|
||||
cacheTime: 6_000,
|
||||
onSuccess(data) {
|
||||
handleStateChange({
|
||||
unaboomersMinted: Number(data[0]),
|
||||
bombBalance: Number(data[1]),
|
||||
unaboomersRadicalized: Number(data[2]),
|
||||
bombsAssembled: Number(data[3]),
|
||||
bombsExploded: Number(data[4]),
|
||||
unaboomersKilled: Number(data[5]),
|
||||
leaderboardPointer: Number(data[6]),
|
||||
balancesFetched: true,
|
||||
unaboomerBalance: Number(data[7])
|
||||
});
|
||||
}
|
||||
});
|
||||
useContractRead({
|
||||
address: contractAddress,
|
||||
abi: MainABI,
|
||||
enabled: options.leaderboardPointer > 0,
|
||||
functionName: 'leaderboard',
|
||||
args: [options.leaderboardPointer],
|
||||
watch: true,
|
||||
cacheTime: 8_000,
|
||||
onSuccess: async (data) => {
|
||||
handleStateChange({
|
||||
leaderAddress: data,
|
||||
});
|
||||
}
|
||||
});
|
||||
useContractRead({
|
||||
address: contractAddress,
|
||||
abi: MainABI,
|
||||
enabled: options.leaderAddress.length > 0,
|
||||
functionName: 'killCount',
|
||||
args: [options.leaderAddress],
|
||||
watch: true,
|
||||
cacheTime: 8_000,
|
||||
onSuccess(data) {
|
||||
handleStateChange({
|
||||
leaderKillCount: Number(data),
|
||||
});
|
||||
}
|
||||
});
|
||||
const radicalizeBoomersPrepare = usePrepareContractWrite({
|
||||
address: contractAddress,
|
||||
abi: MainABI,
|
||||
enabled: isConnected && options.unaboomersMinted < options.unaboomerMaxMintPerWallet && options.unaboomerAmount > 0 && options.balancesFetched,
|
||||
functionName: 'radicalizeBoomers',
|
||||
args: [options.unaboomerAmount],
|
||||
overrides: {
|
||||
from: address,
|
||||
value: BigNumber.from((options.unaboomerPrice * options.unaboomerAmount).toString())
|
||||
}
|
||||
});
|
||||
const radicalizeBoomersWrite = useContractWrite({
|
||||
...radicalizeBoomersPrepare.config,
|
||||
onError(data) {
|
||||
if (data.message.startsWith('user rejected transaction')) NotificationManager.info(`tx cancelled`, 'ok', 4000);
|
||||
}
|
||||
});
|
||||
const assembleBombsPrepare = usePrepareContractWrite({
|
||||
address: contractAddress,
|
||||
abi: MainABI,
|
||||
enabled: isConnected && options.bombAmount > 0,
|
||||
functionName: 'assembleBombs',
|
||||
args: [options.bombAmount],
|
||||
overrides: {
|
||||
from: address,
|
||||
value: BigNumber.from((options.bombPrice * options.bombAmount).toString())
|
||||
}
|
||||
});
|
||||
const assembleBombsWrite = useContractWrite({
|
||||
...assembleBombsPrepare.config,
|
||||
onError(data) {
|
||||
if (data.message.startsWith('user rejected transaction')) NotificationManager.info(`tx cancelled`, 'ok', 4000);
|
||||
}
|
||||
});
|
||||
const sendBombsPrepare = usePrepareContractWrite({
|
||||
address: contractAddress,
|
||||
abi: MainABI,
|
||||
enabled: isConnected && options.bombBalance > 0,
|
||||
functionName: 'sendBombs',
|
||||
cacheTime: 0,
|
||||
staleTime: 400,
|
||||
args: [options.sendBombAmount]
|
||||
});
|
||||
const sendBombsWrite = useContractWrite({
|
||||
...sendBombsPrepare.config,
|
||||
onError(data) {
|
||||
if (data.message.startsWith('user rejected transaction')) NotificationManager.info(`tx cancelled`, 'ok', 4000);
|
||||
}
|
||||
});
|
||||
useWaitForTransaction({
|
||||
hash: radicalizeBoomersWrite.data?.hash,
|
||||
enabled: radicalizeBoomersWrite.status === 'success',
|
||||
onSuccess(data) {
|
||||
let tm = JSON.parse(tokensMinted);
|
||||
const iface = new ethers.utils.Interface(erc721ABI);
|
||||
data.logs.filter(log =>
|
||||
log.topics[0] === '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'
|
||||
).map((log) => {
|
||||
const res = iface.decodeEventLog("Transfer", log.data, log.topics);
|
||||
NotificationManager.success(`You radicalized Unaboomer #${res.tokenId.toString()}`, '', 4000);
|
||||
tm.push(Number(res.tokenId));
|
||||
});
|
||||
setTokensMinted(JSON.stringify(tm));
|
||||
console.log(tm);
|
||||
}
|
||||
})
|
||||
useWaitForTransaction({
|
||||
hash: sendBombsWrite.data?.hash,
|
||||
enabled: sendBombsWrite.status === 'success',
|
||||
onSuccess(data) {
|
||||
const iface = new ethers.utils.Interface(MainABI);
|
||||
data.logs.filter(log =>
|
||||
log.topics[0] === '0x38c7e2e8001cefb27535bd6bcc6363c6d6a6a83dbb77f092b78956334596f9ed'
|
||||
).map((log) => {
|
||||
const res = iface.decodeEventLog("SentBomb", log.data, log.topics);
|
||||
if (res.hit) {
|
||||
if (res.owned) {
|
||||
NotificationManager.error(`Your bomb exploded during assembly and killed your Unaboomer ${res.tokenId.toString()}`, '', 8000);
|
||||
} else {
|
||||
NotificationManager.success(`Your bomb killed Unaboomer ${res.tokenId.toString()}`, '', 8000);
|
||||
}
|
||||
} else {
|
||||
NotificationManager.warning(`Your bomb for Unaboomer ${res.tokenId.toString()} was a dud`, '', 8000);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<div id='hero'>
|
||||
<h1>the web3 revolution & its consequences have been a disaster for the human race.</h1>
|
||||
<p>
|
||||
Technology is advancing at an exponential rate and boomers are being left behind. A.I., Bitcoin,
|
||||
and expensive JPEGs have made them angry. <br /><br />
|
||||
They've begun to radicalize. {options.unaboomerMaxSupply > 0 ? '35,000': options.unaboomerMaxSupply} Boomers have joined forces
|
||||
to lash out at the system.<br /><br />
|
||||
</p>
|
||||
<div id='heroFlex'>
|
||||
<div className='heroFlexItem'>
|
||||
<img src={Unaboomer} width='280px' alt='Pixelated Unaboomer profile picture - a hooded man with dark sunglasses.' />
|
||||
|
||||
{options.unaboomersMinted > 0 && (
|
||||
<p>
|
||||
You have minted {options.unaboomersMinted} Unaboomers.
|
||||
{options.unaboomersKilled > 0 && <>{options.unaboomersKilled} are dead.</>}
|
||||
</p>
|
||||
)}
|
||||
<br />
|
||||
{isConnected
|
||||
&& options.unaboomersMinted < options.unaboomerMaxMintPerWallet
|
||||
&& options.unaboomersKilled + options.unaboomersRadicalized < options.unaboomerMaxSupply
|
||||
&& (
|
||||
<>
|
||||
<input type='number' step='1' name='bombAmountPreview' defaultValue={1} min={1} max={options.unaboomerMaxMintPerWallet - options.unaboomersMinted} onChange={(v) => {
|
||||
handleStateChange({unaboomerAmount: v.target.value});
|
||||
radicalizeBoomersWrite.reset()
|
||||
}}></input>
|
||||
<button className='doThing' disabled={radicalizeBoomersPrepare.status == 'error'} onClick={() => radicalizeBoomersWrite.write?.()}>
|
||||
{radicalizeBoomersWrite.isLoading && <>minting {options.unaboomerAmount}</>}
|
||||
{radicalizeBoomersWrite.isIdle && <>Radicalize {options.unaboomerAmount == 1 ? 'a Unaboomer': <>{options.unaboomerAmount} Unaboomers</>}</>}
|
||||
{radicalizeBoomersWrite.isSuccess && <>sent</>}
|
||||
{radicalizeBoomersWrite.isError && <>error</>}
|
||||
</button>
|
||||
<p>({ethers.utils.formatEther((options.unaboomerPrice * options.unaboomerAmount).toString())} ETH)</p>
|
||||
</>
|
||||
) || options.unaboomersMinted == options.unaboomerMaxMintPerWallet && options.unaboomersKilled + options.unaboomersRadicalized < options.unaboomerMaxSupply && (
|
||||
<h2>max per wallet reached</h2>
|
||||
) || options.unaboomersRadicalized == options.unaboomerMaxSupply && options.unaboomerMaxSupply > 0 && (
|
||||
<h2>max supply reached</h2>
|
||||
)}
|
||||
</div>
|
||||
<div className='heroFlexArrow'>
|
||||
<img src={Arrow} width='100px' alt='Arrow pointing to the next step.' />
|
||||
</div>
|
||||
<div className='heroFlexItem'>
|
||||
<img src={Mailbomb} width='280px' alt='Pixelated Mailbomb image - handle with caution.' />
|
||||
<p>
|
||||
Don't let the Boomers win, fight back! Assemble a mailbomb and blow 'em to smithereens. <br /><br />
|
||||
(Warning: Some bombs are duds!)
|
||||
</p>
|
||||
<button className='doThing buttom'>assemble mailbomb</button>
|
||||
<p>(.01 ETH)</p>
|
||||
</div>
|
||||
<div className='heroFlexArrow'>
|
||||
<img src={Arrow} width='100px' alt='Arrow pointing to the next step.' />
|
||||
</div>
|
||||
<div className='heroFlexItem'>
|
||||
<img src={Explosion} width='280px' alt='Pixelated explosion image.' />
|
||||
<p>
|
||||
Ready for mayhem? Burn your mailrooms to blow up a random boomer. <br /><br />
|
||||
If your bomb is live it will destroy a Boomer PFP forever. <br /><br />
|
||||
(Warning: Your Boomer might explode!)
|
||||
</p>
|
||||
<button className='doThing buttom'>mail a bomb</button>
|
||||
<p>(0 ETH)</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import '../styles/hero.css';
|
||||
import Unaboomer from '../img/unaboomer.png';
|
||||
import Mailbomb from '../img/mailbomb.png';
|
||||
import Explosion from '../img/explosion.png';
|
||||
import Arrow from '../img/arrow_right.png';
|
||||
|
||||
export class Hero extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div id='hero'>
|
||||
<h1>the web3 revolution & its consequences have been a disaster for the human race.</h1>
|
||||
<div id='heroFlex'>
|
||||
<div className='heroFlexItem'>
|
||||
<img src={Unaboomer} width='280px' alt='Pixelated Unaboomer profile picture - a hooded man with dark sunglasses.' />
|
||||
<p>
|
||||
Technology is advancing at an exponential rate and boomers are being left behind. A.I., Bitcoin,
|
||||
and expensive JPEGs have made them angry. <br /><br />
|
||||
They've begun to radicalize. 35,000 Boomers have joined forces
|
||||
to lash out at the system.
|
||||
</p>
|
||||
<button className='doThing buttom'>Radicalize boomer</button>
|
||||
<p>(0 ETH)</p>
|
||||
</div>
|
||||
<div className='heroFlexArrow'>
|
||||
<img src={Arrow} width='100px' alt='Arrow pointing to the next step.' />
|
||||
</div>
|
||||
<div className='heroFlexItem'>
|
||||
<img src={Mailbomb} width='280px' alt='Pixelated Mailbomb image - handle with caution.' />
|
||||
<p>
|
||||
Don't let the Boomers win, fight back! Assemble a mailbomb and blow 'em to smithereens. <br /><br />
|
||||
(Warning: Some bombs are duds!)
|
||||
</p>
|
||||
<button className='doThing buttom'>assemble mailbomb</button>
|
||||
<p>(.01 ETH)</p>
|
||||
</div>
|
||||
<div className='heroFlexArrow'>
|
||||
<img src={Arrow} width='100px' alt='Arrow pointing to the next step.' />
|
||||
</div>
|
||||
<div className='heroFlexItem'>
|
||||
<img src={Explosion} width='280px' alt='Pixelated explosion image.' />
|
||||
<p>
|
||||
Ready for mayhem? Burn your mailrooms to blow up a random boomer. <br /><br />
|
||||
If your bomb is live it will destroy a Boomer PFP forever. <br /><br />
|
||||
(Warning: Your Boomer might explode!)
|
||||
</p>
|
||||
<button className='doThing buttom'>mail a bomb</button>
|
||||
<p>(0 ETH)</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue