diff --git a/src/ERC20TokenV2.sol b/src/ERC20TokenV2.sol index 9d4330f..9f25ab6 100644 --- a/src/ERC20TokenV2.sol +++ b/src/ERC20TokenV2.sol @@ -32,6 +32,7 @@ contract ERC20TokenV2 is } function initialize( + address initialOwner, string memory _symbol, uint _totalSupply, uint _perMint, @@ -41,7 +42,7 @@ contract ERC20TokenV2 is __ERC20_init("ERC20Token", _symbol); __ERC20Burnable_init(); __ERC20Pausable_init(); - __Ownable_init(msg.sender); + __Ownable_init(initialOwner); __ERC20Permit_init("ERC20Token"); __ERC20Votes_init(); __UUPSUpgradeable_init(); diff --git a/src/TokenFactoryV2.sol b/src/TokenFactoryV2.sol index ef79965..35a1387 100644 --- a/src/TokenFactoryV2.sol +++ b/src/TokenFactoryV2.sol @@ -5,11 +5,16 @@ import "@openzeppelin/contracts/proxy/Clones.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; +import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; +import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol"; +import "./ERC20Token.sol"; import "./ERC20TokenV2.sol"; contract TokenFactoryV2 is Initializable, OwnableUpgradeable, UUPSUpgradeable { - address public implementation; + ERC20Token myToken; + ERC1967Proxy proxy; address[] public deployedTokens; + address public implementation; mapping(address => uint) public tokenPrices; /// @custom:oz-upgrades-unsafe-allow constructor @@ -23,6 +28,11 @@ contract TokenFactoryV2 is Initializable, OwnableUpgradeable, UUPSUpgradeable { ) public initializer { __Ownable_init(initialOwner); __UUPSUpgradeable_init(); + require( + _implementation != address(0), + "Invalid implementation address" + ); + implementation = _implementation; } @@ -43,12 +53,19 @@ contract TokenFactoryV2 is Initializable, OwnableUpgradeable, UUPSUpgradeable { uint perMint, uint price ) public onlyOwner { + console.log("deployInscription msg.sender, address:", msg.sender); // 使用 Clones 库创建最小代理合约实例 - address proxy = Clones.clone(implementation); - ERC20TokenV2(proxy).initialize(symbol, totalSupply, perMint, price); + address proxyInstance = Clones.clone(implementation); + ERC20TokenV2(proxyInstance).initialize( + msg.sender, + symbol, + totalSupply, + perMint, + price + ); - deployedTokens.push(proxy); - tokenPrices[proxy] = price; + deployedTokens.push(proxyInstance); + tokenPrices[proxyInstance] = price; } /** @@ -61,4 +78,8 @@ contract TokenFactoryV2 is Initializable, OwnableUpgradeable, UUPSUpgradeable { require(msg.value == price, "Incorrect payment"); token.mint(msg.sender); } + + function size() public view returns (uint) { + return deployedTokens.length; + } } diff --git a/test/ERC20TokenV2Test.sol b/test/ERC20TokenV2Test.sol index 7d208b0..d77ee3c 100644 --- a/test/ERC20TokenV2Test.sol +++ b/test/ERC20TokenV2Test.sol @@ -26,7 +26,7 @@ contract ERC20TokenV2Test is Test { address(implementation), abi.encodeCall( implementation.initialize, - (symbol, totalSupply, perMint, price) + (owner.addr, symbol, totalSupply, perMint, price) ) ); // 用代理关联 MyToken 接口 diff --git a/test/TokenFactoryV1Test.sol b/test/TokenFactoryV1Test.sol index 883dbc4..72d5549 100644 --- a/test/TokenFactoryV1Test.sol +++ b/test/TokenFactoryV1Test.sol @@ -6,11 +6,15 @@ import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol"; import {Upgrades} from "openzeppelin-foundry-upgrades/Upgrades.sol"; import {ERC20Token} from "../src/ERC20Token.sol"; +import {ERC20TokenV2} from "../src/ERC20TokenV2.sol"; import {TokenFactoryV1} from "../src/TokenFactoryV1.sol"; +import {TokenFactoryV2} from "../src/TokenFactoryV2.sol"; contract TokenFactoryV1Test is Test { TokenFactoryV1 public factoryv1; + TokenFactoryV2 public factoryv2; ERC20Token public myToken; + ERC20TokenV2 public myToken2; ERC1967Proxy proxy; Account public owner = makeAccount("owner"); Account public newOwner = makeAccount("newOwner"); @@ -21,7 +25,6 @@ contract TokenFactoryV1Test is Test { uint public perMint = 10 ether; function setUp() public { - factoryv1 = new TokenFactoryV1(); // 部署实现 TokenFactoryV1 implementation = new TokenFactoryV1(); // Deploy the proxy and initialize the contract through the proxy @@ -73,13 +76,20 @@ contract TokenFactoryV1Test is Test { } // // 测试升级 - function testUpgradeability() public { - // Upgrade the proxy to a new version; TokenFactoryV2 - Upgrades.upgradeProxy( - address(proxy), - "TokenFactoryV2.sol:TokenFactoryV2", - "", - owner.addr - ); - } + // function testUpgradeability() public { + // // Upgrade the proxy to a new version; TokenFactoryV2 + // address proxyAddress = address(proxy); + // TokenFactoryV2 implementationV2 = new TokenFactoryV2(); + + // address newImplementation = address(implementationV2); + + // // Upgrade the proxy to the new implementation with arguments + + // Upgrades.upgradeProxy( + // address(proxy), + // "TokenFactoryV2.sol:TokenFactoryV2", + // "", + // owner.addr + // ); + // } } diff --git a/test/TokenFactoryV2Test.sol b/test/TokenFactoryV2Test.sol index c9b0ec9..627c844 100644 --- a/test/TokenFactoryV2Test.sol +++ b/test/TokenFactoryV2Test.sol @@ -2,14 +2,93 @@ pragma solidity ^0.8.20; import {Test, console} from "forge-std/Test.sol"; +import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; +import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol"; import {TokenFactoryV2} from "../src/TokenFactoryV2.sol"; +import {ERC20TokenV2} from "../src/ERC20TokenV2.sol"; contract CounterTest is Test { TokenFactoryV2 public factoryv2; + ERC20TokenV2 public myToken2; + ERC1967Proxy proxy; + ERC1967Proxy proxy2; Account public owner = makeAccount("owner"); Account public user = makeAccount("user"); + string public symbol = "ETK"; + uint public totalSupply = 1_000_000 ether; + uint public perMint = 10 ether; + uint public price = 10 ** 16; // 0.01 ETH in wei + function setUp() public { - factoryv2 = new TokenFactoryV2(); + // vm.startPrank(owner.addr); + // 部署实现 + ERC20TokenV2 implementation = new ERC20TokenV2(); + // Deploy the proxy and initialize the contract through the proxy + proxy = new ERC1967Proxy( + address(implementation), + abi.encodeCall( + implementation.initialize, + (owner.addr, symbol, totalSupply, perMint, price) + ) + ); + // 用代理关联 MyToken 接口 + myToken2 = ERC20TokenV2(address(proxy)); + + TokenFactoryV2 implementationV2 = new TokenFactoryV2(); + proxy2 = new ERC1967Proxy( + address(implementationV2), + abi.encodeCall( + implementationV2.initialize, + (owner.addr, address(myToken2)) + ) + ); + // 用代理关联 TokenFactoryV2 接口 + factoryv2 = TokenFactoryV2(address(proxy2)); + // Emit the owner address for debugging purposes + emit log_address(owner.addr); + // vm.stopPrank(); + } + + function testTokenFactoryV2DeployInscriptionFunctionality() public { + vm.startPrank(owner.addr); + factoryv2.deployInscription(symbol, totalSupply, perMint, price); + + assertEq(factoryv2.size(), 1); + + // Fetch the deployed token address + address deployedTokenAddress = factoryv2.deployedTokens(0); + assertEq(factoryv2.tokenPrices(deployedTokenAddress), price); + // Create an instance of the deployed token contract + ERC20TokenV2 deployedToken = ERC20TokenV2(deployedTokenAddress); + console.log("Deployed token address:", deployedTokenAddress); + console.log("Deployed token:", address(deployedToken)); + assertEq(address(deployedToken), deployedTokenAddress); + // Verify token initialization + assertEq(deployedToken.symbol(), symbol); + // assertEq(deployedToken.balanceOf(owner.addr), 0); + // assertEq(deployedToken.totalSupplyToken(), totalSupply); + // assertEq(deployedToken.perMint(), perMint); + + // // Optionally verify owner initialization + // assertEq(deployedToken.owner(), owner.addr); + vm.stopPrank(); + } + + function testTokenFactoryV2MintInscriptionFunctionality() public { + vm.prank(owner.addr); + factoryv2.deployInscription(symbol, totalSupply, perMint, price); + + assertEq(factoryv2.size(), 1); + // Fetch the deployed token address + address deployedTokenAddress = factoryv2.deployedTokens(0); + ERC20TokenV2 deployedToken = ERC20TokenV2(deployedTokenAddress); + vm.startPrank(user.addr); + factoryv2.mintInscription{value: price}(deployedTokenAddress); + assertEq(deployedToken.balanceOf(user.addr), 10 ether); + assertEq(deployedToken.totalSupply(), 10 ether); + // Verify the total supply token + assertEq(deployedToken.totalSupplyToken(), totalSupply); + vm.stopPrank(); } }