Skip to content

Commit 22a4f35

Browse files
authored
Merge pull request #3 from KoxyG/review
2 parents 2a39c03 + bad2aea commit 22a4f35

11 files changed

+870
-11
lines changed

contracts/XXXToken.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ contract XXXToken is Initializable,
5353
* @dev Initializes the contract replacing the constructor for upgradeable contracts
5454
* Sets up roles and configures token parameters
5555
*/
56-
function initialize() public initializer {
56+
function initialize() external initializer {
5757
// Initialize ERC20 with name and symbol
5858
__ERC20_init("XXX", "XXX");
5959

contracts/XXXTokenVault.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ contract TokenVault is Initializable,
7979
* @dev Initializes the contract replacing the constructor for upgradeable contracts
8080
* @param _ttnToken Address of the XXXToken contract
8181
*/
82-
function initialize(address _ttnToken) public initializer {
82+
function initialize(address _ttnToken) external initializer {
8383
if (_ttnToken == address(0)) revert ZeroAddress("token");
8484
__AccessControl_init();
8585
__UUPSUpgradeable_init();

contracts/XXXVestingManager.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ contract VestingManager is Initializable,
112112
* @param _ttnToken Address of the XXXToken contract
113113
* @param _tokenVault Address of the TokenVault contract
114114
*/
115-
function initialize(address _ttnToken, address _tokenVault) public initializer {
115+
function initialize(address _ttnToken, address _tokenVault) external initializer {
116116
if (_ttnToken == address(0)) revert ZeroAddress("token");
117117
if (_tokenVault == address(0)) revert ZeroAddress("vault");
118118
__AccessControl_init();
@@ -200,7 +200,7 @@ contract VestingManager is Initializable,
200200
* @param scheduleId ID of the vesting schedule
201201
* @return The amount of tokens that can be released
202202
*/
203-
function computeReleasableAmount(uint256 scheduleId) public view returns (uint256) {
203+
function computeReleasableAmount(uint256 scheduleId) internal view returns (uint256) {
204204
if (scheduleId == 0 || scheduleId > _vestingScheduleCounter) revert InvalidScheduleId();
205205

206206
VestingSchedule storage schedule = vestingSchedules[scheduleId];

contracts/upgrades/XXXTokenV2.sol

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,22 @@ contract XXXTokenV2 is XXXToken {
2424
/// @notice The version number of this contract implementation
2525
uint256 public version;
2626

27+
28+
2729
/**
28-
* @dev Initializes the V2 contract with a version number.
29-
* This function is called after the upgrade to set up the new state variables.
30-
* The reinitializer modifier ensures this can only be called once after the upgrade.
30+
* @dev Initializes V2 functionality
31+
* This is called during the upgrade process
32+
* @custom:oz-upgrades-validate-as-initializer
3133
*/
32-
function initializeV2() public reinitializer(2) {
34+
function initializeV2() external reinitializer(2) {
35+
// Initialize parent contracts
36+
__ERC20_init("XXX Token", "XXX");
37+
__ERC20Capped_init(1000000000 * 10**18); // 1 billion tokens
38+
__Ownable_init(msg.sender);
39+
__AccessControl_init();
40+
__Pausable_init();
41+
__UUPSUpgradeable_init();
42+
3343
version = 2;
3444
}
3545
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// SPDX-License-Identifier: MIT
2+
/**
3+
* @title XXXTokenVaultV2
4+
* @dev TESTING PURPOSES ONLY - DO NOT USE IN PRODUCTION
5+
* This is a test implementation of TokenVault V2 to demonstrate upgrade functionality.
6+
* It adds version tracking and additional allocation tracking for testing purposes.
7+
* This contract should not be used in production environments.
8+
*/
9+
10+
pragma solidity ^0.8.24;
11+
12+
import "../XXXTokenVault.sol";
13+
import "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
14+
import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
15+
import "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
16+
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
17+
18+
contract XXXTokenVaultV2 is TokenVault {
19+
// Version tracking for upgrade testing
20+
uint256 public version;
21+
// Additional counter for V2 allocations
22+
uint256 public totalAllocatedV2;
23+
24+
25+
26+
27+
/**
28+
* @dev Initializes V2 functionality
29+
* This is called during the upgrade process
30+
* @custom:oz-upgrades-validate-as-initializer
31+
*/
32+
function initializeV2() external reinitializer(2) {
33+
// Initialize parent contracts
34+
__ReentrancyGuard_init();
35+
__AccessControl_init();
36+
__Pausable_init();
37+
__UUPSUpgradeable_init();
38+
39+
40+
41+
version = 2;
42+
}
43+
44+
/**
45+
* @dev Returns the current version number
46+
* @return The version number (2 for V2)
47+
*/
48+
function getVersion() external view returns (uint256) {
49+
return version;
50+
}
51+
52+
/**
53+
* @dev Returns the total amount allocated through V2
54+
* @return The total amount allocated using V2 functions
55+
*/
56+
function getTotalAllocatedV2() external view returns (uint256) {
57+
return totalAllocatedV2;
58+
}
59+
60+
/**
61+
* @dev Creates a new allocation and tracks it in V2 counter
62+
* @param beneficiary Address to receive allocated tokens
63+
* @param amount Total amount of tokens to allocate
64+
* @return allocationId Unique identifier for the allocation
65+
*/
66+
function createAllocationV2(address beneficiary, uint256 amount) external onlyRole(DEFAULT_ADMIN_ROLE) returns (uint256) {
67+
// Input validation
68+
require(beneficiary != address(0), "Invalid beneficiary");
69+
require(amount > 0, "Amount must be greater than 0");
70+
71+
// Track V2 allocation
72+
totalAllocatedV2 += amount;
73+
74+
// Call base contract's allocation function
75+
return this.createAllocation(beneficiary, amount);
76+
}
77+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// SPDX-License-Identifier: MIT
2+
/**
3+
* @title XXXVestingManagerV2
4+
* @dev TESTING PURPOSES ONLY - DO NOT USE IN PRODUCTION
5+
* This is a test implementation of VestingManager V2 to demonstrate upgrade functionality.
6+
* It adds version tracking and additional vesting tracking for testing purposes.
7+
* This contract should not be used in production environments.
8+
*/
9+
10+
pragma solidity ^0.8.24;
11+
12+
import "../XXXVestingManager.sol";
13+
import "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
14+
import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
15+
import "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
16+
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
17+
18+
19+
contract XXXVestingManagerV2 is VestingManager {
20+
// Version tracking for upgrade testing
21+
uint256 public version;
22+
// Additional counter for V2 vesting schedules
23+
uint256 public totalVestedV2;
24+
25+
/**
26+
* @dev Initializes V2 functionality
27+
* This is called during the upgrade process
28+
* @custom:oz-upgrades-validate-as-initializer
29+
*/
30+
function initializeV2() external reinitializer(2) {
31+
// Initialize parent contracts
32+
__ReentrancyGuard_init();
33+
__AccessControl_init();
34+
__Pausable_init();
35+
__UUPSUpgradeable_init();
36+
37+
// Set version to 2
38+
version = 2;
39+
}
40+
41+
/**
42+
* @dev Returns the current version number
43+
* @return The version number (2 for V2)
44+
*/
45+
function getVersion() external view returns (uint256) {
46+
return version;
47+
}
48+
49+
/**
50+
* @dev Returns the total amount vested through V2
51+
* @return The total amount vested using V2 functions
52+
*/
53+
function getTotalVestedV2() external view returns (uint256) {
54+
return totalVestedV2;
55+
}
56+
57+
/**
58+
* @dev Creates a new vesting schedule and tracks it in V2 counter
59+
* @param beneficiary Address to receive vested tokens
60+
* @param amount Total amount of tokens to vest
61+
* @param startTime Unix timestamp when vesting begins
62+
* @param cliffDuration Duration in seconds until first tokens unlock
63+
* @param duration Total duration of vesting in seconds
64+
* @param slicePeriodSeconds Duration of each vesting slice in seconds
65+
* @return scheduleId Unique identifier for the vesting schedule
66+
*/
67+
function createVestingScheduleV2(
68+
address beneficiary,
69+
uint256 amount,
70+
uint256 startTime,
71+
uint256 cliffDuration,
72+
uint256 duration,
73+
uint256 slicePeriodSeconds
74+
) external onlyRole(VESTING_ADMIN_ROLE) returns (uint256) {
75+
// Input validation
76+
require(beneficiary != address(0), "Invalid beneficiary");
77+
require(amount > 0, "Amount must be greater than 0");
78+
79+
// Track V2 vesting
80+
totalVestedV2 += amount;
81+
82+
// Call base contract's vesting schedule function
83+
return this.createVestingSchedule(
84+
beneficiary,
85+
amount,
86+
startTime,
87+
cliffDuration,
88+
duration,
89+
slicePeriodSeconds
90+
);
91+
}
92+
}

test/TokenVault.test.ts

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ describe("TokenVault", function () {
7676
});
7777
});
7878

79-
describe("Vesting Manager", function () {
79+
describe("Set Vesting Manager", function () {
8080
it("Should allow admin to set vesting manager", async function () {
8181
await vault.setVestingManager(vestingManager.address);
8282
expect(await vault.vestingManager()).to.equal(vestingManager.address);
@@ -236,4 +236,45 @@ describe("TokenVault", function () {
236236
).to.be.revertedWithCustomError(vault, "EnforcedPause");
237237
});
238238
});
239+
240+
describe("Token Minting", function () {
241+
it("Should allow minting up to max supply", async function () {
242+
const maxSupply = await token.MAX_SUPPLY();
243+
const halfSupply = maxSupply / 2n;
244+
245+
// Mint half the supply
246+
await vault.connect(owner).createAllocation(beneficiary1.address, halfSupply);
247+
await vault.connect(owner).createAllocation(beneficiary2.address, halfSupply);
248+
249+
// Verify total supply
250+
expect(await token.totalSupply()).to.equal(maxSupply);
251+
});
252+
253+
it("Should not allow minting beyond max supply", async function () {
254+
const maxSupply = await token.MAX_SUPPLY();
255+
const halfSupply = maxSupply / 2n;
256+
257+
// Mint half the supply
258+
await vault.connect(owner).createAllocation(beneficiary1.address, halfSupply);
259+
await vault.connect(owner).createAllocation(beneficiary2.address, halfSupply);
260+
261+
// Try to mint one more token
262+
await expect(
263+
vault.connect(owner).createAllocation(beneficiary1.address, 1)
264+
).to.be.revertedWithCustomError(token, "MaxSupplyExceeded");
265+
});
266+
267+
it("Should not allow minting that would exceed max supply", async function () {
268+
const maxSupply = await token.MAX_SUPPLY();
269+
const halfSupply = maxSupply / 2n;
270+
271+
// Mint half the supply
272+
await vault.connect(owner).createAllocation(beneficiary1.address, halfSupply);
273+
274+
// Try to mint more than the remaining supply
275+
await expect(
276+
vault.connect(owner).createAllocation(beneficiary2.address, halfSupply + 1n)
277+
).to.be.revertedWithCustomError(token, "MaxSupplyExceeded");
278+
});
279+
});
239280
});

0 commit comments

Comments
 (0)