Compare commits
2 Commits
4bcf23a9ac
...
5b0d24ccba
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5b0d24ccba | ||
|
|
9873dfc76b |
17
README.md
17
README.md
@ -4,7 +4,10 @@ Idle game & shitcoin advanture dedicated to cohort VII of Raid Guild.
|
|||||||
|
|
||||||
## Set up for local DEV
|
## Set up for local DEV
|
||||||
|
|
||||||
### 1. Run `anvil` to setup local RPC
|
### 1. Run `anvil` to setup local RPC as a fork of base mainnet
|
||||||
|
`anvil --rpc-url <you'r base mainnet rpc url>`
|
||||||
|
|
||||||
|
you can get a free rpc url by registering with https://alchemy.com and creating and app
|
||||||
|
|
||||||
### 2. Deploy contract
|
### 2. Deploy contract
|
||||||
|
|
||||||
@ -14,14 +17,14 @@ Either use `./deploy_contract.sh` script (!! change contract values and set priv
|
|||||||
|
|
||||||
Move to `app` dir, install deps via `npm install` and run `npm run dev` to start the dev server.
|
Move to `app` dir, install deps via `npm install` and run `npm run dev` to start the dev server.
|
||||||
|
|
||||||
#### 3. 1. Run `cast rpc anvil_mine`
|
#### 3. 1. Point Metamask to Anvil network for local dev
|
||||||
|
|
||||||
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. Change `app/contract_address.ts` to match your program address if needed
|
|
||||||
|
|
||||||
### 4. Local development requires mining blocks by hand
|
### 4. Local development requires mining blocks by hand
|
||||||
|
|
||||||
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
|
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
|
||||||
|
|
||||||
|
|
||||||
|
### 5. Fork tests
|
||||||
|
forge test --rpc-url <you'r base mainnet rpc url>
|
||||||
|
|||||||
@ -4,14 +4,16 @@ pragma solidity ^0.8.13;
|
|||||||
import {Script, console} from "forge-std/Script.sol";
|
import {Script, console} from "forge-std/Script.sol";
|
||||||
import {RaidGeld} from "../src/RaidGeld.sol";
|
import {RaidGeld} from "../src/RaidGeld.sol";
|
||||||
|
|
||||||
contract RaidGeldScript is Script {
|
import {Constants} from "../src/Constants.sol";
|
||||||
|
|
||||||
|
contract RaidGeldScript is Script, Constants {
|
||||||
RaidGeld public raidgeld;
|
RaidGeld public raidgeld;
|
||||||
|
|
||||||
function setUp() public {}
|
function setUp() public {}
|
||||||
|
|
||||||
function run() public {
|
function run() public {
|
||||||
vm.startBroadcast();
|
vm.startBroadcast();
|
||||||
raidgeld = new RaidGeld();
|
raidgeld = new RaidGeld(DAO_TOKEN, POOL);
|
||||||
vm.stopBroadcast();
|
vm.stopBroadcast();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
8
src/Constants.sol
Normal file
8
src/Constants.sol
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity ^0.8.13;
|
||||||
|
|
||||||
|
contract Constants {
|
||||||
|
//base addresses
|
||||||
|
address public constant DAO_TOKEN = 0x11dC980faf34A1D082Ae8A6a883db3A950a3c6E8;
|
||||||
|
address public constant POOL = 0x27004f6d0c1bB7979367D32Ba9d6DF6d61A18926;
|
||||||
|
}
|
||||||
@ -6,28 +6,44 @@ import "@openzeppelin/contracts/access/Ownable.sol";
|
|||||||
import {RaidGeldUtils} from "../src/RaidGeldUtils.sol";
|
import {RaidGeldUtils} from "../src/RaidGeldUtils.sol";
|
||||||
import {Army, Player, Raider} from "../src/RaidGeldStructs.sol";
|
import {Army, Player, Raider} from "../src/RaidGeldStructs.sol";
|
||||||
|
|
||||||
|
|
||||||
contract RaidGeld is ERC20, Ownable {
|
contract RaidGeld is ERC20, Ownable {
|
||||||
uint256 public constant MANTISSA = 1e4;
|
uint256 public constant MANTISSA = 1e4;
|
||||||
|
|
||||||
uint256 public constant BUY_IN_AMOUNT = 0.00005 ether;
|
uint256 public constant BUY_IN_AMOUNT = 0.00005 ether;
|
||||||
|
uint256 public immutable BUY_IN_DAO_TOKEN_AMOUNT;
|
||||||
|
|
||||||
uint256 public constant INITIAL_GELD = 50 * MANTISSA;
|
uint256 public constant INITIAL_GELD = 50 * MANTISSA;
|
||||||
uint256 public constant RAID_WAIT = 15 seconds;
|
uint256 public constant RAID_WAIT = 15 seconds;
|
||||||
|
|
||||||
mapping(address => Player) private players;
|
mapping(address => Player) private players;
|
||||||
mapping(address => Army) private armies;
|
mapping(address => Army) private armies;
|
||||||
|
|
||||||
|
ERC20 public daoToken;
|
||||||
|
address public pool;
|
||||||
|
|
||||||
// Modifier for functions that should only be available to registered players
|
// Modifier for functions that should only be available to registered players
|
||||||
modifier onlyPlayer() {
|
modifier onlyPlayer() {
|
||||||
require(players[msg.sender].created_at != 0, "Not an initiated player");
|
require(players[msg.sender].created_at != 0, "Not an initiated player");
|
||||||
_;
|
_;
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
// This effectively registers the user
|
||||||
function register() external payable {
|
function register() external payable {
|
||||||
require(players[msg.sender].created_at == 0, "Whoops, player already exists :)");
|
require(players[msg.sender].created_at == 0, "Whoops, player already exists :)");
|
||||||
require(msg.value == BUY_IN_AMOUNT, "Incorrect buy in amount");
|
if (msg.value != 0) {
|
||||||
|
require(msg.value == BUY_IN_AMOUNT, "Incorrect buy in amount");
|
||||||
|
} else {
|
||||||
|
//@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");
|
||||||
|
}
|
||||||
|
|
||||||
// Mint some starting tokens to the player
|
// Mint some starting tokens to the player
|
||||||
_mint(msg.sender, INITIAL_GELD);
|
_mint(msg.sender, INITIAL_GELD);
|
||||||
|
|||||||
@ -2,10 +2,16 @@
|
|||||||
pragma solidity ^0.8.13;
|
pragma solidity ^0.8.13;
|
||||||
|
|
||||||
import {Test, console} from "forge-std/Test.sol";
|
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 {RaidGeld, Army, Player} from "../src/RaidGeld.sol";
|
||||||
import "../src/RaidGeldUtils.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;
|
RaidGeld public raid_geld;
|
||||||
address public player1;
|
address public player1;
|
||||||
address public player2;
|
address public player2;
|
||||||
@ -15,14 +21,28 @@ contract raid_geldTest is Test {
|
|||||||
owner = address(0x126);
|
owner = address(0x126);
|
||||||
player1 = address(0x123);
|
player1 = address(0x123);
|
||||||
vm.deal(owner, 10 ether);
|
vm.deal(owner, 10 ether);
|
||||||
vm.deal(player1, 10 ether);
|
fundAccount(player1);
|
||||||
vm.prank(owner);
|
vm.prank(owner);
|
||||||
raid_geld = new RaidGeld();
|
raid_geld = new RaidGeld(DAO_TOKEN, POOL);
|
||||||
|
}
|
||||||
|
function fundAccount(address _acc) private {
|
||||||
|
vm.deal(_acc, 10 ether);
|
||||||
|
stdstore
|
||||||
|
.target(DAO_TOKEN)
|
||||||
|
.sig("balanceOf(address)")
|
||||||
|
.with_key(_acc)
|
||||||
|
.checked_write(100 ether);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function registerPlayer() private {
|
function registerPlayer() private {
|
||||||
raid_geld.register{value: raid_geld.BUY_IN_AMOUNT()}();
|
raid_geld.register{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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function test_00_no_fallback() public {
|
function test_00_no_fallback() public {
|
||||||
vm.expectRevert();
|
vm.expectRevert();
|
||||||
@ -36,7 +56,7 @@ contract raid_geldTest is Test {
|
|||||||
payable(address(raid_geld)).transfer(0.1 ether);
|
payable(address(raid_geld)).transfer(0.1 ether);
|
||||||
}
|
}
|
||||||
|
|
||||||
function test_02_registration() public {
|
function test_02_1_registrationWithEth() public {
|
||||||
vm.startPrank(player1);
|
vm.startPrank(player1);
|
||||||
|
|
||||||
uint256 initialBalance = address(raid_geld).balance;
|
uint256 initialBalance = address(raid_geld).balance;
|
||||||
@ -64,6 +84,35 @@ contract raid_geldTest is Test {
|
|||||||
assertEq(army.champion.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));
|
||||||
|
|
||||||
|
// Send registration fee ETH to the contract
|
||||||
|
registerPlayerWithDaoToken();
|
||||||
|
|
||||||
|
// Check that initialraid_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());
|
||||||
|
|
||||||
|
// 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_03_funds_can_be_withdrawn() public {
|
function test_03_funds_can_be_withdrawn() public {
|
||||||
uint256 initialBalance = owner.balance;
|
uint256 initialBalance = owner.balance;
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
pragma solidity ^0.8.13;
|
pragma solidity ^0.8.13;
|
||||||
|
|
||||||
import {Test, console} from "forge-std/Test.sol";
|
import {Test, console} from "forge-std/Test.sol";
|
||||||
import {Army, Raider} from "../src/RaidGeld.sol";
|
import {Army, Raider} from "../src/RaidGeldStructs.sol";
|
||||||
import "../src/RaidGeldUtils.sol";
|
import "../src/RaidGeldUtils.sol";
|
||||||
|
|
||||||
contract raid_geldTest is Test {
|
contract raid_geldTest is Test {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user