Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added SimpleTreasury contract #21

Merged
merged 3 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Repository holding the contracts made by Gnosis Labs team.
| OmenAgentResultMapping | Maps prediction results to markets on Omen 2.0 | [0xbe1F6944496923683ca849fc0cC93fD10523cB83](https://gnosisscan.io/address/0x260E1077dEA98e738324A6cEfB0EE9A272eD471a#code) | [omen-agentresultmapping](https://thegraph.com/studio/subgraph/omen-agentresultmapping/) |
| Agent NFT | Agent NFTs that control mechs for NFT game | [0x0D7C0Bd4169D090038c6F41CFd066958fe7619D0](https://gnosisscan.io/address/0x0D7C0Bd4169D090038c6F41CFd066958fe7619D0#code) | |
| Agent communication contract | Simple contract storing message queue for each agent | [0xd422e0059ed819e8d792af936da206878188e34f](https://gnosisscan.io/address/0xd422e0059ed819e8d792af936da206878188e34f#code) | |
| Simple Treasury contract | Contract for storing the NFT agent game treasury | [0x624ad0db52e6b18afb4d36b8e79d0c2a74f3fc8a](https://gnosisscan.io/address/0x624ad0db52e6b18afb4d36b8e79d0c2a74f3fc8a#code) | |

## Set up contracts development

Expand Down
38 changes: 38 additions & 0 deletions src/NFT/SimpleTreasury.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract SimpleTreasury is Ownable {
IERC721 public nftContract;
uint256 public requiredNFTBalance = 3;

function setRequiredNFTBalance(uint256 _newBalance) external onlyOwner {
requiredNFTBalance = _newBalance;
}

event WithdrawnByNFTHolder(address indexed holder, uint256 amount);

constructor(address _nftContract) Ownable(msg.sender) {
require(_nftContract != address(0), "Invalid NFT contract address");
nftContract = IERC721(_nftContract);
}

// Function to receive xDAI
receive() external payable {}

// Withdraw function that checks NFT balance
function withdraw() external {
uint256 nftBalance = nftContract.balanceOf(msg.sender);
require(nftBalance >= requiredNFTBalance, "Insufficient NFT balance");

uint256 balance = address(this).balance;
require(balance > 0, "No funds to withdraw");

(bool success,) = payable(msg.sender).call{value: balance}("");
require(success, "Transfer failed");

emit WithdrawnByNFTHolder(msg.sender, balance);
}
}
84 changes: 84 additions & 0 deletions test/SimpleTreasury.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "forge-std/Test.sol";
import "../src/NFT/SimpleTreasury.sol";
import "./mocks/MockNFT.sol";

contract SimpleTreasuryTest is Test {
SimpleTreasury public treasury;
MockNFT public nft;

address public owner;
address public user;
uint256 public constant INITIAL_BALANCE = 10 ether;

function setUp() public {
owner = makeAddr("owner");
user = makeAddr("user");

vm.startPrank(owner);
nft = new MockNFT();
treasury = new SimpleTreasury(address(nft));
vm.stopPrank();

// Fund treasury
vm.deal(address(treasury), INITIAL_BALANCE);
}

function test_WithdrawWithSufficientNFTs() public {
// Mint 3 NFTs to user
vm.startPrank(owner);
for (uint256 i = 0; i < treasury.requiredNFTBalance(); ++i) {
nft.mint(user);
}
vm.stopPrank();

// Try to withdraw as user
vm.prank(user);
uint256 userBalanceBefore = user.balance;
treasury.withdraw();

assertEq(user.balance - userBalanceBefore, INITIAL_BALANCE, "User should receive all treasury balance");
assertEq(address(treasury).balance, 0, "Treasury should be empty");
}

function test_WithdrawWithInsufficientNFTs() public {
// Mint only 2 NFTs to user
vm.startPrank(owner);
nft.mint(user);
nft.mint(user);
vm.stopPrank();

// Try to withdraw as user
vm.prank(user);
vm.expectRevert("Insufficient NFT balance");
treasury.withdraw();
}

function test_SetRequiredNFTBalance() public {
uint256 newRequiredBalance = 5;

vm.prank(owner);
treasury.setRequiredNFTBalance(newRequiredBalance);

assertEq(treasury.requiredNFTBalance(), newRequiredBalance, "Required NFT balance should be updated");
}

function test_SetRequiredNFTBalanceNotOwner() public {
vm.prank(user);
vm.expectRevert(abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, address(user)));
treasury.setRequiredNFTBalance(5);
}

function test_ReceiveEther() public {
uint256 amount = 1 ether;
vm.deal(user, amount);

vm.prank(user);
(bool success,) = address(treasury).call{value: amount}("");

assertTrue(success, "Should accept ether");
assertEq(address(treasury).balance, INITIAL_BALANCE + amount, "Treasury balance should increase");
}
}
16 changes: 16 additions & 0 deletions test/mocks/MockNFT.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";

contract MockNFT is ERC721 {
uint256 private _tokenIdCounter;

constructor() ERC721("MockNFT", "MNFT") {}

function mint(address to) external returns (uint256) {
uint256 tokenId = _tokenIdCounter++;
_mint(to, tokenId);
return tokenId;
}
}
Loading