Compare commits

..

5 Commits

Author SHA1 Message Date
aaf1c0fd46
Swapping WETH -> RGCVII
Some checks failed
CI / Foundry project (push) Waiting to run
CI / Foundry project (pull_request) Has been cancelled
2024-10-27 21:20:38 +01:00
d28e33612e
forge install: v3-core
v1.0.0
2024-10-27 13:37:24 +01:00
a4be82cbd9
Added v3-periphery and remappings 2024-10-27 13:37:15 +01:00
8b35e86904
forge install: v3-periphery
v1.3.0
2024-10-27 12:57:15 +01:00
d197935fae
Prepping uniswap of received ETH -> RGCVII 2024-10-27 12:57:05 +01:00
9 changed files with 78 additions and 30 deletions

6
.gitmodules vendored
View File

@ -4,3 +4,9 @@
[submodule "lib/openzeppelin-contracts"] [submodule "lib/openzeppelin-contracts"]
path = lib/openzeppelin-contracts path = lib/openzeppelin-contracts
url = https://github.com/OpenZeppelin/openzeppelin-contracts url = https://github.com/OpenZeppelin/openzeppelin-contracts
[submodule "lib/v3-periphery"]
path = lib/v3-periphery
url = https://github.com/uniswap/v3-periphery
[submodule "lib/v3-core"]
path = lib/v3-core
url = https://github.com/uniswap/v3-core

View File

@ -100,7 +100,7 @@ const PlayerProvider = ({ children }: { children: ReactNode }) => {
abi, abi,
address: contractAddress, address: contractAddress,
functionName: 'register', functionName: 'register',
value: parseEther("0.00005"), value: parseEther("0.0005"),
}) })
}, [writeContract]) }, [writeContract])

1
lib/v3-core Submodule

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

1
lib/v3-periphery Submodule

@ -0,0 +1 @@
Subproject commit 80f26c86c57b8a5e4b913f42844d4c8bd274d058

View File

@ -1 +1,3 @@
@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/ @openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/
@uniswap/v3-periphery/contracts/=lib/v3-periphery/contracts
@uniswap/v3-core/contracts/=lib/v3-core/contracts

View File

@ -3,7 +3,6 @@ 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";
import {Constants} from "../src/Constants.sol"; import {Constants} from "../src/Constants.sol";
contract RaidGeldScript is Script, Constants { contract RaidGeldScript is Script, Constants {

View File

@ -5,4 +5,6 @@ contract Constants {
//base addresses //base addresses
address public constant DAO_TOKEN = 0x11dC980faf34A1D082Ae8A6a883db3A950a3c6E8; address public constant DAO_TOKEN = 0x11dC980faf34A1D082Ae8A6a883db3A950a3c6E8;
address public constant POOL = 0x27004f6d0c1bB7979367D32Ba9d6DF6d61A18926; address public constant POOL = 0x27004f6d0c1bB7979367D32Ba9d6DF6d61A18926;
address public constant WETH = 0x4200000000000000000000000000000000000006;
address public constant SWAP_ROUTER = 0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD;
} }

View File

@ -3,28 +3,40 @@ pragma solidity ^0.8.13;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/access/Ownable.sol";
import '@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol';
import '@uniswap/v3-periphery/contracts/libraries/TransferHelper.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";
import "../src/Constants.sol";
contract RaidGeld is ERC20, Ownable, Constants {
contract RaidGeld is ERC20, Ownable {
uint256 public constant MANTISSA = 1e4; uint256 public constant MANTISSA = 1e4;
uint256 public constant BUY_IN_AMOUNT = 0.0005 ether;
uint256 public constant BUY_IN_AMOUNT = 0.00005 ether;
uint256 public immutable BUY_IN_DAO_TOKEN_AMOUNT; uint256 public immutable BUY_IN_DAO_TOKEN_AMOUNT;
uint256 public constant INITIAL_GELD = 50 * MANTISSA; uint256 public constant INITIAL_GELD = 50 * MANTISSA;
mapping(address => Player) private players; mapping(address => Player) private players;
mapping(address => Army) private armies; mapping(address => Army) private armies;
// WETH
IERC20 public immutable weth = IERC20(WETH);
// RGCVII token
ERC20 public daoToken; ERC20 public daoToken;
// RGCVII pool
address public pool; address public pool;
// Uniswap
ISwapRouter private constant router = ISwapRouter(SWAP_ROUTER);
// 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");
_; _;
} }
// Modifier for functions that should only be available to non initialized players
modifier newPlayer() {
require(players[msg.sender].created_at == 0, "Whoops, player already exists :)");
_;
}
constructor(address _daoToken, address _pool) ERC20("Raid Geld", "GELD") Ownable(msg.sender) { constructor(address _daoToken, address _pool) ERC20("Raid Geld", "GELD") Ownable(msg.sender) {
daoToken = ERC20(_daoToken); daoToken = ERC20(_daoToken);
@ -32,27 +44,13 @@ contract RaidGeld is ERC20, Ownable {
BUY_IN_DAO_TOKEN_AMOUNT = 50 * 10 ** daoToken.decimals(); BUY_IN_DAO_TOKEN_AMOUNT = 50 * 10 ** daoToken.decimals();
} }
// This effectively registers the user function init_player(address player) private {
function register() external payable {
require(players[msg.sender].created_at == 0, "Whoops, player already exists :)");
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(player, INITIAL_GELD);
// Set initial states // Set initial states
players[msg.sender] = players[player] =
Player({total_minted: INITIAL_GELD, created_at: block.timestamp, last_raided_at: block.timestamp}); Player({total_minted: INITIAL_GELD, created_at: block.timestamp, last_raided_at: block.timestamp});
armies[msg.sender] = Army({ armies[player] = Army({
moloch_denier: Raider({level: 0}), moloch_denier: Raider({level: 0}),
apprentice: Raider({level: 0}), apprentice: Raider({level: 0}),
anointed: Raider({level: 0}), anointed: Raider({level: 0}),
@ -61,6 +59,36 @@ contract RaidGeld is ERC20, Ownable {
}); });
} }
// New player want to register with ETH
function register_eth() external payable newPlayer {
require(weth.transferFrom(msg.sender, address(this), BUY_IN_AMOUNT), "Make sure to send exactly 0.0005 eth");
TransferHelper.safeApprove(WETH, address(router), BUY_IN_AMOUNT);
ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({
tokenIn: WETH,
tokenOut: DAO_TOKEN,
fee: 10000,
recipient: address(this),
deadline: block.timestamp,
amountIn: BUY_IN_AMOUNT,
amountOutMinimum: 0,
sqrtPriceLimitX96: 0
});
router.exactInputSingle(params);
init_player(msg.sender);
}
// New player wants to register with dao
function register_dao() external payable newPlayer {
//@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"
);
// Init player
init_player(msg.sender);
}
// Override for default number of decimals // Override for default number of decimals
function decimals() public view virtual override returns (uint8) { function decimals() public view virtual override returns (uint8) {
return 4; return 4;

View File

@ -3,12 +3,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 {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"; import {Constants} from "../src/Constants.sol";
import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";
contract raid_geldTest is Test, Constants { contract raid_geldTest is Test, Constants {
using stdStorage for StdStorage; using stdStorage for StdStorage;
RaidGeld public raid_geld; RaidGeld public raid_geld;
@ -28,15 +29,23 @@ contract raid_geldTest is Test, Constants {
function fundAccount(address _acc) private { function fundAccount(address _acc) private {
vm.deal(_acc, 10 ether); vm.deal(_acc, 10 ether);
stdstore.target(DAO_TOKEN).sig("balanceOf(address)").with_key(_acc).checked_write(100 ether); stdstore.target(DAO_TOKEN).sig("balanceOf(address)").with_key(_acc).checked_write(100 ether);
stdstore.target(WETH).sig("balanceOf(address)").with_key(_acc).checked_write(100 ether);
}
function getPoolLiquidity() public view {
IUniswapV3Pool pool = IUniswapV3Pool(POOL);
console.log(pool.liquidity());
} }
function registerPlayer() private { function registerPlayer() private {
raid_geld.register{value: raid_geld.BUY_IN_AMOUNT()}(); getPoolLiquidity();
raid_geld.weth().approve(address(raid_geld), raid_geld.BUY_IN_AMOUNT());
raid_geld.register_eth();
} }
function registerPlayerWithDaoToken() private { function registerPlayerWithDaoToken() private {
raid_geld.daoToken().approve(address(raid_geld), raid_geld.BUY_IN_DAO_TOKEN_AMOUNT()); raid_geld.daoToken().approve(address(raid_geld), raid_geld.BUY_IN_DAO_TOKEN_AMOUNT());
raid_geld.register(); raid_geld.register_dao();
} }
function test_00_no_fallback() public { function test_00_no_fallback() public {
@ -130,7 +139,7 @@ contract raid_geldTest is Test, Constants {
function test_03_02_RGCVII_funds_can_be_withdrawn() public { function test_03_02_RGCVII_funds_can_be_withdrawn() public {
uint256 initialBalance = raid_geld.daoToken().balanceOf(address(raid_geld)); uint256 initialBalance = raid_geld.daoToken().balanceOf(address(raid_geld));
// Switch to Player 1 and register it // Switch to Player 1 and register it
vm.startPrank(player1); vm.startPrank(player1);
registerPlayerWithDaoToken(); registerPlayerWithDaoToken();
@ -139,7 +148,7 @@ contract raid_geldTest is Test, Constants {
vm.startPrank(owner); vm.startPrank(owner);
raid_geld.withdraw_dao(); raid_geld.withdraw_dao();
uint256 newBalance = raid_geld.daoToken().balanceOf(address(owner)); uint256 newBalance = raid_geld.daoToken().balanceOf(address(owner));
uint256 newContractBalance = raid_geld.daoToken().balanceOf(address(raid_geld)); uint256 newContractBalance = raid_geld.daoToken().balanceOf(address(raid_geld));
// contract balance should be empty // contract balance should be empty
assertEq(newContractBalance, 0); assertEq(newContractBalance, 0);