From 738378d93e075a4baa7b7909c2bcdc74d38a5317 Mon Sep 17 00:00:00 2001 From: yellow <8539006+yellowBirdy@users.noreply.github.com> Date: Fri, 25 Oct 2024 02:13:52 +0200 Subject: [PATCH] bit of a refactor --- src/RaidGeld.sol | 28 ++++++---------------------- src/RaidGeldStructs.sol | 22 ++++++++++++++++++++++ src/RaidGeldUtils.sol | 31 +++++++++++++++++++++++-------- test/RaidGeld.t.sol | 4 +--- test/RaidGeldUtils.t.sol | 21 +++++++++++++-------- 5 files changed, 65 insertions(+), 41 deletions(-) create mode 100644 src/RaidGeldStructs.sol diff --git a/src/RaidGeld.sol b/src/RaidGeld.sol index feb5422..e5bf6ba 100644 --- a/src/RaidGeld.sol +++ b/src/RaidGeld.sol @@ -4,29 +4,13 @@ pragma solidity ^0.8.13; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import {RaidGeldUtils} from "../src/RaidGeldUtils.sol"; - -struct Raider { - uint16 level; -} - -struct Army { - Raider moloch_denier; - Raider apprentice; - Raider anointed; - Raider champion; - uint256 profit_per_second; -} - -struct Player { - uint256 total_minted; - uint256 created_at; - uint256 last_raided_at; -} +import {Army, Player, Raider} from "../src/RaidGeldStructs.sol"; contract RaidGeld is ERC20, Ownable { - uint8 constant DECIMALS = 4; + uint256 public constant MANTISSA = 1e4; + uint256 public constant BUY_IN_AMOUNT = 0.00005 ether; - uint256 public constant INITIAL_GELD = 50 * 10 ** DECIMALS; + uint256 public constant INITIAL_GELD = 50 * MANTISSA; uint256 public constant RAID_WAIT = 15 seconds; mapping(address => Player) private players; @@ -80,7 +64,7 @@ contract RaidGeld is ERC20, Ownable { function performRaid(address player) private { uint256 time_past = block.timestamp - players[player].last_raided_at; - uint256 new_geld = armies[player].profit_per_second * time_past * 10 ** decimals(); + uint256 new_geld = armies[player].profit_per_second * time_past; // TODO: Pink noise, make it so sometimes its better than expected @@ -124,7 +108,7 @@ contract RaidGeld is ERC20, Ownable { currentLevel = army.champion.level; } - uint256 cost = RaidGeldUtils.calculateUnitPrice(unit, currentLevel, n_units) * 10 ** decimals(); + uint256 cost = RaidGeldUtils.calculateUnitPrice(unit, currentLevel, n_units); 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 diff --git a/src/RaidGeldStructs.sol b/src/RaidGeldStructs.sol new file mode 100644 index 0000000..c846e87 --- /dev/null +++ b/src/RaidGeldStructs.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + + + +struct Raider { + uint16 level; +} + +struct Army { + Raider moloch_denier; + Raider apprentice; + Raider anointed; + Raider champion; + uint256 profit_per_second; +} + +struct Player { + uint256 total_minted; + uint256 created_at; + uint256 last_raided_at; +} \ No newline at end of file diff --git a/src/RaidGeldUtils.sol b/src/RaidGeldUtils.sol index 5a702c7..e5a5427 100644 --- a/src/RaidGeldUtils.sol +++ b/src/RaidGeldUtils.sol @@ -1,18 +1,28 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.13; -import {Army} from "../src/RaidGeld.sol"; +import {Army} from "../src/RaidGeldStructs.sol"; library RaidGeldUtils { + + uint256 public constant PRECISION = 10000; + + uint256 constant BASE_PRICE = 380000; + uint256 constant PRICE_FACTOR = 11500; + uint256 constant APPRENTICE_PROFIT = 61000; + uint256 constant ANOINTED_PROFIT = 6 * 64000; + uint256 constant CHAMPION_PROFIT = 67000 * 61000 * 64000/ PRECISION / PRECISION; + + function calculateUnitPrice(uint8 unit, uint16 currentLevel, uint16 units) internal pure returns (uint256) { require(unit <= 3, "No matching unit found"); - uint256 rollingPriceCalculation = uint256(unit + 1) * 38; + + uint256 rollingPriceCalculation = uint256(unit + 1) * BASE_PRICE; uint256 price = rollingPriceCalculation; // Each level costs 15% more than previous - uint256 PERCENT_INCREASE = 115; for (uint256 i = 1; i < currentLevel + units; i++) { - rollingPriceCalculation = rollingPriceCalculation * PERCENT_INCREASE / 100; + rollingPriceCalculation = rollingPriceCalculation * PRICE_FACTOR / PRECISION; if (i >= currentLevel) { price += rollingPriceCalculation; } @@ -22,10 +32,15 @@ library RaidGeldUtils { function calculateProfitsPerSecond(Army memory army) internal pure returns (uint256) { // Each next unit scales progressivelly better - uint256 moloch_denier_profit = army.moloch_denier.level; - uint256 apprentice_profit = army.apprentice.level * 61 / 10; - uint256 anointed_profit = army.anointed.level * 6 * 64 / 10; - uint256 champion_profit = army.champion.level * 61 / 10 * 64 / 10 * 67 / 10; + + uint256 moloch_denier_profit = army.moloch_denier.level * PRECISION; + + uint256 apprentice_profit = army.apprentice.level * APPRENTICE_PROFIT; + + uint256 anointed_profit = army.anointed.level * ANOINTED_PROFIT; + + uint256 champion_profit = army.champion.level * CHAMPION_PROFIT; + return moloch_denier_profit + apprentice_profit + anointed_profit + champion_profit; } } diff --git a/test/RaidGeld.t.sol b/test/RaidGeld.t.sol index 6f31f6e..c704c5d 100644 --- a/test/RaidGeld.t.sol +++ b/test/RaidGeld.t.sol @@ -118,10 +118,9 @@ contract raid_geldTest is Test { uint256 unit_level = army.moloch_denier.level; uint256 balance = raid_geld.balanceOf(player1); uint256 income_per_sec = army.profit_per_second; - // Add 1 unit raid_geld.addUnit(0, 1); - uint256 unitPrice = RaidGeldUtils.calculateUnitPrice(0, 0, 1) * 10 ** 4; + uint256 unitPrice = RaidGeldUtils.calculateUnitPrice(0, 0, 1); // Check that those tokens were burnt // WARN: In addUnit will mint additional tokens but they are not calculated @@ -134,7 +133,6 @@ contract raid_geldTest is Test { // Check that unit level increased uint256 new_unit_level = army.moloch_denier.level; assertEq(new_unit_level, unit_level + 1); - // Check that user income per second increased uint256 new_income_per_sec = army.profit_per_second; assertLt(income_per_sec, new_income_per_sec); diff --git a/test/RaidGeldUtils.t.sol b/test/RaidGeldUtils.t.sol index 2c377ed..4ac0f19 100644 --- a/test/RaidGeldUtils.t.sol +++ b/test/RaidGeldUtils.t.sol @@ -9,7 +9,7 @@ contract raid_geldTest is Test { function test_0_unit_price() public { // buying 1 unit of moloch_denier uint256 basePriceMolochDenier = RaidGeldUtils.calculateUnitPrice(0, 0, 1); - assertEq(basePriceMolochDenier, 38); + assertEq(basePriceMolochDenier, RaidGeldUtils.BASE_PRICE); // buying 3 units // has to be a bit more than 3 * 38 = 114 @@ -28,7 +28,7 @@ contract raid_geldTest is Test { assertGt(price, basePriceChamp * 12); } - function test_1_profits_per_second() public { + function test_1_profits_per_second(uint16 _dLvl, uint16 _apLvl, uint16 _anLvl, uint16 _cLvl) public { Army memory army = Army({ moloch_denier: Raider({ level: 1}), apprentice: Raider({ level: 0}), @@ -37,16 +37,21 @@ contract raid_geldTest is Test { profit_per_second: 0 // irrelevant for this test }); uint256 profits_per_second = RaidGeldUtils.calculateProfitsPerSecond(army); - assertEq(profits_per_second, 1); + assertEq(profits_per_second, RaidGeldUtils.PRECISION); army = Army({ - moloch_denier: Raider({ level: 2}), - apprentice: Raider({ level: 0}), - anointed: Raider({ level: 10}), - champion: Raider({ level: 1}), + moloch_denier: Raider({ level: _dLvl}), + apprentice: Raider({ level: _apLvl}), + anointed: Raider({ level: _anLvl}), + champion: Raider({ level: _cLvl}), profit_per_second: 0 // irrelevant for this test }); profits_per_second = RaidGeldUtils.calculateProfitsPerSecond(army); - assertEq(profits_per_second, 640); + uint256 expected = + _dLvl * RaidGeldUtils.PRECISION + + _apLvl * RaidGeldUtils.APPRENTICE_PROFIT + + _anLvl * RaidGeldUtils.ANOINTED_PROFIT + + _cLvl * RaidGeldUtils.CHAMPION_PROFIT; + assertEq(profits_per_second, expected); } }