1
0
forked from mico/idle_moloch
idle_moloch/app/src/providers/PlayerProvider.tsx

322 lines
7.6 KiB
TypeScript

import React, {
createContext,
ReactNode,
useCallback,
useContext,
useEffect,
useRef,
useState,
} from "react";
import { useAccount, useReadContract, useWriteContract } from "wagmi";
import contractAbi from "../../../out/RaidGeld.sol/RaidGeld.json";
import { Hash, parseEther } from "viem";
import contracts from "../../contract_address";
import WaitingForTxModal from "../components/WaitingForTxModal";
import BossOutcomeModal from "../components/BossOutcomeModal";
import styles from "../styles/Background.module.css";
import { coinSound } from "../utils/soundsEffect";
const { contractAddress, daoTokenAddress } = contracts;
const abi = contractAbi.abi;
export type UnitType = 0 | 1 | 2 | 3;
export type BossLevel = 0 | 1 | 2 | 3 | 4 | 5 | 6;
export interface Player {
created_at: bigint;
last_raided_at: bigint;
total_minted: bigint;
total_rewards: bigint;
n_runs: number;
prestige_level: number;
is_registered: boolean;
has_active_session: boolean;
}
export interface Army {
anointed: { level: number };
apprentice: { level: number };
champion: { level: number };
moloch_denier: { level: number };
profit_per_second: bigint;
}
export interface Boss {
level: BossLevel;
variants: [
BossLevel,
BossLevel,
BossLevel,
BossLevel,
BossLevel,
BossLevel,
BossLevel
];
}
export interface LastBossResult {
level: BossLevel;
variant: BossLevel;
battled_at: bigint;
reward: bigint;
prestigeGained: boolean;
}
export interface PlayerContextType {
isRegistered: boolean;
player: null | Player;
army: null | Army;
boss: null | Boss;
lastBossResult: null | LastBossResult;
balance: bigint;
register: (arg: "ETH" | "RGCVII") => void;
raid: () => void;
battleWithBoss: () => void;
addUnit: (unit: UnitType, amount?: number) => void;
}
const PlayerContext = createContext<PlayerContextType>({
isRegistered: false,
player: null,
army: null,
boss: null,
lastBossResult: null,
balance: BigInt(0),
register: () => {},
raid: () => {},
battleWithBoss: () => {},
addUnit: () => {},
});
const PlayerProvider = ({ children }: { children: ReactNode }) => {
const { address, isConnected } = useAccount();
const { writeContract, error } = useWriteContract();
const [[txHash, callbackFn], setHashAndCallback] = useState<
[Hash | null, () => void]
>([null, () => {}]);
const [bossBattledModalOpen, setBossBattlesModalOpen] = useState(false);
const hasFetchedLastBossFirstTime = useRef(false);
useEffect(() => {
console.warn(error);
}, [error]);
const resetHashAndCallback = useCallback(() => {
setHashAndCallback([null, () => {}]);
}, []);
const { data: isRegistered } = useReadContract({
address: contractAddress,
abi,
functionName: "isRegistered",
args: [address],
query: {
enabled: isConnected,
refetchInterval: 10000,
},
});
const { data: balance } = useReadContract({
address: contractAddress,
abi,
functionName: "balanceOf",
args: [address],
query: {
refetchInterval: 10000,
enabled: isConnected,
},
});
const { data: player } = useReadContract({
address: contractAddress,
abi,
functionName: "getPlayer",
args: [address],
query: {
enabled: isConnected,
refetchInterval: 10000,
},
});
const { data: army } = useReadContract({
address: contractAddress,
abi,
functionName: "getArmy",
args: [address],
query: {
enabled: isConnected,
refetchInterval: 10000,
},
});
const { data: boss } = useReadContract({
address: contractAddress,
abi,
functionName: "getBoss",
args: [address],
query: {
enabled: isConnected,
refetchInterval: 10000,
},
});
const { data: lastBossResult } = useReadContract({
address: contractAddress,
abi,
functionName: "getLastBossResult",
args: [address],
query: {
enabled: isConnected,
refetchInterval: 10000,
},
});
const register = useCallback(
(arg: "RGCVII" | "ETH") => {
if (arg === "ETH") {
writeContract(
{
abi,
address: contractAddress,
functionName: "register_eth",
value: parseEther("0.00045"),
},
{
onSuccess: (hash) => {
setHashAndCallback([hash, resetHashAndCallback]);
},
onError: () => resetHashAndCallback(),
}
);
} else if (arg === "RGCVII") {
writeContract(
{
abi,
address: daoTokenAddress,
functionName: "approve",
args: [contractAddress, parseEther("400")],
},
{
onSuccess: (hash) => {
setHashAndCallback([
hash,
() =>
writeContract(
{
abi,
address: contractAddress,
functionName: "register_dao",
},
{
onSuccess: (hash) => {
setHashAndCallback([hash, resetHashAndCallback]);
},
onError: () => resetHashAndCallback(),
}
),
]);
},
onError: () => resetHashAndCallback(),
}
);
}
},
[writeContract, resetHashAndCallback]
);
const raid = useCallback(() => {
writeContract(
{
abi,
address: contractAddress,
functionName: "raid",
},
{
onSuccess: (hash) => {
setHashAndCallback([hash, resetHashAndCallback]);
},
onError: () => resetHashAndCallback(),
}
);
}, [writeContract, resetHashAndCallback]);
const addUnit = useCallback(
(unit: UnitType) => {
writeContract(
{
abi,
address: contractAddress,
functionName: "addUnit",
args: [unit, 1],
},
{
onSuccess: () => {
coinSound();
},
onError: () => resetHashAndCallback(),
}
);
},
[writeContract, resetHashAndCallback]
);
const battleWithBoss = useCallback(() => {
writeContract(
{
abi,
address: contractAddress,
functionName: "battle_with_boss",
},
{
onSuccess: (hash) => {
setHashAndCallback([hash, () => resetHashAndCallback()]);
},
onError: () => resetHashAndCallback(),
}
);
}, [writeContract, resetHashAndCallback]);
useEffect(() => {
if (lastBossResult != null) {
if (hasFetchedLastBossFirstTime.current) {
setBossBattlesModalOpen(true);
} else {
hasFetchedLastBossFirstTime.current = true;
}
}
}, [lastBossResult]);
return (
<PlayerContext.Provider
value={{
isRegistered: isRegistered as boolean,
player: player as Player,
army: army as Army,
boss: boss as Boss,
balance: balance as bigint,
lastBossResult: lastBossResult as LastBossResult,
register,
raid,
addUnit,
battleWithBoss,
}}
>
{children}
<div
className={`${
txHash || bossBattledModalOpen ? styles.leaderboardOverlay : ""
}`}
>
{txHash && <WaitingForTxModal hash={txHash} callbackFn={callbackFn} />}
{bossBattledModalOpen && (
<BossOutcomeModal setIsOpen={setBossBattlesModalOpen} />
)}
</div>
</PlayerContext.Provider>
);
};
export const usePlayer = () => {
return useContext(PlayerContext);
};
export default PlayerProvider;