1+ // SPDX-License-Identifier: UNLICENSED
2+ pragma solidity ^ 0.8.13 ;
3+
4+ import {Test, console} from "forge-std/Test.sol " ;
5+ import {IERC20Errors } from "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol " ;
6+ import {Ownable} from "openzeppelin-contracts/contracts/access/Ownable.sol " ;
7+ import {CrosschainNubilaNetwork} from "../src/CrosschainNubilaNetwork.sol " ;
8+
9+ contract CrosschainNubilaNetworkTest is Test {
10+ CrosschainNubilaNetwork public token;
11+ address public owner;
12+ address public minter1;
13+ address public minter2;
14+ address public user1;
15+ address public user2;
16+
17+ event MinterAdded (address indexed account );
18+ event MinterRemoved (address indexed account );
19+ event CrosschainMinted (address indexed receiver , uint256 amount );
20+ event CrosschainBurned (address indexed sender , address indexed receiver , uint256 amount );
21+
22+ function setUp () public {
23+ owner = makeAddr ("owner " );
24+ minter1 = makeAddr ("minter1 " );
25+ minter2 = makeAddr ("minter2 " );
26+ user1 = makeAddr ("user1 " );
27+ user2 = makeAddr ("user2 " );
28+
29+ vm.startPrank (owner);
30+ token = new CrosschainNubilaNetwork ();
31+ vm.stopPrank ();
32+ }
33+
34+ function testInitialState () public view {
35+ assertEq (token.name (), "Nubila Network " );
36+ assertEq (token.symbol (), "NB " );
37+ assertEq (token.totalSupply (), 0 );
38+ assertEq (token.owner (), owner);
39+ assertFalse (token.isMinter (owner));
40+ assertFalse (token.isMinter (minter1));
41+ }
42+
43+ function testAddMinter () public {
44+ vm.expectEmit (true , true , true , true );
45+ emit MinterAdded (minter1);
46+ vm.startPrank (owner);
47+ token.addMinter (minter1);
48+ assertTrue (token.isMinter (minter1));
49+ vm.expectRevert (abi.encodeWithSelector (CrosschainNubilaNetwork.ErrAlreadyMinter.selector , minter1));
50+ token.addMinter (minter1); // Should revert if already a minter
51+ vm.expectRevert (CrosschainNubilaNetwork.ErrZeroAddress.selector );
52+ token.addMinter (address (0 )); // Should revert for zero address
53+ vm.stopPrank ();
54+
55+ vm.expectRevert (abi.encodeWithSelector (Ownable.OwnableUnauthorizedAccount.selector , user1));
56+ vm.prank (user1);
57+ token.addMinter (minter2); // Only owner can add minters
58+ }
59+
60+ function testRemoveMinter () public {
61+ vm.startPrank (owner);
62+ token.addMinter (minter1);
63+ assertTrue (token.isMinter (minter1));
64+
65+ token.removeMinter (minter1);
66+ assertFalse (token.isMinter (minter1));
67+ vm.expectRevert (abi.encodeWithSelector (CrosschainNubilaNetwork.ErrNotMinter.selector , minter1));
68+ token.removeMinter (minter1); // Should revert if not a minter
69+ vm.stopPrank ();
70+
71+ vm.expectRevert (abi.encodeWithSelector (Ownable.OwnableUnauthorizedAccount.selector , user1));
72+ vm.prank (user1);
73+ token.removeMinter (minter2); // Only owner can remove minters
74+ }
75+
76+ function testMint () public {
77+ vm.startPrank (owner);
78+ token.addMinter (minter1);
79+ vm.stopPrank ();
80+
81+ vm.expectEmit (true , true , true , true );
82+ emit CrosschainMinted (user1, 100 ether);
83+ vm.prank (minter1);
84+ token.crosschainMint (user1, 100 ether);
85+ assertEq (token.balanceOf (user1), 100 ether);
86+ assertEq (token.totalSupply (), 100 ether);
87+
88+ vm.expectRevert (abi.encodeWithSelector (CrosschainNubilaNetwork.ErrNotAuthorizedMinter.selector , user2));
89+ vm.prank (user2);
90+ token.crosschainMint (user2, 50 ether); // Only minters can mint
91+ }
92+
93+ function testCrosschainBurn () public {
94+ vm.startPrank (owner);
95+ token.addMinter (minter1);
96+ vm.stopPrank ();
97+
98+ vm.expectEmit (true , true , true , true );
99+ emit CrosschainMinted (user1, 200 ether);
100+ vm.prank (minter1);
101+ token.crosschainMint (user1, 200 ether);
102+ assertEq (token.balanceOf (user1), 200 ether);
103+
104+ vm.startPrank (user1);
105+ vm.expectEmit (true , true , true , true );
106+ emit CrosschainBurned (user1, user2, 50 ether);
107+ token.crosschainBurn (50 ether, user2);
108+ assertEq (token.balanceOf (user1), 150 ether);
109+ assertEq (token.balanceOf (user2), 0 ); // Bridged tokens are burned, not transferred to receiver
110+ assertEq (token.totalSupply (), 150 ether);
111+ vm.expectEmit (true , true , true , true );
112+ emit CrosschainBurned (user1, user1, 25 ether);
113+ token.crosschainBurn (25 ether, address (0 )); // Test with zero address receiver, should burn from sender
114+ assertEq (token.balanceOf (user1), 125 ether); // This line is duplicated, but it's fine for the test
115+ assertEq (token.totalSupply (), 125 ether);
116+
117+ vm.expectRevert (abi.encodeWithSelector (IERC20Errors .ERC20InsufficientBalance .selector , user1, 125 ether, 200 ether));
118+ token.crosschainBurn (200 ether, user2); // Should revert if amount exceeds balance
119+ vm.stopPrank ();
120+ }
121+ }
0 commit comments