Compare commits
6 Commits
cc9cb65e4e
...
87b9ecce67
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
87b9ecce67 | ||
|
|
836e3d8719 | ||
|
|
de3ba29ac6 | ||
|
|
c3f8852de7 | ||
|
|
925c199fef | ||
|
|
296113a68d |
6
.gitmodules
vendored
6
.gitmodules
vendored
@ -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
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import { Address } from "viem"
|
||||
|
||||
const contracts: Record<string, Address> = {
|
||||
contractAddress: "0xbd06B0878888bf4c6895704fa603a5ADf7e65c66",
|
||||
// contractAddress: "0xbd06B0878888bf4c6895704fa603a5ADf7e65c66",
|
||||
contractAddress: "0x4593ed9CbE6003e687e5e77368534bb04b162503",
|
||||
daoTokenAddress: "0x11dC980faf34A1D082Ae8A6a883db3A950a3c6E8"
|
||||
}
|
||||
|
||||
|
||||
@ -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) => {
|
||||
|
||||
@ -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/",
|
||||
]
|
||||
1
lib/openzeppelin-contracts-upgradeable
Submodule
1
lib/openzeppelin-contracts-upgradeable
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit fa525310e45f91eb20a6d3baa2644be8e0adba31
|
||||
1
lib/openzeppelin-foundry-upgrades
Submodule
1
lib/openzeppelin-foundry-upgrades
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 16e0ae21e0e39049f619f2396fa28c57fad07368
|
||||
@ -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
92
src/IRaidGeld.sol
Normal 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;
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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}();
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user