diff --git a/contracts/TestCurrency.sol b/contracts/TestCurrency.sol index 1166df9..72b2538 100644 --- a/contracts/TestCurrency.sol +++ b/contracts/TestCurrency.sol @@ -2,37 +2,29 @@ pragma solidity ^0.8.0; import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; -import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol"; - -contract TestCurrency is ERC20, AccessControl { - bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); - bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE"); +contract TestCurrency is ERC20 { uint8 internal immutable _decimals; constructor( string memory name_, string memory symbol_, uint256 initialSupply, - uint8 decimals_, - address admin + uint8 decimals_ ) ERC20(name_, symbol_) { _decimals = decimals_; _mint(msg.sender, initialSupply); - _grantRole(DEFAULT_ADMIN_ROLE, admin); } function decimals() public view virtual override returns (uint8) { return _decimals; } - function mint(address recipient, uint256 amount) external onlyRole(MINTER_ROLE) { - // require(msg.sender == _owner, "Only owner can mint"); + function mint(address recipient, uint256 amount) public virtual { return _mint(recipient, amount); } - function burn(address recipient, uint256 amount) external onlyRole(BURNER_ROLE) { - // require(msg.sender == _owner, "Only owner can burn"); + function burn(address recipient, uint256 amount) public virtual { return _burn(recipient, amount); } } diff --git a/contracts/TestCurrencyAC.sol b/contracts/TestCurrencyAC.sol new file mode 100644 index 0000000..8f3b8b1 --- /dev/null +++ b/contracts/TestCurrencyAC.sol @@ -0,0 +1,28 @@ +//SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.0; + +import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol"; +import {TestCurrency} from "./TestCurrency.sol"; + +contract TestCurrencyAC is TestCurrency, AccessControl { + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE"); + + constructor( + string memory name_, + string memory symbol_, + uint256 initialSupply, + uint8 decimals_, + address admin + ) TestCurrency(name_, symbol_, initialSupply, decimals_) { + _grantRole(DEFAULT_ADMIN_ROLE, admin); + } + + function mint(address recipient, uint256 amount) public override onlyRole(MINTER_ROLE) { + super.mint(recipient, amount); + } + + function burn(address recipient, uint256 amount) public override onlyRole(BURNER_ROLE) { + super.burn(recipient, amount); + } +} diff --git a/contracts/TestERC4626.sol b/contracts/TestERC4626.sol index f48e598..7e9d86a 100644 --- a/contracts/TestERC4626.sol +++ b/contracts/TestERC4626.sol @@ -4,7 +4,11 @@ pragma solidity ^0.8.0; import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import {ERC4626} from "@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol"; import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; -import {TestCurrency} from "./TestCurrency.sol"; + +interface IMintable { + function mint(address recipient, uint256 amount) external; + function burn(address recipient, uint256 amount) external; +} contract TestERC4626 is ERC4626 { bool internal _broken; @@ -58,9 +62,9 @@ contract TestERC4626 is ERC4626 { */ function discreteEarning(int256 assets) external { if (assets > 0) { - TestCurrency(asset()).mint(address(this), uint256(assets)); + IMintable(asset()).mint(address(this), uint256(assets)); } else { - TestCurrency(asset()).burn(address(this), uint256(-assets)); + IMintable(asset()).burn(address(this), uint256(-assets)); } } diff --git a/js/test-utils.js b/js/test-utils.js index e8e82f1..557d0cc 100644 --- a/js/test-utils.js +++ b/js/test-utils.js @@ -8,7 +8,10 @@ const { Assertion } = require("chai"); const { ethers } = hre; async function initCurrency(options, initial_targets, initial_balances) { - const Currency = await ethers.getContractFactory(options.contractClass || "TestCurrency"); + const extraArgs = options.extraArgs || []; + const Currency = await ethers.getContractFactory( + options.contractClass || (extraArgs.length == 0 ? "TestCurrency" : "TestCurrencyAC") + ); let currency = await Currency.deploy( options.name || "Test Currency", options.symbol || "TEST", diff --git a/test/test-utils-functions.js b/test/test-utils-functions.js index 086fcab..7208886 100644 --- a/test/test-utils-functions.js +++ b/test/test-utils-functions.js @@ -14,7 +14,8 @@ describe("Utils library tests", function () { [, anon, admin, user1, user2] = await ethers.getSigners(); }); - async function deployFixture() { + async function deployACFixture() { + // Fixture with TestCurrencyAC (with access control) const currency = await initCurrency( { name: "Test USDC", symbol: "USDC", decimals: 6, initial_supply: _A(50000), extraArgs: [admin] }, [anon, user1, user2, admin], @@ -24,8 +25,19 @@ describe("Utils library tests", function () { return { currency }; } - it("Checks only MINTER_ROLE can mint", async () => { - const { currency } = await helpers.loadFixture(deployFixture); + async function deployFixture() { + // Fixture with TestCurrency (without access control) + const currency = await initCurrency( + { name: "Test USDC", symbol: "USDC", decimals: 6, initial_supply: _A(50000) }, + [anon, user1, user2, admin], + [_A("10000"), _A("2000"), _A("1000"), _A("20000")] + ); + + return { currency }; + } + + it("Checks only MINTER_ROLE can mint (TestCurrencyAC)", async () => { + const { currency } = await helpers.loadFixture(deployACFixture); expect(await currency.balanceOf(anon)).to.equal(_A(10000)); @@ -40,11 +52,22 @@ describe("Utils library tests", function () { expect(await currency.balanceOf(anon)).to.equal(_A(10100)); }); - it("Checks TestERC4626", async () => { + it("Checks anyone can mint and burnd (TestCurrency)", async () => { const { currency } = await helpers.loadFixture(deployFixture); expect(await currency.balanceOf(anon)).to.equal(_A(10000)); + await expect(currency.connect(admin).mint(anon, _A(100))).not.to.be.reverted; + expect(await currency.balanceOf(anon)).to.equal(_A(10100)); + await expect(currency.connect(admin).burn(anon, _A(150))).not.to.be.reverted; + expect(await currency.balanceOf(anon)).to.equal(_A(9950)); + }); + + it("Checks TestERC4626", async () => { + const { currency } = await helpers.loadFixture(deployACFixture); + + expect(await currency.balanceOf(anon)).to.equal(_A(10000)); + const TestERC4626 = await ethers.getContractFactory("TestERC4626"); const vault = await TestERC4626.deploy("Test", "TEST", currency);