Compare commits

...

12 Commits

Author SHA1 Message Date
7a32129f7e
Ran forge fmt + solved client bug with amounts being much too high due to change in contract calculations
Some checks failed
CI / Foundry project (push) Has been cancelled
CI / Foundry project (pull_request) Has been cancelled
2024-10-25 11:12:51 +02:00
a5f1bc7a57
Merged latest main 2024-10-25 10:57:00 +02:00
ab43dc31a4
App now credits the team in this cohort not mico
Some checks are pending
CI / Foundry project (push) Waiting to run
2024-10-24 18:22:51 +02:00
3fdfb2d822
Added a line about changing contract_address.ts if needed 2024-10-24 15:15:15 +02:00
886d86ad07
gitignore fuckery
Some checks failed
CI / Foundry project (push) Has been cancelled
2024-10-24 14:58:10 +02:00
52cf3b40e3
put address into gitignore
Some checks are pending
CI / Foundry project (push) Waiting to run
2024-10-24 14:51:12 +02:00
118b05b41a
put address into gitignore
Some checks are pending
CI / Foundry project (push) Waiting to run
2024-10-24 14:50:49 +02:00
19932be0a9
put address into gitignore
Some checks are pending
CI / Foundry project (push) Waiting to run
2024-10-24 14:48:17 +02:00
8a251a6dd2
put address into gitignore 2024-10-24 14:42:36 +02:00
cefb360792
Deployed new version + configurability for address 2024-10-24 14:40:46 +02:00
cb12c772ae
Made tests pure where applicable
Some checks are pending
CI / Foundry project (push) Waiting to run
2024-10-24 14:35:55 +02:00
a8cd6a1b5c
Removed console logs
Some checks are pending
CI / Foundry project (push) Waiting to run
2024-10-24 14:32:16 +02:00
16 changed files with 139 additions and 81 deletions

3
.gitignore vendored
View File

@ -1,3 +1,6 @@
# Address
/app/contract_address.ts
# Compiler files # Compiler files
cache/ cache/
out/ out/

View File

@ -20,6 +20,8 @@ This is so time gets set on the local chain, otherwise you will start at 0 time
#### 3. 2. Point Metamask to Anvil network for local dev #### 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
app/.gitignore vendored
View File

@ -1,4 +1,7 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. # See https://help.github.com/articles/ignoring-files/ for more about ignoring files
# address
contract_address.ts
# dependencies # dependencies
/node_modules /node_modules

4
app/contract_address.ts Normal file
View File

@ -0,0 +1,4 @@
const contractAddress = "0xbd06B0878888bf4c6895704fa603a5ADf7e65c66";
export default contractAddress

View File

@ -8,14 +8,12 @@ const calculateBalance = (balance: bigint, perSecond: bigint, lastRaidedAt: bigi
(new Date()).getTime() - parseInt(lastRaidedAt.toString()) * 1000; (new Date()).getTime() - parseInt(lastRaidedAt.toString()) * 1000;
return ( return (
balance + balance +
(BigInt(millisecondsSinceLastRaid) * (perSecond * BigInt(10000) /* decimals */) (BigInt(millisecondsSinceLastRaid) * perSecond
/ BigInt(1000) /* deduct milliseconds*/)) / BigInt(1000) /* deduct milliseconds*/))
} }
export const toReadable = (value: bigint, applyTokenDivision?: boolean) => { export const toReadable = (value: bigint) => {
if (applyTokenDivision) { value = value / BigInt(10000);
value = value / BigInt(10000);
}
const suffixes = [ const suffixes = [
{ value: BigInt('1000'), suffix: 'thousand' }, { value: BigInt('1000'), suffix: 'thousand' },
{ value: BigInt('1000000'), suffix: 'million' }, { value: BigInt('1000000'), suffix: 'million' },
@ -37,8 +35,6 @@ export const toReadable = (value: bigint, applyTokenDivision?: boolean) => {
{ value: BigInt('1000000000000000000000000000000000000000000000000000000'), suffix: 'septendecillion' }, { value: BigInt('1000000000000000000000000000000000000000000000000000000'), suffix: 'septendecillion' },
]; ];
console.log(value)
for (let i = 0; i < suffixes.length; i++) { for (let i = 0; i < suffixes.length; i++) {
if (value < suffixes[i].value) { if (value < suffixes[i].value) {
if (i == 0) { if (i == 0) {
@ -66,8 +62,8 @@ const Counter = () => {
balance, balance,
army?.profit_per_second ?? BigInt(0), army?.profit_per_second ?? BigInt(0),
player?.last_raided_at ?? BigInt(0) player?.last_raided_at ?? BigInt(0)
), true); ));
availableBalance.current = toReadable(balance, true); availableBalance.current = toReadable(balance);
render(); render();
}, 100); }, 100);
return () => clearInterval(tickInterval) return () => clearInterval(tickInterval)

View File

@ -25,7 +25,6 @@ const Header = () => {
const perSecondParagraph = useMemo(() => { const perSecondParagraph = useMemo(() => {
const perSecond = toReadable(army?.profit_per_second ?? BigInt(0)) const perSecond = toReadable(army?.profit_per_second ?? BigInt(0))
console.log(perSecond, army?.profit_per_second)
return (isRegistered) ? return (isRegistered) ?
<p className={styles.counter_per_seconds}>per second: {perSecond}</p> <p className={styles.counter_per_seconds}>per second: {perSecond}</p>
: null : null

View File

@ -26,7 +26,7 @@ const Home: NextPage = () => {
</main> </main>
<footer className={styles.footer}> <footer className={styles.footer}>
Made with by your fren mic0 Made with by your frens at 😈 Slay the Moloch team for Cohort VII of <a href="https://www.raidguild.org/" target="blank">RaidGuild</a>
</footer> </footer>
</div> </div>
); );

View File

@ -2,8 +2,8 @@ import React, { createContext, ReactNode, useCallback, useContext, useEffect } f
import { useAccount, useReadContract, useWriteContract } from 'wagmi' import { useAccount, useReadContract, useWriteContract } from 'wagmi'
import contractAbi from "../../../out/RaidGeld.sol/RaidGeld.json" import contractAbi from "../../../out/RaidGeld.sol/RaidGeld.json"
import { parseEther } from 'viem' import { parseEther } from 'viem'
import contractAddress from '../../contract_address'
const contractAddress = "0xbd06B0878888bf4c6895704fa603a5ADf7e65c66"
const abi = contractAbi.abi const abi = contractAbi.abi
export interface Player { export interface Player {
@ -91,7 +91,7 @@ const PlayerProvider = ({ children }: { children: ReactNode }) => {
} }
}); });
console.log(player) console.log(player, army)
const register = useCallback(() => { const register = useCallback(() => {
writeContract({ writeContract({

View File

@ -21,19 +21,10 @@
} }
.footer { .footer {
display: flex; margin-top: 2rem;
flex: 1;
padding: 2rem 0; padding: 2rem 0;
border-top: 1px solid #eaeaea; border-top: 1px solid #eaeaea;
justify-content: center; text-align: center;
align-items: center;
}
.footer a {
display: flex;
justify-content: center;
align-items: center;
flex-grow: 1;
} }
.title a { .title a {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -63,7 +63,7 @@ contract RaidGeld is ERC20, Ownable {
// Helper so we can use it when buying units too // Helper so we can use it when buying units too
function performRaid(address player) private { function performRaid(address player) private {
uint256 time_past = block.timestamp - players[player].last_raided_at; uint256 time_past = block.timestamp - players[player].last_raided_at;
uint256 new_geld = armies[player].profit_per_second * time_past; uint256 new_geld = armies[player].profit_per_second * time_past;
// TODO: Pink noise, make it so sometimes its better than expected // TODO: Pink noise, make it so sometimes its better than expected
@ -109,14 +109,14 @@ contract RaidGeld is ERC20, Ownable {
} }
uint256 cost = RaidGeldUtils.calculateUnitPrice(unit, currentLevel, n_units); uint256 cost = RaidGeldUtils.calculateUnitPrice(unit, currentLevel, n_units);
// First trigger a raid so player receives what he is due at to this moment // First trigger a raid so player receives what he is due at to this moment
performRaid(msg.sender); performRaid(msg.sender);
require(balanceOf(msg.sender) > cost, "Not enough GELD to add this much"); require(balanceOf(msg.sender) > cost, "Not enough GELD to add this much");
// TODO: Since we are first minting then burning the token, this could be simplified // TODO: Since we are first minting then burning the token, this could be simplified
// by first calculating the difference and then minting / burning in just one operation // by first calculating the difference and then minting / burning in just one operation
// then burn the cost of the new army // then burn the cost of the new army
_burn(msg.sender, cost); _burn(msg.sender, cost);
// Increase level // Increase level

View File

@ -1,8 +1,6 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity ^0.8.13; pragma solidity ^0.8.13;
struct Raider { struct Raider {
uint16 level; uint16 level;
} }
@ -19,4 +17,4 @@ struct Player {
uint256 total_minted; uint256 total_minted;
uint256 created_at; uint256 created_at;
uint256 last_raided_at; uint256 last_raided_at;
} }

View File

@ -4,15 +4,12 @@ pragma solidity ^0.8.13;
import {Army} from "../src/RaidGeldStructs.sol"; import {Army} from "../src/RaidGeldStructs.sol";
library RaidGeldUtils { library RaidGeldUtils {
uint256 public constant PRECISION = 10000; uint256 public constant PRECISION = 10000;
uint256 constant BASE_PRICE = 380000; uint256 constant BASE_PRICE = 380000;
uint256 constant PRICE_FACTOR = 11500; uint256 constant PRICE_FACTOR = 11500;
uint256 constant APPRENTICE_PROFIT = 61000; uint256 constant APPRENTICE_PROFIT = 61000;
uint256 constant ANOINTED_PROFIT = 6 * 64000; uint256 constant ANOINTED_PROFIT = 6 * 64000;
uint256 constant CHAMPION_PROFIT = 67000 * 61000 * 64000/ PRECISION / PRECISION; uint256 constant CHAMPION_PROFIT = 67000 * 61000 * 64000 / PRECISION / PRECISION;
function calculateUnitPrice(uint8 unit, uint16 currentLevel, uint16 units) internal pure returns (uint256) { function calculateUnitPrice(uint8 unit, uint16 currentLevel, uint16 units) internal pure returns (uint256) {
require(unit <= 3, "No matching unit found"); require(unit <= 3, "No matching unit found");
@ -37,7 +34,7 @@ library RaidGeldUtils {
uint256 apprentice_profit = army.apprentice.level * APPRENTICE_PROFIT; uint256 apprentice_profit = army.apprentice.level * APPRENTICE_PROFIT;
uint256 anointed_profit = army.anointed.level * ANOINTED_PROFIT; uint256 anointed_profit = army.anointed.level * ANOINTED_PROFIT;
uint256 champion_profit = army.champion.level * CHAMPION_PROFIT; uint256 champion_profit = army.champion.level * CHAMPION_PROFIT;

View File

@ -3,7 +3,7 @@ pragma solidity ^0.8.13;
import {Test, console} from "forge-std/Test.sol"; import {Test, console} 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";
contract raid_geldTest is Test { contract raid_geldTest is Test {
RaidGeld public raid_geld; RaidGeld public raid_geld;
@ -124,7 +124,7 @@ contract raid_geldTest is Test {
// Check that those tokens were burnt // Check that those tokens were burnt
// WARN: In addUnit will mint additional tokens but they are not calculated // WARN: In addUnit will mint additional tokens but they are not calculated
// into this because the test doesnt move the blockchain so no extra tokens // into this because the test doesnt move the blockchain so no extra tokens
// are minted to the user // are minted to the user
uint256 newBalance = raid_geld.balanceOf(player1); uint256 newBalance = raid_geld.balanceOf(player1);
assertEq(newBalance, balance - unitPrice); assertEq(newBalance, balance - unitPrice);

View File

@ -3,14 +3,14 @@ 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/RaidGeld.sol";
import "../src/RaidGeldUtils.sol"; import "../src/RaidGeldUtils.sol";
contract raid_geldTest is Test { contract raid_geldTest is Test {
function test_0_unit_price() public { function test_0_unit_price() public pure {
// buying 1 unit of moloch_denier // buying 1 unit of moloch_denier
uint256 basePriceMolochDenier = RaidGeldUtils.calculateUnitPrice(0, 0, 1); uint256 basePriceMolochDenier = RaidGeldUtils.calculateUnitPrice(0, 0, 1);
assertEq(basePriceMolochDenier, RaidGeldUtils.BASE_PRICE); assertEq(basePriceMolochDenier, RaidGeldUtils.BASE_PRICE);
// buying 3 units // buying 3 units
// has to be a bit more than 3 * 38 = 114 // has to be a bit more than 3 * 38 = 114
uint256 price = RaidGeldUtils.calculateUnitPrice(0, 0, 3); uint256 price = RaidGeldUtils.calculateUnitPrice(0, 0, 3);
@ -30,28 +30,25 @@ contract raid_geldTest is Test {
function test_1_profits_per_second(uint16 _dLvl, uint16 _apLvl, uint16 _anLvl, uint16 _cLvl) public { function test_1_profits_per_second(uint16 _dLvl, uint16 _apLvl, uint16 _anLvl, uint16 _cLvl) public {
Army memory army = Army({ Army memory army = Army({
moloch_denier: Raider({ level: 1}), moloch_denier: Raider({level: 1}),
apprentice: Raider({ level: 0}), apprentice: Raider({level: 0}),
anointed: Raider({ level: 0}), anointed: Raider({level: 0}),
champion: Raider({ level: 0}), champion: Raider({level: 0}),
profit_per_second: 0 // irrelevant for this test profit_per_second: 0 // irrelevant for this test
}); });
uint256 profits_per_second = RaidGeldUtils.calculateProfitsPerSecond(army); uint256 profits_per_second = RaidGeldUtils.calculateProfitsPerSecond(army);
assertEq(profits_per_second, RaidGeldUtils.PRECISION); assertEq(profits_per_second, RaidGeldUtils.PRECISION);
army = Army({ army = Army({
moloch_denier: Raider({ level: _dLvl}), moloch_denier: Raider({level: _dLvl}),
apprentice: Raider({ level: _apLvl}), apprentice: Raider({level: _apLvl}),
anointed: Raider({ level: _anLvl}), anointed: Raider({level: _anLvl}),
champion: Raider({ level: _cLvl}), champion: Raider({level: _cLvl}),
profit_per_second: 0 // irrelevant for this test profit_per_second: 0 // irrelevant for this test
}); });
profits_per_second = RaidGeldUtils.calculateProfitsPerSecond(army); profits_per_second = RaidGeldUtils.calculateProfitsPerSecond(army);
uint256 expected = uint256 expected = _dLvl * RaidGeldUtils.PRECISION + _apLvl * RaidGeldUtils.APPRENTICE_PROFIT
_dLvl * RaidGeldUtils.PRECISION + + _anLvl * RaidGeldUtils.ANOINTED_PROFIT + _cLvl * RaidGeldUtils.CHAMPION_PROFIT;
_apLvl * RaidGeldUtils.APPRENTICE_PROFIT +
_anLvl * RaidGeldUtils.ANOINTED_PROFIT +
_cLvl * RaidGeldUtils.CHAMPION_PROFIT;
assertEq(profits_per_second, expected); assertEq(profits_per_second, expected);
} }
} }