Skip to content

Commit

Permalink
Add TWAB tests
Browse files Browse the repository at this point in the history
  • Loading branch information
trmid committed Oct 9, 2024
1 parent fab2a05 commit 418f727
Show file tree
Hide file tree
Showing 4 changed files with 277 additions and 4 deletions.
7 changes: 3 additions & 4 deletions src/WorldIdVerifiedPrizeVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@ contract WorldIdVerifiedPrizeVault is Ownable, ERC4626, Claimable {
/// @param account The account receiving the deposit
/// @param currentBalance The current account balance
/// @param newBalance The new balance addition
/// @param accountDepositLimit The account deposit limit
/// @param remainingDepositLimit The account's remaining deposit limit
error DepositLimitExceeded(
address account,
uint256 currentBalance,
uint256 newBalance,
uint256 accountDepositLimit
uint256 remainingDepositLimit
);

////////////////////////////////////////////////////////////////////////////////
Expand All @@ -58,7 +58,7 @@ contract WorldIdVerifiedPrizeVault is Ownable, ERC4626, Claimable {
/// @param _depositAmount The amount that the balance is being increased by
modifier enforceDepositLimit(address _account, uint256 _depositAmount) {
if (_depositAmount > maxDeposit(_account)) {
revert DepositLimitExceeded(_account, balanceOf(_account), _depositAmount, accountDepositLimit);
revert DepositLimitExceeded(_account, balanceOf(_account), _depositAmount, maxDeposit(_account));
}
_;
}
Expand All @@ -84,7 +84,6 @@ contract WorldIdVerifiedPrizeVault is Ownable, ERC4626, Claimable {
address owner_,
uint256 accountDepositLimit_
) ERC20(name_, symbol_) ERC4626(IERC20(prizePool_.prizeToken())) Ownable(owner_) Claimable(prizePool_, claimer_) {
assert(address(twabController) != address(0));
assert(address(worldIdAddressBook_) != address(0));
twabController = prizePool_.twabController();
worldIdAddressBook = worldIdAddressBook_;
Expand Down
225 changes: 225 additions & 0 deletions test/WorldIdVerifiedPrizeVault.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import { Test, stdError } from "forge-std/Test.sol";

import { WorldIdVerifiedPrizeVaultWrapper } from "./contracts/WorldIdVerifiedPrizeVaultWrapper.sol";
import { TwabController } from "pt-v5-twab-controller/TwabController.sol";
import { PrizePool, ConstructorParams } from "pt-v5-prize-pool/PrizePool.sol";
import { ERC20Mock } from "../lib/pt-v5-vault/lib/openzeppelin-contracts/contracts/mocks/ERC20Mock.sol";
import { MockWorldIdAddressBook } from "./contracts/MockWorldIdAddressBook.sol";

contract WorldIdVerifiedPrizeVaultTest is Test {

// Events
event Transfer(address indexed from, address indexed to, uint256 amount);

WorldIdVerifiedPrizeVaultWrapper public worldVault;

MockWorldIdAddressBook public worldIdAddressBook;
TwabController public twabController;
PrizePool public prizePool;
ERC20Mock public prizeToken;

uint32 periodLength = 1 days;
uint32 periodOffset = 0;

address alice;
address bob;
address claimer;
address owner;

function setUp() public {
alice = makeAddr("alice");
bob = makeAddr("bob");
claimer = makeAddr("claimer");
owner = makeAddr("owner");

worldIdAddressBook = new MockWorldIdAddressBook();
vm.startPrank(alice);
worldIdAddressBook.setAccountVerification(block.timestamp + 91 days);
vm.stopPrank();
vm.startPrank(bob);
worldIdAddressBook.setAccountVerification(block.timestamp + 91 days);
vm.stopPrank();

prizeToken = new ERC20Mock();
twabController = new TwabController(periodLength, periodOffset);
prizePool = new PrizePool(
ConstructorParams(
prizeToken,
twabController,
address(this),
0.5e18,
1 days,
uint48((block.timestamp / periodLength + 1) * periodLength),
91,
4,
100,
4,
30,
60
)
);
worldVault = new WorldIdVerifiedPrizeVaultWrapper(
"World Vault",
"przWLD",
prizePool,
worldIdAddressBook,
claimer,
owner,
100e18 // account deposit limit
);
}

/* ============ Constructor ============ */

function testConstructor_twabControllerSet() public {
assertEq(address(worldVault.twabController()), address(twabController));
}

function testConstructor_nameSet() public {
assertEq(worldVault.name(), "World Vault");
}

function testConstructor_symbolSet() public {
assertEq(worldVault.symbol(), "przWLD");
}

/* ============ balanceOf ============ */

function testBalanceOf_startingBalanceZero() public {
assertEq(worldVault.balanceOf(address(this)), 0);
}

/* ============ totalSupply ============ */

function testBalanceOf_startingSupplyZero() public {
assertEq(worldVault.totalSupply(), 0);
}

/* ============ mint ============ */

function testMint_updatesBalance() public {
assertEq(worldVault.balanceOf(alice), 0);
worldVault.mint(alice, 1e18);
assertEq(worldVault.balanceOf(alice), 1e18);
worldVault.mint(alice, 2e18 + 1);
assertEq(worldVault.balanceOf(alice), 3e18 + 1);
}

function testMint_updatesSupply() public {
assertEq(worldVault.totalSupply(), 0);
worldVault.mint(alice, 1e18);
assertEq(worldVault.totalSupply(), 1e18);
worldVault.mint(bob, 1);
assertEq(worldVault.totalSupply(), 1e18 + 1);
}

function testMint_emitsTransfer() public {
vm.expectEmit();
emit Transfer(address(0), alice, 1);
worldVault.mint(alice, 1);
}

/* ============ burn ============ */

function testBurn_updatesBalance() public {
assertEq(worldVault.balanceOf(alice), 0);
worldVault.mint(alice, 1e18);
assertEq(worldVault.balanceOf(alice), 1e18);
worldVault.burn(alice, 1);
assertEq(worldVault.balanceOf(alice), 1e18 - 1);
}

function testBurn_updatesSupply() public {
assertEq(worldVault.totalSupply(), 0);
worldVault.mint(alice, 1e18);
worldVault.mint(bob, 1e18);
assertEq(worldVault.totalSupply(), 2e18);
worldVault.burn(bob, 1e18 - 1);
assertEq(worldVault.totalSupply(), 1e18 + 1);
}

function testBurn_emitsTransfer() public {
worldVault.mint(alice, 1);
vm.expectEmit();
emit Transfer(alice, address(0), 1);
worldVault.burn(alice, 1);
}

/* ============ transfer ============ */

function testTransfer_updatesBalances() public {
worldVault.mint(alice, 1e18);
assertEq(worldVault.balanceOf(alice), 1e18);
assertEq(worldVault.balanceOf(bob), 0);
vm.startPrank(alice);
worldVault.transfer(bob, 4e17);
vm.stopPrank();
assertEq(worldVault.balanceOf(alice), 6e17);
assertEq(worldVault.balanceOf(bob), 4e17);
}

function testTransfer_noChangeToSupply() public {
worldVault.mint(alice, 1e18);
worldVault.mint(bob, 1e18);
assertEq(worldVault.totalSupply(), 2e18);
vm.startPrank(alice);
worldVault.transfer(bob, 5e17);
vm.stopPrank();
assertEq(worldVault.totalSupply(), 2e18);
}

function testTransfer_emitsTransfer() public {
worldVault.mint(alice, 1);
vm.expectEmit();
emit Transfer(alice, bob, 1);
vm.startPrank(alice);
worldVault.transfer(bob, 1);
vm.stopPrank();
}

/* ============ uint96 limiter ============ */

function testLimitUint96() public {
vm.startPrank(owner);
worldVault.setAccountDepositLimit(type(uint256).max);
vm.stopPrank();

assertEq(worldVault.balanceOf(alice), 0);
assertEq(worldVault.totalSupply(), 0);

worldVault.mint(alice, type(uint96).max);

assertEq(worldVault.balanceOf(alice), type(uint96).max);
assertEq(worldVault.totalSupply(), type(uint96).max);

vm.expectRevert(stdError.arithmeticError);
worldVault.mint(alice, 1);

vm.startPrank(alice);
worldVault.transfer(bob, type(uint96).max);
vm.stopPrank();

assertEq(worldVault.balanceOf(alice), 0);
assertEq(worldVault.balanceOf(bob), type(uint96).max);
assertEq(worldVault.totalSupply(), type(uint96).max);

vm.startPrank(bob);
worldVault.transfer(alice, type(uint96).max / 2);
vm.stopPrank();

assertEq(worldVault.balanceOf(alice), type(uint96).max / 2);
assertEq(worldVault.balanceOf(bob), type(uint96).max / 2 + 1);
assertEq(worldVault.totalSupply(), type(uint96).max);

worldVault.burn(alice, type(uint96).max / 2);
worldVault.burn(bob, type(uint96).max / 2 + 1);

assertEq(worldVault.balanceOf(alice), 0);
assertEq(worldVault.balanceOf(bob), 0);
assertEq(worldVault.totalSupply(), 0);
}

}
15 changes: 15 additions & 0 deletions test/contracts/MockWorldIdAddressBook.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import { IWorldIdAddressBook } from "../../src/interfaces/IWorldIdAddressBook.sol";

/// @notice Mock address book that lets addresses "verify" their account by calling `setAccountVerification`.
contract MockWorldIdAddressBook is IWorldIdAddressBook {

mapping(address => uint256) public addressVerifiedUntil;

function setAccountVerification(uint256 verifiedUntil) external {
addressVerifiedUntil[msg.sender] = verifiedUntil;
}

}
34 changes: 34 additions & 0 deletions test/contracts/WorldIdVerifiedPrizeVaultWrapper.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import { WorldIdVerifiedPrizeVault, PrizePool, IWorldIdAddressBook } from "../../src/WorldIdVerifiedPrizeVault.sol";

contract WorldIdVerifiedPrizeVaultWrapper is WorldIdVerifiedPrizeVault {

constructor(
string memory name_,
string memory symbol_,
PrizePool prizePool_,
IWorldIdAddressBook worldIdAddressBook_,
address claimer_,
address owner_,
uint256 accountDepositLimit_
) WorldIdVerifiedPrizeVault(
name_,
symbol_,
prizePool_,
worldIdAddressBook_,
claimer_,
owner_,
accountDepositLimit_
) {}

function mint(address _receiver, uint256 _amount) public {
_mint(_receiver, _amount);
}

function burn(address _owner, uint256 _amount) public {
_burn(_owner, _amount);
}

}

0 comments on commit 418f727

Please sign in to comment.