Compare commits

...

6 Commits

Author SHA1 Message Date
yellow
87b9ecce67 upgrades wip (deploys)
Some checks failed
CI / Foundry project (push) Has been cancelled
2024-11-10 05:07:06 +01:00
yellow
836e3d8719 forge install: openzeppelin-contracts-upgradeable
v5.1.0
2024-11-10 02:33:41 +01:00
yellow
de3ba29ac6 forge install: openzeppelin-foundry-upgrades
v0.3.6
2024-11-10 02:13:38 +01:00
yellow
c3f8852de7 interface added 2024-11-09 22:14:21 +01:00
yellow
925c199fef no snake case in RaidGeld.sol 2024-11-09 22:11:53 +01:00
yellow
296113a68d reg names 2024-11-09 22:07:38 +01:00
11 changed files with 180 additions and 34 deletions

6
.gitmodules vendored
View File

@ -7,3 +7,9 @@
[submodule "lib/Baal"]
path = lib/Baal
url = https://github.com/HausDAO/Baal
[submodule "lib/openzeppelin-foundry-upgrades"]
path = lib/openzeppelin-foundry-upgrades
url = https://github.com/OpenZeppelin/openzeppelin-foundry-upgrades
[submodule "lib/openzeppelin-contracts-upgradeable"]
path = lib/openzeppelin-contracts-upgradeable
url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable

View File

@ -1,7 +1,8 @@
import { Address } from "viem"
const contracts: Record<string, Address> = {
contractAddress: "0xbd06B0878888bf4c6895704fa603a5ADf7e65c66",
// contractAddress: "0xbd06B0878888bf4c6895704fa603a5ADf7e65c66",
contractAddress: "0x4593ed9CbE6003e687e5e77368534bb04b162503",
daoTokenAddress: "0x11dC980faf34A1D082Ae8A6a883db3A950a3c6E8"
}

View File

@ -176,7 +176,7 @@ const PlayerProvider = ({ children }: { children: ReactNode }) => {
{
abi,
address: contractAddress,
functionName: "register_eth",
functionName: "registerEth",
value: parseEther("0.00045"),
},
{
@ -203,7 +203,7 @@ const PlayerProvider = ({ children }: { children: ReactNode }) => {
{
abi,
address: contractAddress,
functionName: "register_dao",
functionName: "registerDaoToken",
},
{
onSuccess: (hash) => {
@ -263,7 +263,7 @@ const PlayerProvider = ({ children }: { children: ReactNode }) => {
{
abi,
address: contractAddress,
functionName: "battle_with_boss",
functionName: "battleWithBoss",
},
{
onSuccess: (hash) => {

View File

@ -3,9 +3,17 @@ src = "src"
out = "out"
libs = ["lib"]
# upgrades
ffi = true
ast = true
build_info = true
extra_output = ["storageLayout"]
# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options
remappings = [
"@uniswap/v3-core/=lib/v3-core/",
"@uniswap/v3-periphery=lib/v3-periphery/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/",
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
]

@ -0,0 +1 @@
Subproject commit fa525310e45f91eb20a6d3baa2644be8e0adba31

@ -0,0 +1 @@
Subproject commit 16e0ae21e0e39049f619f2396fa28c57fad07368

View File

@ -12,7 +12,7 @@ contract RaidGeldScript is Script, Constants {
function run() public {
vm.startBroadcast();
raidgeld = new RaidGeld(DAO_TOKEN, POOL, BAAL, NFT_POSITION_MANAGER);
// raidgeld = new RaidGeld(DAO_TOKEN, POOL, BAAL, NFT_POSITION_MANAGER);
vm.stopBroadcast();
}
}

92
src/IRaidGeld.sol Normal file
View File

@ -0,0 +1,92 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
import {Army, Player, Boss, LastBossResult} from "./RaidGeldStructs.sol";
/**
* @title IRaidGeld
* @dev Interface for the RaidGeld contract
*/
interface IRaidGeld {
/**
* @notice Registers ETH for the player
*/
function registerEth() external payable;
/**
* @notice Registers DAO tokens for the player
*/
function registerDaoToken() external payable;
/**
* @notice Initiates a raid
*/
function raid() external;
/**
* @notice Adds units to the player's army
* @param unit The type of unit to add
* @param n_units The number of units to add
*/
function addUnit(uint8 unit, uint16 n_units) external;
/**
* @notice Initiates a battle with the boss
* @return hasWonOrAscended An array indicating if the player has won or ascended
*/
function battleWithBoss() external returns (bool[2] memory hasWonOrAscended);
/**
* @notice Gets the player information
* @param addr The address of the player
* @return Player The player information
*/
function getPlayer(address addr) external view returns (Player memory);
/**
* @notice Gets the army information of the player
* @param addr The address of the player
* @return Army The army information
*/
function getArmy(address addr) external view returns (Army memory);
/**
* @notice Gets the boss information
* @param addr The address of the boss
* @return Boss The boss information
*/
function getBoss(address addr) external view returns (Boss memory);
/**
* @notice Gets the result of the last boss battle
* @param addr The address of the player
* @return LastBossResult The result of the last boss battle
*/
function getLastBossResult(address addr) external view returns (LastBossResult memory);
/**
* @notice Checks if the player is registered
* @param addr The address of the player
* @return bool True if the player is registered, false otherwise
*/
function isRegistered(address addr) external view returns (bool);
/**
* @notice Sets the buy-in amount for DAO tokens
* @param newAmount The new buy-in amount
*/
function setDaoTokenBuyInAmount(uint256 newAmount) external;
/**
* @notice Deploys a swap pool with specified amounts of GELD and DAO tokens
* @param _geldAmount The amount of GELD tokens
* @param _daoTokenAmount The amount of DAO tokens
*/
function deploySwapPool(uint256 _geldAmount, uint256 _daoTokenAmount) external;
/**
* @notice Sets the DAO address
* @param _dao The new DAO address
*/
function setDaoAddress(address _dao) external;
}

View File

@ -1,20 +1,23 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {IBaal} from "lib/Baal/contracts/interfaces/IBaal.sol";
import { IUniswapV3Factory } from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Factory.sol";
import { IERC20, TransferHelper } from "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol";
import { TransferHelper } from "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol";
import { INonfungiblePositionManager } from "./lib/INonfungiblePositionManager.sol";
import { CustomMath} from "./lib/CustomMath.sol";
import { IRaidGeld } from "./IRaidGeld.sol";
import {RaidGeldUtils } from "../src/RaidGeldUtils.sol";
import {Army, Player, Raider, Boss, LastBossResult} from "../src/RaidGeldStructs.sol";
import { Constants} from "../src/Constants.sol";
contract RaidGeld is ERC20, Ownable, Constants {
contract RaidGeld is ERC20Upgradeable, OwnableUpgradeable, Constants, IRaidGeld {
uint256 public constant MANTISSA = 1e4;
uint256 public constant BUY_IN_AMOUNT = 0.00045 ether;
uint256 public BUY_IN_DAO_TOKEN_AMOUNT;
@ -26,15 +29,15 @@ contract RaidGeld is ERC20, Ownable, Constants {
mapping(address => LastBossResult) private lastBossResults;
// WETH
IWETH public immutable weth = IWETH(WETH);
IWETH public constant weth = IWETH(WETH);
// RGCVII token
ERC20 public daoToken;
IERC20Metadata public daoToken;
IBaal public baal;
address public DAO;
bool poolDeployed = false;
bool poolDeployed;
int24 internal maxTick;
int24 internal minTick;
uint24 internal poolFee = 10000;
uint24 internal constant poolFee = 10000;
INonfungiblePositionManager public nonfungiblePositionManager;
// RGCVII pool
address public DAOWETHpool;
@ -104,8 +107,25 @@ contract RaidGeld is ERC20, Ownable, Constants {
_;
}
constructor(address _daoToken, address _pool, address _baal, address _nftPositionManager) ERC20("Raid Geld", "GELD") Ownable(msg.sender) {
daoToken = ERC20(_daoToken);
// constructor(address _daoToken, address _pool, address _baal, address _nftPositionManager) {
// daoToken = IERC20Metadata(_daoToken);
// DAOWETHpool = _pool;
// baal = IBaal(_baal);
// BUY_IN_DAO_TOKEN_AMOUNT = 400 * 10 ** daoToken.decimals();
// nonfungiblePositionManager = INonfungiblePositionManager(_nftPositionManager);
// IUniswapV3Factory factory = IUniswapV3Factory(nonfungiblePositionManager.factory());
// int24 tickSpacing = factory.feeAmountTickSpacing(poolFee);
// require(tickSpacing != 0, "InvalidPoolFee");
// maxTick = (887272 / tickSpacing) * tickSpacing;
// minTick = -maxTick;
// }
function initialize(address _owner, address _daoToken, address _pool, address _baal, address _nftPositionManager) public initializer {
__ERC20_init("RaidGeld", "GELD");
__Ownable_init(_owner);
daoToken = IERC20Metadata(_daoToken);
DAOWETHpool = _pool;
baal = IBaal(_baal);
BUY_IN_DAO_TOKEN_AMOUNT = 400 * 10 ** daoToken.decimals();
@ -118,7 +138,7 @@ contract RaidGeld is ERC20, Ownable, Constants {
minTick = -maxTick;
}
function start_game(address player) private {
function startGame(address player) private {
bool existing_player = players[player].is_registered;
// Mint some starting tokens to the player
@ -160,7 +180,7 @@ contract RaidGeld is ERC20, Ownable, Constants {
}
// New player want to register with ETH
function register_eth() external payable newPlay {
function registerEth() external payable newPlay {
require(msg.value == BUY_IN_AMOUNT, "Incorrect buy in amount");
weth.deposit{value: BUY_IN_AMOUNT}();
weth.approve(address(router), BUY_IN_AMOUNT);
@ -175,18 +195,18 @@ contract RaidGeld is ERC20, Ownable, Constants {
});
uint256 daoTokenAmount = router.exactInputSingle(params);
performSacrifice(daoTokenAmount);
start_game(msg.sender);
startGame(msg.sender);
}
// New player wants to register with dao
function register_dao() external payable newPlay {
function registerDaoToken() external payable newPlay {
//@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"
);
performSacrifice(BUY_IN_DAO_TOKEN_AMOUNT);
start_game(msg.sender);
startGame(msg.sender);
}
function performSacrifice(uint256 _baseAmount) private {
uint256 amount = _baseAmount * SACRIFICE_SHARE / MANTISSA;
@ -301,7 +321,7 @@ contract RaidGeld is ERC20, Ownable, Constants {
);
}
function battle_with_boss() external onlyActiveSession returns (bool[2] memory hasWonOrAscended) {
function battleWithBoss() external onlyActiveSession returns (bool[2] memory hasWonOrAscended) {
// first perform raid
performRaid(msg.sender);
Boss memory boss_to_attack = bosses[msg.sender];
@ -340,7 +360,7 @@ contract RaidGeld is ERC20, Ownable, Constants {
// User ascends! Moloch is defeated, user can start a new run
players[msg.sender].prestige_level += 1;
emit PrestigeGained(msg.sender, players[msg.sender].prestige_level);
player_dies(msg.sender);
playerDies(msg.sender);
lastBossResults[msg.sender].prestigeGained = true;
return [hasWonBattle, true /* New prestige level! */ ];
} else {
@ -350,12 +370,12 @@ contract RaidGeld is ERC20, Ownable, Constants {
} else {
// Whoops u died, boss defeated you
lastBossResults[msg.sender].reward = 0;
player_dies(msg.sender);
playerDies(msg.sender);
}
return [hasWonBattle, false /* hasnt gotten prestige level */ ];
}
function player_dies(address player) private {
function playerDies(address player) private {
resetPlayer(player);
players[player].has_active_session = false;
_burn(msg.sender, balanceOf(player));
@ -464,7 +484,7 @@ interface ISwapRouter02 {
function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn);
}
interface IWETH is IERC20 {
interface IWETH is IERC20Metadata {
function deposit() external payable;
function withdraw(uint256 amount) external;
}

View File

@ -3,6 +3,7 @@ pragma solidity ^0.8.13;
import {Test, console} from "forge-std/Test.sol";
import {stdStorage, StdStorage} from "forge-std/Test.sol";
import {Upgrades} from "openzeppelin-foundry-upgrades/Upgrades.sol";
import {RaidGeld, Army, Player, Boss, LastBossResult} from "../src/RaidGeld.sol";
import "../src/RaidGeldUtils.sol";
import {Constants} from "../src/Constants.sol";
@ -38,22 +39,38 @@ contract raid_geldTest is Test, Constants {
vm.deal(owner, 10 ether);
fundAccount(player1);
vm.prank(owner);
raid_geld = new RaidGeld(DAO_TOKEN, POOL, BAAL, NFT_POSITION_MANAGER);
// raid_geld = new RaidGeld(DAO_TOKEN, POOL, BAAL, NFT_POSITION_MANAGER);
// raid_geld.weth().deposit{value: 5 ether}();
address proxy = Upgrades.deployUUPSProxy(
"RaidGeld.sol:RaidGeld",
abi.encodeCall(RaidGeld.initialize, (
owner,
DAO_TOKEN,
POOL,
BAAL,
NFT_POSITION_MANAGER
))
);
console.log("Upgrades sysmbol", RaidGeld(payable(proxy)).symbol());
raid_geld = RaidGeld(payable(proxy));
raid_geld.weth().deposit{value: 5 ether}();
}
function fundAccount(address _acc) private {
vm.deal(_acc, 10 ether);
console.log("dao token", DAO_TOKEN);
stdstore.target(DAO_TOKEN).sig("balanceOf(address)").with_key(_acc).checked_write(1000 ether);
}
function registerPlayer() private {
raid_geld.register_eth{value: raid_geld.BUY_IN_AMOUNT()}();
raid_geld.registerEth{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.registerDaoToken();
}
function test_00_no_fallback() public {
@ -281,7 +298,7 @@ contract raid_geldTest is Test, Constants {
// Make a lot of time pass so user deffo has GELD to attack the boss
vm.warp(1200000);
bool[2] memory results = raid_geld.battle_with_boss();
bool[2] memory results = raid_geld.battleWithBoss();
// Should almost always defeat first boss
assertEq(results[0], true);
// First boss doesnt grant a new prestige level (ascension)
@ -322,7 +339,7 @@ contract raid_geldTest is Test, Constants {
raid_geld.addUnit(0, 1);
Boss memory boss = raid_geld.getBoss(player1);
bool[2] memory results = raid_geld.battle_with_boss();
bool[2] memory results = raid_geld.battleWithBoss();
// Should lose with just starting GELD
assertEq(results[0], false);
// First boss doesnt grant a new prestige level (ascension)
@ -359,7 +376,7 @@ contract raid_geldTest is Test, Constants {
// Contract gets DAO Tokens with first register
assertLt(balance1, balance2);
bool[2] memory results = raid_geld.battle_with_boss();
bool[2] memory results = raid_geld.battleWithBoss();
// Should lose with just starting GELD
assertEq(results[0], false);
Player memory player = raid_geld.getPlayer(player1);
@ -395,7 +412,7 @@ contract raid_geldTest is Test, Constants {
for (uint j = 0; j < 6; j++) {
vm.prevrandao(prevrandao + j * 7 + i * 59);
newStreak += 1;
results = raid_geld.battle_with_boss();
results = raid_geld.battleWithBoss();
if (results[0] == false) {
alreadyLost = true;
break;
@ -407,7 +424,7 @@ contract raid_geldTest is Test, Constants {
}
continue;
}
results = raid_geld.battle_with_boss();
results = raid_geld.battleWithBoss();
if (results[0] == true && results[1] == true) {
success = true;
Player memory player = raid_geld.getPlayer(player1);

View File

@ -17,7 +17,7 @@ contract raid_geldTest is Test, Constants {
owner = address(0x126);
vm.deal(owner, 10 ether);
vm.prank(owner);
raid_geld = new RaidGeld(DAO_TOKEN, POOL, BAAL, NFT_POSITION_MANAGER);
// raid_geld = new RaidGeld(DAO_TOKEN, POOL, BAAL, NFT_POSITION_MANAGER);
raid_geld.weth().deposit{value: 5 ether}();
}