Compare commits

..

No commits in common. "d976f13a04b790ca17dd013b6d67e666e62f70a7" and "504197e83cbdf5e8328cce3e4ccaf64360629b61" have entirely different histories.

24 changed files with 289 additions and 518 deletions

View File

@ -4,41 +4,24 @@ Idle game & shitcoin advanture dedicated to cohort VII of Raid Guild.
## Set up for local DEV
### 1. Run `anvil` to setup local RPC as a fork of base mainnet
`anvil --fork-url <YOUR BASE MAINNET RPC URL> --block-time 10 --chain-id 31337`
You can get a free rpc url by registering with https://alchemy.com and creating an app
Be sure to set --chain-id to 31337 if you are forking mainnet base, otherwise it will deploy with Base chain id and metamask will glitch out.
### 1. Run `anvil` to setup local RPC
### 2. Deploy contract
Use `./deploy_contract.sh` script
This will deploy the contract and give you ETH and DAO Token (RGCVII) funds.
1. Make sure to change `DEV_WALLET` var to your own.
2. Make sure you have your private key on `DEV_PRIVATE_KEY` environment variable
Alternatively, check the script and run the steps as you see fit.
Either use `./deploy_contract.sh` script (!! change contract values and set private key to $DEV_PRIVATE_KEY for it to work) or call those things by hand.
### 3. Run dev app
Move to `app` dir, install deps via `npm install` and run `npm run dev` to start the dev server.
#### 3. 1. Point Metamask to Anvil network for local dev
#### 3. 1. Run `cast rpc anvil_mine`
Add network `http://127.0.0.1:8545` with chain id `31337`
This is so time gets set on the local chain, otherwise you will start at 0 time and first mint will give you bajillion GELD.
#### 3. 2. Change `app/contract_address.ts` to match your program address if needed
#### 3. 2. Point Metamask to Anvil network for local dev
#### 3. 3. Reset metamask transaction history between anvil deployments
#### 3. 3. Change `app/contract_address.ts` to match your program address if needed
If u re-run `anvil` and redeploy the contract, do clear your history in Metamask under Advanced Settings, otherwise Metamask glitches because of its cache (?)
### 4. Local development requires mining blocks by hand
### 4. Fork tests
Run `forge test --rpc-url <your base mainnet rpc url>`
You can get a free rpc url by registering with https://alchemy.com and creating an app
Call `cast rpc anvil_mine` to mine next block, otherwise it wont ever progress and time "stands still" as far as the game is concerned

View File

@ -1,8 +1,4 @@
import { Address } from "viem"
const contractAddress = "0xbd06B0878888bf4c6895704fa603a5ADf7e65c66";
const contracts: Record<string, Address> = {
contractAddress: "0xbd06B0878888bf4c6895704fa603a5ADf7e65c66",
daoTokenAddress: "0x11dC980faf34A1D082Ae8A6a883db3A950a3c6E8"
}
export default contracts
export default contractAddress

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

View File

@ -5,12 +5,10 @@ import { usePlayer } from "../providers/PlayerProvider";
import { useAccount } from 'wagmi';
import dynamic from "next/dynamic";
import Counter, { toReadable } from "./Counter";
import { useModal } from "../providers/ModalProvider";
const Header = () => {
const { isConnected } = useAccount();
const { isRegistered, army } = usePlayer();
const { openRegistrationModal } = useModal();
const { isRegistered, register, army } = usePlayer();
const title = useMemo(() => {
return isRegistered ? `SLAY THE MOLOCH` :
@ -35,8 +33,8 @@ const Header = () => {
const onRegister = useCallback(() => {
if (isRegistered) return
openRegistrationModal()
}, [isRegistered, openRegistrationModal])
register();
}, [isRegistered, register])
return <header onClick={onRegister} className={styles.header}>
<h1 className={`${styles.title} ${isConnected && !isRegistered ? bgStyles.excited : ""}`}>{title}</h1>

View File

@ -1,26 +0,0 @@
import { useCallback } from "react";
import { usePlayer } from "../providers/PlayerProvider";
import styles from "../styles/Modal.module.css";
interface RegistrationModalProps {
isOpen: boolean;
setIsOpen: (val: boolean) => void
}
const RegistrationModal = ({ isOpen, setIsOpen }: RegistrationModalProps) => {
const { register } = usePlayer()
const onRegister = useCallback((mode: "ETH" | "RGCVII") => {
register(mode);
setIsOpen(false);
}, [register, setIsOpen])
if (!isOpen) return null;
return <div className={styles.modal}>
<h2>Insert coins to continue</h2>
<div>
<button onClick={() => onRegister("RGCVII")}>50 RGCVII</button>
<button onClick={() => onRegister("ETH")}>0.0005 ETH</button>
</div>
</div>
}
export default RegistrationModal

View File

@ -1,31 +0,0 @@
import { useEffect } from "react";
import { Hash } from "viem"
import { useWaitForTransactionReceipt } from "wagmi";
import styles from "../styles/Modal.module.css"
interface WaitingForTxModalProps {
hash: Hash,
callbackFn: () => void;
}
const WaitingForTxModal = ({
hash,
callbackFn
}: WaitingForTxModalProps) => {
const { isFetched } = useWaitForTransactionReceipt({ hash })
useEffect(() => {
if (isFetched) {
callbackFn()
}
}, [isFetched, callbackFn])
return <div className={styles.modal}>
<div className={styles.loadingImage}>
<div className={styles.loadingHamsterWheelStand} />
<div className={styles.loadingHamsterWheel} />
<div className={styles.loadingHamster} />
</div>
<p className={styles.loadingText}>Writing contract ...</p>
</div>
}
export default WaitingForTxModal

View File

@ -8,8 +8,6 @@ import { RainbowKitProvider, midnightTheme } from "@rainbow-me/rainbowkit";
import { config } from "../wagmi";
import { Press_Start_2P, Texturina } from "next/font/google";
import PlayerProvider from "../providers/PlayerProvider";
import ModalProvider from '../providers/ModalProvider';
const client = new QueryClient();
const font = Texturina({ weight: ["400"], subsets: ["latin"] });
@ -44,9 +42,7 @@ function MyApp({ Component, pageProps }: AppProps) {
}
`}</style>
<PlayerProvider>
<ModalProvider>
<Component {...pageProps} />
</ModalProvider>
</PlayerProvider>
</RainbowKitProvider>
</QueryClientProvider>

View File

@ -1,33 +0,0 @@
import React, { createContext, ReactNode, useCallback, useContext, useState } from 'react'
import RegistrationModal from '../components/RegistrationModal';
export interface PlayerContextType {
openRegistrationModal: () => void
}
const ModalContext = createContext<PlayerContextType>({
openRegistrationModal: () => { }
});
const ModalProvider = ({ children }: { children: ReactNode }) => {
const [registrationModalOpen, setIsRegistrationModalOpen] = useState(false)
const openRegistrationModal = useCallback(() => {
setIsRegistrationModalOpen(true)
}, [])
return (
<ModalContext.Provider value={{
openRegistrationModal
}}>
{children}
<RegistrationModal setIsOpen={setIsRegistrationModalOpen} isOpen={registrationModalOpen} />
</ModalContext.Provider>
);
}
export const useModal = () => {
return useContext(ModalContext);
}
export default ModalProvider

View File

@ -1,11 +1,9 @@
import React, { createContext, ReactNode, useCallback, useContext, useEffect, useState } from 'react'
import React, { createContext, ReactNode, useCallback, useContext, useEffect } 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 { parseEther } from 'viem'
import contractAddress from '../../contract_address'
const { contractAddress, daoTokenAddress } = contracts
const abi = contractAbi.abi
export type UnitType = 0 | 1 | 2 | 3
@ -28,7 +26,7 @@ export interface PlayerContextType {
player: null | Player,
army: null | Army,
balance: bigint,
register: (arg: "ETH" | "RGCVII") => void,
register: () => void,
raid: () => void,
addUnit: (unit: UnitType) => void
}
@ -46,16 +44,11 @@ const PlayerContext = createContext<PlayerContextType>({
const PlayerProvider = ({ children }: { children: ReactNode }) => {
const { address, isConnected } = useAccount();
const { writeContract, error } = useWriteContract();
const [[txHash, callbackFn], setHashAndCallback] = useState<[Hash | null, () => void]>([null, () => { }])
useEffect(() => {
console.warn(error)
}, [error])
const resetHashAndCallback = useCallback(() => {
setHashAndCallback([null, () => { }])
}, [])
const { data: isRegistered } = useReadContract({
address: contractAddress,
abi,
@ -63,7 +56,7 @@ const PlayerProvider = ({ children }: { children: ReactNode }) => {
args: [address],
query: {
enabled: isConnected,
refetchInterval: 15,
refetchInterval: 5,
}
});
@ -73,7 +66,7 @@ const PlayerProvider = ({ children }: { children: ReactNode }) => {
functionName: 'balanceOf',
args: [address],
query: {
refetchInterval: 15,
refetchInterval: 5,
enabled: isConnected
}
});
@ -102,42 +95,14 @@ const PlayerProvider = ({ children }: { children: ReactNode }) => {
console.log(balance, player, army)
const register = useCallback((arg: "RGCVII" | "ETH") => {
if (arg === 'ETH') {
const register = useCallback(() => {
writeContract({
abi,
address: contractAddress,
functionName: 'register_eth',
functionName: 'register',
value: parseEther("0.00005"),
}, {
onSuccess: (hash) => {
setHashAndCallback([hash, resetHashAndCallback])
}
})
} else if (arg === "RGCVII") {
writeContract({
abi,
address: daoTokenAddress,
functionName: 'approve',
args: [contractAddress, parseEther("50")],
}, {
onSuccess: (hash) => {
setHashAndCallback([
hash,
() => writeContract({
abi,
address: contractAddress,
functionName: 'register_dao',
}, {
onSuccess: (hash) => {
setHashAndCallback([hash, resetHashAndCallback])
}
})
])
}
});
}
}, [writeContract, resetHashAndCallback])
}, [writeContract])
const raid = useCallback(() => {
writeContract({
@ -167,7 +132,6 @@ const PlayerProvider = ({ children }: { children: ReactNode }) => {
addUnit
}}>
{children}
{txHash && <WaitingForTxModal hash={txHash} callbackFn={callbackFn} />}
</PlayerContext.Provider>
);
}

View File

@ -1,67 +0,0 @@
.modal {
position: fixed;
margin: 0 auto;
height: auto;
background: var(--bg-color);
border-width: 8px;
border-image: url("/background/frame.png") 22 fill / auto space;
padding: 44px;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
& button {
font-size: 1.4rem;
margin: 0 11px;
}
& h2 {
margin-top: 0;
}
.loadingImage {
position: relative;
width: 240px;
height: 240px;
}
.loadingHamster {
position: absolute;
background-image: url("/loader/hamster.png");
width: 240px;
height: 240px;
animation: jump 0.2s ease infinite;
}
.loadingHamsterWheel {
position: absolute;
background-image: url("/loader/hamster_wheel.png");
width: 240px;
height: 240px;
animation: spin 3.5s linear infinite;
}
.loadingHamsterWheelStand {
position: absolute;
background-image: url("/loader/hamster_stand.png");
width: 240px;
height: 240px;
}
.loadingText {
text-align: center;
font-size: 1.1rem;
margin-bottom: 0;
}
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
@keyframes jump {
0%,
100% {
transform: translate(0, 0);
}
50% {
transform: translate(0, -10px);
}
}

View File

@ -1,6 +1,5 @@
:root {
--bg-color: #1a1a1a;
--bg-color-button: #000;
--text-color: #ffffff;
--accent-color: #f00000;
--border-color: #800000;
@ -41,8 +40,8 @@ a:hover {
}
button {
background-color: var(--bg-color-button);
color: var(--text-color);
background-color: var(--accent-color);
color: var(--bg-color);
border: 2px solid var(--border-color);
padding: 10px;
cursor: pointer;
@ -50,7 +49,6 @@ button {
button:hover {
background-color: var(--hover-color);
color: var(--bg-color-button);
}
header,

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,23 +1,4 @@
#!/bin/bash
# YOUR WALLET, change to you account below:
DEV_WALLET="0x3295CCA2d922c637d35b258fc6c9C7e471803b45"
DAO_OWNER="0x4d5A5B4a679b10038e1677C84Cb675d10d29fFFD"
DAO_CONTRACT="0x11dC980faf34A1D082Ae8A6a883db3A950a3c6E8"
# Set balance for the dev wallet (1eth)
cast rpc anvil_setBalance $DEV_WALLET 0xDE0B6B3A7640000 --rpc-url http://127.0.0.1:8545
cast rpc anvil_setBalance $DAO_OWNER 0xDE0B6B3A7640000 --rpc-url http://127.0.0.1:8545
# Deploy RaidGeld
forge script script/RaidGeld.s.sol:RaidGeldScript --rpc-url http://127.0.0.1:8545 --broadcast --private-key $DEV_PRIVATE_KEY
# Impersonate the DAO owner account
cast rpc anvil_impersonateAccount $DAO_OWNER
# Send the mint transaction as the impersonated owner
cast send $DAO_CONTRACT "mint(address,uint256)" $DEV_WALLET 0x00000000000000000000000000000000000000000000003635c9adc5dea00000 --from $DAO_OWNER --rpc-url http://127.0.0.1:8545 --unlocked --gas-limit 300000
# Stop impersonating the DAO owner
cast rpc anvil_stopImpersonatingAccount $DAO_OWNER
#!/bin/sh
cast rpc anvil_setBalance 0x3295CCA2d922c637d35b258fc6c9C7e471803b45 0xDE0B6B3A7640000 --rpc-url http://127.0.0.1:8545
forge script script/RaidGeld.s.sol:RaidGeldScript --rpc-url 127.0.0.1:8545 --broadcast --private-key $DEV_PRIVATE_KEY
cast rpc anvil_mine

@ -1 +1 @@
Subproject commit 8f24d6b04c92975e0795b5868aa0d783251cdeaa
Subproject commit 1eea5bae12ae557d589f9f0f0edae2faa47cb262

View File

@ -3,16 +3,15 @@ pragma solidity ^0.8.13;
import {Script, console} from "forge-std/Script.sol";
import {RaidGeld} from "../src/RaidGeld.sol";
import {Constants} from "../src/Constants.sol";
contract RaidGeldScript is Script, Constants {
contract RaidGeldScript is Script {
RaidGeld public raidgeld;
function setUp() public {}
function run() public {
vm.startBroadcast();
raidgeld = new RaidGeld(DAO_TOKEN, POOL);
raidgeld = new RaidGeld();
vm.stopBroadcast();
}
}

View File

@ -1,10 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
contract Constants {
//base addresses
address public constant DAO_TOKEN = 0x11dC980faf34A1D082Ae8A6a883db3A950a3c6E8;
address public constant POOL = 0x27004f6d0c1bB7979367D32Ba9d6DF6d61A18926;
address public constant WETH = 0x4200000000000000000000000000000000000006;
address public constant SWAP_ROUTER = 0x2626664c2603336E57B271c5C0b26F421741e481;
}

View File

@ -3,27 +3,18 @@ pragma solidity ^0.8.13;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import {RaidGeldUtils} from "../src/RaidGeldUtils.sol";
import {Army, Player, Raider} from "../src/RaidGeldStructs.sol";
import "../src/Constants.sol";
contract RaidGeld is ERC20, Ownable, Constants {
contract RaidGeld is ERC20, Ownable {
uint256 public constant MANTISSA = 1e4;
uint256 public constant BUY_IN_AMOUNT = 0.00005 ether;
uint256 public immutable BUY_IN_DAO_TOKEN_AMOUNT;
uint256 public constant INITIAL_GELD = 500 * MANTISSA;
uint256 public constant INITIAL_GELD = 50 * MANTISSA;
mapping(address => Player) private players;
mapping(address => Army) private armies;
// WETH
IWETH public immutable weth = IWETH(WETH);
// RGCVII token
ERC20 public daoToken;
// RGCVII pool
address public pool;
// Uniswap
ISwapRouter02 private constant router = ISwapRouter02(SWAP_ROUTER);
// Events
event PlayerRegistered(address indexed player, uint256 initialGeld);
event RaidPerformed(
@ -49,20 +40,19 @@ contract RaidGeld is ERC20, Ownable, Constants {
_;
}
modifier newPlayer() {
require(players[msg.sender].created_at == 0, "Whoops, player already exists :)");
_;
}
constructor() ERC20("Raid Geld", "GELD") Ownable(msg.sender) {}
constructor(address _daoToken, address _pool) ERC20("Raid Geld", "GELD") Ownable(msg.sender) {
daoToken = ERC20(_daoToken);
pool = _pool;
BUY_IN_DAO_TOKEN_AMOUNT = 50 * 10 ** daoToken.decimals();
}
// This effectively registers the user
function register() external payable {
require(
players[msg.sender].created_at == 0,
"Whoops, player already exists :)"
);
require(msg.value == BUY_IN_AMOUNT, "Incorrect buy in amount");
function init_player(address player) private {
// Mint some starting tokens to the player
_mint(player, INITIAL_GELD);
_mint(msg.sender, INITIAL_GELD);
// Set initial states
players[msg.sender] = Player({
total_minted: INITIAL_GELD,
@ -81,44 +71,14 @@ contract RaidGeld is ERC20, Ownable, Constants {
emit PlayerRegistered(msg.sender, INITIAL_GELD);
}
// New player want to register with ETH
function register_eth() external payable newPlayer {
require(msg.value == BUY_IN_AMOUNT, "Incorrect buy in amount");
weth.deposit{value: BUY_IN_AMOUNT}();
weth.approve(address(router), BUY_IN_AMOUNT);
ISwapRouter02.ExactInputSingleParams memory params = ISwapRouter02.ExactInputSingleParams({
tokenIn: WETH,
tokenOut: DAO_TOKEN,
fee: 10000,
recipient: address(this),
amountIn: BUY_IN_AMOUNT,
amountOutMinimum: 0,
sqrtPriceLimitX96: 0
});
router.exactInputSingle(params);
init_player(msg.sender);
}
// New player wants to register with dao
function register_dao() external payable newPlayer {
//@notice this is not safe for arbitrary tokens, which may not follow the interface eg. USDT
//@notice but should be fine for the DAO token
require(
daoToken.transferFrom(msg.sender, address(this), BUY_IN_DAO_TOKEN_AMOUNT), "Failed to transfer DAO tokens"
);
// Init player
init_player(msg.sender);
}
// Override for default number of decimals
function decimals() public view virtual override returns (uint8) {
return 4;
}
// Allows the owner to withdraw DAO tokens
// Allows the owner to withdraw
function withdraw() external onlyOwner {
uint256 amount = daoToken.balanceOf(address(this));
daoToken.transfer(owner(), amount);
payable(owner()).transfer(address(this).balance);
}
// Manual minting for itchy fingers
@ -246,40 +206,3 @@ contract RaidGeld is ERC20, Ownable, Constants {
revert("No fallback calls accepted");
}
}
interface ISwapRouter02 {
struct ExactInputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 amountIn;
uint256 amountOutMinimum;
uint160 sqrtPriceLimitX96;
}
function exactInputSingle(ExactInputSingleParams calldata params)
external
payable
returns (uint256 amountOut);
struct ExactOutputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 amountOut;
uint256 amountInMaximum;
uint160 sqrtPriceLimitX96;
}
function exactOutputSingle(ExactOutputSingleParams calldata params)
external
payable
returns (uint256 amountIn);
}
interface IWETH is IERC20 {
function deposit() external payable;
function withdraw(uint256 amount) external;
}

View File

@ -2,20 +2,15 @@
pragma solidity ^0.8.13;
import {Test, console} from "forge-std/Test.sol";
import {stdStorage, StdStorage} from "forge-std/Test.sol";
import {RaidGeld, Army, Player} from "../src/RaidGeld.sol";
import "../src/RaidGeldUtils.sol";
import {Constants} from "../src/Constants.sol";
contract raid_geldTest is Test, Constants {
using stdStorage for StdStorage;
contract raid_geldTest is Test {
RaidGeld public raid_geld;
address public player1;
address public player2;
address public owner;
event Approval(address indexed owner, address indexed spender, uint256 value);
event PlayerRegistered(address indexed player, uint256 initialGeld);
event RaidPerformed(
address indexed player,
@ -38,24 +33,13 @@ contract raid_geldTest is Test, Constants {
owner = address(0x126);
player1 = address(0x123);
vm.deal(owner, 10 ether);
fundAccount(player1);
vm.deal(player1, 10 ether);
vm.prank(owner);
raid_geld = new RaidGeld(DAO_TOKEN, POOL);
raid_geld.weth().deposit{value: 5 ether}();
}
function fundAccount(address _acc) private {
vm.deal(_acc, 10 ether);
stdstore.target(DAO_TOKEN).sig("balanceOf(address)").with_key(_acc).checked_write(100 ether);
raid_geld = new RaidGeld();
}
function registerPlayer() private {
raid_geld.register_eth{value: raid_geld.BUY_IN_AMOUNT()}();
}
function registerPlayerWithDaoToken() private {
raid_geld.daoToken().approve(address(raid_geld), raid_geld.BUY_IN_DAO_TOKEN_AMOUNT());
raid_geld.register_dao();
raid_geld.register{value: raid_geld.BUY_IN_AMOUNT()}();
}
function test_00_no_fallback() public {
@ -70,58 +54,26 @@ contract raid_geldTest is Test, Constants {
payable(address(raid_geld)).transfer(0.1 ether);
}
function test_02_1_registrationWithEth() public {
function test_02_registration() public {
vm.startPrank(player1);
uint256 contractBalance = raid_geld.daoToken().balanceOf(address(raid_geld));
uint256 userBalance = address(player1).balance;
uint256 initialBalance = address(raid_geld).balance;
// Making sure event is emitted when player is registered
vm.expectEmit(address(raid_geld));
emit PlayerRegistered(player1, raid_geld.INITIAL_GELD());
// Send registration fee ETH to the contract
registerPlayer();
// Check that initialraid_geld.is received by the player
assertEq(raid_geld.balanceOf(player1), raid_geld.INITIAL_GELD());
// Verify the contract balance is updated
uint256 contractBalance2 = raid_geld.daoToken().balanceOf(address(raid_geld));
uint256 userBalance2 = address(player1).balance;
// Contract should get DAO tokens
assertLt(contractBalance, contractBalance2);
// Player should lose ETH
assertEq(userBalance2, userBalance - raid_geld.BUY_IN_AMOUNT());
// Verify player is set initially
Player memory player = raid_geld.getPlayer(player1);
assertEq(player.total_minted, raid_geld.INITIAL_GELD());
assertEq(player.created_at, block.timestamp);
assertEq(player.last_raided_at, block.timestamp);
Army memory army = raid_geld.getArmy(player1);
assertEq(army.moloch_denier.level, 0);
assertEq(army.apprentice.level, 0);
assertEq(army.anointed.level, 0);
assertEq(army.champion.level, 0);
}
function test_02_2_registrationWithDaoToken() public {
vm.startPrank(player1);
uint256 initialBalance = raid_geld.daoToken().balanceOf(address(raid_geld));
// Making sure event is emitted when player is registered
// doesnt test player emitted event because other events get emitted before it
registerPlayerWithDaoToken();
// Check that initial raid_geld is received by the player
assertEq(raid_geld.balanceOf(player1), raid_geld.INITIAL_GELD());
// Verify the contract dao token balance is updated
assertEq(
raid_geld.daoToken().balanceOf(address(raid_geld)), initialBalance + raid_geld.BUY_IN_DAO_TOKEN_AMOUNT()
address(raid_geld).balance,
initialBalance + raid_geld.BUY_IN_AMOUNT()
);
// Verify player is set initially
@ -138,30 +90,40 @@ contract raid_geldTest is Test, Constants {
assertEq(army.champion.level, 0);
}
function test_03_dao_token_can_be_withdrawn() public {
uint256 initialBalance = raid_geld.daoToken().balanceOf(address(raid_geld));
function test_03_funds_can_be_withdrawn() public {
uint256 initialBalance = owner.balance;
// Switch to Player 1 and register it
vm.startPrank(player1);
// doesnt test player emitted event because other events get emitted before it
registerPlayerWithDaoToken();
// Making sure event is emitted when player is registered
vm.expectEmit(address(raid_geld));
emit PlayerRegistered(player1, raid_geld.INITIAL_GELD());
registerPlayer();
// Switch back to owner and withdraw funds
vm.startPrank(owner);
raid_geld.withdraw();
uint256 newBalance = raid_geld.daoToken().balanceOf(address(owner));
uint256 newContractBalance = raid_geld.daoToken().balanceOf(address(raid_geld));
uint256 newBalance = owner.balance;
uint256 newContractBalance = address(raid_geld).balance;
// contract balance should be empty
assertEq(newContractBalance, 0);
// owner should have the extra funds
assertGt(newBalance, initialBalance);
assertEq(newBalance, initialBalance + raid_geld.BUY_IN_AMOUNT());
}
function test_04_only_owner_can_withdraw() public {
// Register player 1
vm.startPrank(player1);
// Making sure event is emitted when player is registered
vm.expectEmit(address(raid_geld));
emit PlayerRegistered(player1, raid_geld.INITIAL_GELD());
registerPlayer();
// attempt to withdraw with player 1, it should fail
@ -176,6 +138,7 @@ contract raid_geldTest is Test, Constants {
// Making sure event is emitted when player is registered
vm.expectEmit(address(raid_geld));
emit PlayerRegistered(player1, raid_geld.INITIAL_GELD());
registerPlayer();
@ -188,6 +151,7 @@ contract raid_geldTest is Test, Constants {
// Making sure event is emitted when player is registered
vm.expectEmit(address(raid_geld));
emit PlayerRegistered(player1, raid_geld.INITIAL_GELD());
registerPlayer();

View File

@ -2,7 +2,7 @@
pragma solidity ^0.8.13;
import {Test, console} from "forge-std/Test.sol";
import {Army, Raider} from "../src/RaidGeldStructs.sol";
import {Army, Raider} from "../src/RaidGeld.sol";
import "../src/RaidGeldUtils.sol";
contract raid_geldTest is Test {