NTU-FINTECH-HW1/hw1/test/NFinTech/NFinTech.t.sol
2024-03-21 12:00:51 +08:00

369 lines
9.6 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {Test, console2} from "forge-std/Test.sol";
import "../../src/NFinTech/NFinTech.sol";
/// @title NFinTech Test
/// @author Louis Tsai
/// @notice Do NOT modify this contract or you might get 0 points for the assingment.
contract NFinTechTest is Test {
NFinTech internal nft;
address internal Bob;
address internal Alice;
address internal user;
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
function setUp() public {
nft = new NFinTech("NFinTech", "NFT");
user = makeAddr("user");
Bob = makeAddr("Bob");
vm.prank(Bob);
nft.claim();
Alice = makeAddr("Alice");
vm.prank(Alice);
nft.claim();
}
/* Default Tests */
function test_name() public {
string memory name = nft.name();
assertEq(name, "NFinTech");
}
function test_symbol() public {
string memory symbol = nft.symbol();
assertEq(symbol, "NFT");
}
function test_balanceOf() public {
uint256 balance;
vm.prank(Bob);
balance = nft.balanceOf(Bob);
assertEq(balance, 1);
vm.prank(Alice);
balance = nft.balanceOf(Alice);
assertEq(balance, 1);
vm.expectRevert();
nft.balanceOf(address(0));
}
function test_ownerOf() public {
address owner;
owner = nft.ownerOf(0);
assertEq(owner, Bob);
owner = nft.ownerOf(1);
assertEq(owner, Alice);
vm.expectRevert();
nft.ownerOf(3);
}
/* PART 1: Complete approve related function -> 10 points */
function test_approve() public returns (bool) {
vm.prank(Bob);
vm.expectEmit(true, true, true, false);
emit Approval(Bob, Alice, 0);
nft.approve(Alice, 0);
address operator = nft.getApproved(0);
assertEq(operator, Alice);
return true;
}
function test_setApprovalForAll() public returns (bool) {
bool approved;
vm.prank(Bob);
vm.expectEmit(true, true, true, false);
emit ApprovalForAll(Bob, Alice, true);
nft.setApprovalForAll(Alice, true);
approved = nft.isApprovedForAll(Bob, Alice);
assertEq(approved, true);
vm.prank(Bob);
vm.expectEmit(true, true, true, false);
emit ApprovalForAll(Bob, Alice, false);
nft.setApprovalForAll(Alice, false);
approved = nft.isApprovedForAll(Bob, Alice);
assertEq(approved, false);
vm.prank(Bob);
vm.expectRevert();
nft.setApprovalForAll(address(0), true);
return true;
}
function test_approve_not_token_owner() public returns (bool) {
vm.prank(Bob);
vm.expectRevert();
nft.approve(Alice, 1);
return true;
}
function test_approve_then_setApprovalForAll() public returns (bool) {
vm.prank(Bob);
vm.expectEmit(true, true, true, false);
emit ApprovalForAll(Bob, Alice, true);
nft.setApprovalForAll(Alice, true);
vm.prank(Alice);
vm.expectEmit(true, true, true, false);
emit Approval(Bob, user, 0);
nft.approve(user, 0);
address operator = nft.getApproved(0);
assertEq(operator, user);
return true;
}
/* PART 2: Complete transferFrom function -> 10 points */
function test_transferFrom() public returns (bool) {
uint256 balance;
address owner;
vm.prank(Bob);
nft.approve(Alice, 0);
vm.prank(Alice);
vm.expectEmit(true, true, true, false);
emit Transfer(Bob, Alice, 0);
nft.transferFrom(Bob, Alice, 0);
balance = nft.balanceOf(Bob);
assertEq(balance, 0);
balance = nft.balanceOf(Alice);
assertEq(balance, 2);
owner = nft.ownerOf(0);
assertEq(owner, Alice);
owner = nft.ownerOf(1);
assertEq(owner, Alice);
return true;
}
function test_transferFrom_zero_address() public returns (bool) {
vm.prank(Bob);
nft.approve(Alice, 0);
vm.prank(Alice);
vm.expectRevert();
nft.transferFrom(Bob, address(0), 0);
return true;
}
function test_transferFrom_not_owner() public returns (bool) {
vm.prank(Bob);
nft.approve(Alice, 0);
vm.prank(Alice);
vm.expectRevert();
nft.transferFrom(Bob, address(0), 1);
return true;
}
/* PART 3: Complete safeTransferFrom function -> 10 points */
function test_safeTransferFrom_eoa() public returns (bool) {
uint256 balance;
address owner;
vm.prank(Bob);
nft.approve(Alice, 0);
vm.prank(Alice);
vm.expectEmit(true, true, true, false);
emit Transfer(Bob, Alice, 0);
nft.transferFrom(Bob, Alice, 0);
balance = nft.balanceOf(Bob);
assertEq(balance, 0);
balance = nft.balanceOf(Alice);
assertEq(balance, 2);
owner = nft.ownerOf(0);
assertEq(owner, Alice);
owner = nft.ownerOf(1);
assertEq(owner, Alice);
return true;
}
function test_safeTransferFrom_ca_success() public returns (bool) {
uint256 balance;
address owner;
MockSuccessReceiver receiver = new MockSuccessReceiver();
vm.prank(Bob);
nft.approve(Alice, 0);
vm.prank(Alice);
vm.expectEmit(true, true, true, false);
emit Transfer(Bob, address(receiver), 0);
nft.safeTransferFrom(Bob, address(receiver), 0);
balance = nft.balanceOf(Bob);
assertEq(balance, 0);
balance = nft.balanceOf(address(receiver));
assertEq(balance, 1);
owner = nft.ownerOf(0);
assertEq(owner, address(receiver));
owner = nft.ownerOf(1);
assertEq(owner, Alice);
return true;
}
function test_safeTransferFrom_ca_failure() public returns (bool) {
MockBadReceiver receiver = new MockBadReceiver();
vm.prank(Bob);
nft.approve(Alice, 0);
vm.prank(Alice);
vm.expectRevert();
nft.safeTransferFrom(Bob, address(receiver), 0);
return true;
}
/* PART 4: Mixed operation test */
function test_approve_then_transferFrom() public {
uint256 balance;
address owner;
vm.prank(Bob);
nft.approve(Alice, 0);
vm.prank(Alice);
vm.expectEmit(true, true, true, false);
emit Transfer(Bob, Alice, 0);
nft.transferFrom(Bob, Alice, 0);
balance = nft.balanceOf(Bob);
assertEq(balance, 0);
balance = nft.balanceOf(Alice);
assertEq(balance, 2);
owner = nft.ownerOf(0);
assertEq(owner, Alice);
owner = nft.ownerOf(1);
assertEq(owner, Alice);
}
function test_approve_user_then_transferFrom() public {
uint256 balance;
address owner;
vm.prank(Bob);
nft.approve(Alice, 0);
vm.prank(Alice);
vm.expectEmit(true, true, true, false);
emit Transfer(Bob, user, 0);
nft.transferFrom(Bob, user, 0);
balance = nft.balanceOf(Bob);
assertEq(balance, 0);
balance = nft.balanceOf(user);
assertEq(balance, 1);
owner = nft.ownerOf(0);
assertEq(owner, user);
owner = nft.ownerOf(1);
assertEq(owner, Alice);
}
function test_setApprovalForAll_then_transferFrom() public {
uint256 balance;
address owner;
vm.prank(Bob);
nft.setApprovalForAll(Alice, true);
vm.prank(Alice);
vm.expectEmit(true, true, true, false);
emit Transfer(Bob, user, 0);
nft.transferFrom(Bob, user, 0);
balance = nft.balanceOf(Bob);
assertEq(balance, 0);
balance = nft.balanceOf(user);
assertEq(balance, 1);
owner = nft.ownerOf(0);
assertEq(owner, user);
owner = nft.ownerOf(1);
assertEq(owner, Alice);
}
/* We use the following parts to calculate your score */
function test_check_approve_related_points() public {
test_approve();
test_setApprovalForAll();
test_approve_not_token_owner();
test_approve_then_setApprovalForAll();
console2.log("Get 10 points");
}
function test_check_transferFrom_points() public {
test_transferFrom();
setUp();
test_transferFrom_zero_address();
setUp();
test_transferFrom_not_owner();
console2.log("Get 10 points");
}
function test_check_safeTransferFrom_points() public {
test_safeTransferFrom_eoa();
setUp();
test_safeTransferFrom_ca_failure();
setUp();
test_safeTransferFrom_ca_success();
console2.log("Get 10 points");
}
function test_check_mix_operation() public {
test_approve_then_transferFrom();
setUp();
test_approve_user_then_transferFrom();
setUp();
test_setApprovalForAll_then_transferFrom();
console2.log("Get 10 points");
}
}
contract MockSuccessReceiver is IERC721TokenReceiver {
function onERC721Received(address, address, uint256, bytes calldata) external returns (bytes4) {
return IERC721TokenReceiver.onERC721Received.selector;
}
}
contract MockBadReceiver is IERC721TokenReceiver {
function onERC721Received(address, address, uint256, bytes calldata) external returns (bytes4) {
return bytes4(keccak256("approve(address,uint256)"));
}
}