From 2364c4f55bbbe36541e1a7f95e1074556db6e6ec Mon Sep 17 00:00:00 2001 From: Max Pushkarov Date: Thu, 1 Aug 2024 20:04:22 +0300 Subject: [PATCH 1/7] feat: add factory contract for BrokerToken --- src/BrokerTokenFactory.sol | 58 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 src/BrokerTokenFactory.sol diff --git a/src/BrokerTokenFactory.sol b/src/BrokerTokenFactory.sol new file mode 100644 index 0000000..39f9523 --- /dev/null +++ b/src/BrokerTokenFactory.sol @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity ^0.8.24; + +import '@openzeppelin/contracts/access/Ownable.sol'; +import './BrokerToken.sol'; + +/** + * @title BrokerTokenFactory + * @notice Factory contract to create new instances of BrokerToken. + * Only the owner can create new tokens. + */ +contract BrokerTokenFactory is Ownable { + // Array to store addresses of created tokens + address[] public brokerTokens; + + /** + * @notice Event emitted when a new BrokerToken is created. + * @param tokenAddress Address of the newly created BrokerToken. + */ + event BrokerTokenCreated(address indexed tokenAddress); + + constructor(address owner) Ownable(owner) {} + + /** + * @notice Creates a new BrokerToken and mints the supply to the factory owner. + * @param name Name of the Token. + * @param symbol Symbol of the Token. + * @param supply Maximum supply of the Token. + */ + function createBrokerToken( + string memory name, + string memory symbol, + uint256 supply + ) external onlyOwner { + BrokerToken token = new BrokerToken(name, symbol, supply); + brokerTokens.push(address(token)); + emit BrokerTokenCreated(address(token)); + } + + /** + * @notice Returns the number of created BrokerTokens. + * @return uint256 Number of created BrokerTokens. + */ + function getBrokerTokensCount() external view returns (uint256) { + return brokerTokens.length; + } + + /** + * @notice Returns the address of a created BrokerToken at a given index. + * @param index Index of the token in the brokerTokens array. + * @return address Address of the BrokerToken. + */ + function getBrokerToken(uint256 index) external view returns (address) { + require(index < brokerTokens.length, "Index out of bounds"); + return brokerTokens[index]; + } +} + From 527a0a79cf5dbbff0c1447aa764b42deb05b82c9 Mon Sep 17 00:00:00 2001 From: Max Pushkarov Date: Thu, 1 Aug 2024 20:04:40 +0300 Subject: [PATCH 2/7] test: add unit tests for factory contract --- test/BrokerTokenFactory.t.sol | 84 +++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 test/BrokerTokenFactory.t.sol diff --git a/test/BrokerTokenFactory.t.sol b/test/BrokerTokenFactory.t.sol new file mode 100644 index 0000000..665a28e --- /dev/null +++ b/test/BrokerTokenFactory.t.sol @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity ^0.8.24; + +import "forge-std/Test.sol"; +import "../src/BrokerTokenFactory.sol"; +import "../src/BrokerToken.sol"; + +contract BrokerTokenFactoryTest is Test { + BrokerTokenFactory factory; + address owner; + + function setUp() public { + owner = address(this); + vm.deal(owner, 100 ether); + factory = new BrokerTokenFactory(owner); + } + + function testCreateBrokerToken() public { + string memory name = "BrokerToken"; + string memory symbol = "BTK"; + uint256 supply = 1000 * 10 ** 8; + + // Ensure only the owner can create tokens + vm.prank(owner); + factory.createBrokerToken(name, symbol, supply); + + // Check if the token was created + assertEq(factory.getBrokerTokensCount(), 1); + + address tokenAddress = factory.getBrokerToken(0); + BrokerToken token = BrokerToken(tokenAddress); + + // Validate the token's properties + assertEq(token.name(), name); + assertEq(token.symbol(), symbol); + assertEq(token.totalSupply(), supply); + assertEq(token.decimals(), 8); + } + + function testFailNonOwnerCannotCreateBrokerToken() public { + string memory name = "BrokerToken"; + string memory symbol = "BTK"; + uint256 supply = 1000 * 10 ** 8; + + // Try to create a token with a different address + vm.prank(address(0x1234)); + vm.expectRevert("Ownable: caller is not the owner"); + factory.createBrokerToken(name, symbol, supply); + } + + function testGetBrokerToken() public { + string memory name = "BrokerToken"; + string memory symbol = "BTK"; + uint256 supply = 1000 * 10 ** 8; + + vm.prank(owner); + factory.createBrokerToken(name, symbol, supply); + + address tokenAddress = factory.getBrokerToken(0); + BrokerToken token = BrokerToken(tokenAddress); + + // Validate the token address + assertEq(address(token), tokenAddress); + } + + function testBrokerTokensCount() public { + string memory name1 = "BrokerToken1"; + string memory symbol1 = "BTK1"; + uint256 supply1 = 1000 * 10 ** 8; + + string memory name2 = "BrokerToken2"; + string memory symbol2 = "BTK2"; + uint256 supply2 = 2000 * 10 ** 8; + + vm.prank(owner); + factory.createBrokerToken(name1, symbol1, supply1); + vm.prank(owner); + factory.createBrokerToken(name2, symbol2, supply2); + + // Validate the number of created tokens + assertEq(factory.getBrokerTokensCount(), 2); + } +} + From aba681ce2b40eaf2ee1d21a5970042592862c250 Mon Sep 17 00:00:00 2001 From: Max Pushkarov Date: Fri, 2 Aug 2024 11:33:20 +0300 Subject: [PATCH 3/7] style: run `forge fmt` --- src/BrokerTokenFactory.sol | 11 +++-------- test/BrokerTokenFactory.t.sol | 3 +-- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/BrokerTokenFactory.sol b/src/BrokerTokenFactory.sol index 39f9523..3d5761a 100644 --- a/src/BrokerTokenFactory.sol +++ b/src/BrokerTokenFactory.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.24; -import '@openzeppelin/contracts/access/Ownable.sol'; -import './BrokerToken.sol'; +import "@openzeppelin/contracts/access/Ownable.sol"; +import "./BrokerToken.sol"; /** * @title BrokerTokenFactory @@ -27,11 +27,7 @@ contract BrokerTokenFactory is Ownable { * @param symbol Symbol of the Token. * @param supply Maximum supply of the Token. */ - function createBrokerToken( - string memory name, - string memory symbol, - uint256 supply - ) external onlyOwner { + function createBrokerToken(string memory name, string memory symbol, uint256 supply) external onlyOwner { BrokerToken token = new BrokerToken(name, symbol, supply); brokerTokens.push(address(token)); emit BrokerTokenCreated(address(token)); @@ -55,4 +51,3 @@ contract BrokerTokenFactory is Ownable { return brokerTokens[index]; } } - diff --git a/test/BrokerTokenFactory.t.sol b/test/BrokerTokenFactory.t.sol index 665a28e..22189df 100644 --- a/test/BrokerTokenFactory.t.sol +++ b/test/BrokerTokenFactory.t.sol @@ -26,7 +26,7 @@ contract BrokerTokenFactoryTest is Test { // Check if the token was created assertEq(factory.getBrokerTokensCount(), 1); - + address tokenAddress = factory.getBrokerToken(0); BrokerToken token = BrokerToken(tokenAddress); @@ -81,4 +81,3 @@ contract BrokerTokenFactoryTest is Test { assertEq(factory.getBrokerTokensCount(), 2); } } - From 96b5c35614a418c690a5b6144bfffaddd1c551a4 Mon Sep 17 00:00:00 2001 From: Max Pushkarov Date: Fri, 2 Aug 2024 14:40:11 +0300 Subject: [PATCH 4/7] docs: add comment about `decimals` ctor param --- src/BrokerToken.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/src/BrokerToken.sol b/src/BrokerToken.sol index 4945bd7..ff3f657 100644 --- a/src/BrokerToken.sol +++ b/src/BrokerToken.sol @@ -15,6 +15,7 @@ contract BrokerToken is ERC20Permit { * Mints the supply to the deployer. * @param name Name of the Token. * @param symbol Symbol of the Token. + * @param decimals_ Number of decimals of the Token. * @param supply Maximum supply of the Token. */ constructor(string memory name, string memory symbol, uint8 decimals_, uint256 supply) From 6f888acf86640c600ede7f852c86096609d2ccd3 Mon Sep 17 00:00:00 2001 From: Max Pushkarov Date: Fri, 2 Aug 2024 14:42:52 +0300 Subject: [PATCH 5/7] feat: add `decimals` param to token factory ctor --- src/BrokerTokenFactory.sol | 7 +++++-- test/BrokerTokenFactory.t.sol | 15 ++++++++++----- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/BrokerTokenFactory.sol b/src/BrokerTokenFactory.sol index 3d5761a..2676eae 100644 --- a/src/BrokerTokenFactory.sol +++ b/src/BrokerTokenFactory.sol @@ -27,8 +27,11 @@ contract BrokerTokenFactory is Ownable { * @param symbol Symbol of the Token. * @param supply Maximum supply of the Token. */ - function createBrokerToken(string memory name, string memory symbol, uint256 supply) external onlyOwner { - BrokerToken token = new BrokerToken(name, symbol, supply); + function createBrokerToken(string memory name, string memory symbol, uint8 decimals, uint256 supply) + external + onlyOwner + { + BrokerToken token = new BrokerToken(name, symbol, decimals, supply); brokerTokens.push(address(token)); emit BrokerTokenCreated(address(token)); } diff --git a/test/BrokerTokenFactory.t.sol b/test/BrokerTokenFactory.t.sol index 22189df..a5580db 100644 --- a/test/BrokerTokenFactory.t.sol +++ b/test/BrokerTokenFactory.t.sol @@ -18,11 +18,12 @@ contract BrokerTokenFactoryTest is Test { function testCreateBrokerToken() public { string memory name = "BrokerToken"; string memory symbol = "BTK"; + uint8 decimals = 8; uint256 supply = 1000 * 10 ** 8; // Ensure only the owner can create tokens vm.prank(owner); - factory.createBrokerToken(name, symbol, supply); + factory.createBrokerToken(name, symbol, decimals, supply); // Check if the token was created assertEq(factory.getBrokerTokensCount(), 1); @@ -40,21 +41,23 @@ contract BrokerTokenFactoryTest is Test { function testFailNonOwnerCannotCreateBrokerToken() public { string memory name = "BrokerToken"; string memory symbol = "BTK"; + uint8 decimals = 8; uint256 supply = 1000 * 10 ** 8; // Try to create a token with a different address vm.prank(address(0x1234)); vm.expectRevert("Ownable: caller is not the owner"); - factory.createBrokerToken(name, symbol, supply); + factory.createBrokerToken(name, symbol, decimals, supply); } function testGetBrokerToken() public { string memory name = "BrokerToken"; string memory symbol = "BTK"; + uint8 decimals = 8; uint256 supply = 1000 * 10 ** 8; vm.prank(owner); - factory.createBrokerToken(name, symbol, supply); + factory.createBrokerToken(name, symbol, decimals, supply); address tokenAddress = factory.getBrokerToken(0); BrokerToken token = BrokerToken(tokenAddress); @@ -66,16 +69,18 @@ contract BrokerTokenFactoryTest is Test { function testBrokerTokensCount() public { string memory name1 = "BrokerToken1"; string memory symbol1 = "BTK1"; + uint8 decimals1 = 8; uint256 supply1 = 1000 * 10 ** 8; string memory name2 = "BrokerToken2"; string memory symbol2 = "BTK2"; + uint8 decimals2 = 8; uint256 supply2 = 2000 * 10 ** 8; vm.prank(owner); - factory.createBrokerToken(name1, symbol1, supply1); + factory.createBrokerToken(name1, symbol1, decimals1, supply1); vm.prank(owner); - factory.createBrokerToken(name2, symbol2, supply2); + factory.createBrokerToken(name2, symbol2, decimals2, supply2); // Validate the number of created tokens assertEq(factory.getBrokerTokensCount(), 2); From 29f34f75b71eb25055ae85760b90519601581180 Mon Sep 17 00:00:00 2001 From: Max Pushkarov Date: Sat, 3 Aug 2024 14:10:06 +0300 Subject: [PATCH 6/7] feat(scripts): add deployment script for BrokerTokenFactory contract --- script/DeployBrokerTokenFactory.s.sol | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 script/DeployBrokerTokenFactory.s.sol diff --git a/script/DeployBrokerTokenFactory.s.sol b/script/DeployBrokerTokenFactory.s.sol new file mode 100644 index 0000000..e3cfb58 --- /dev/null +++ b/script/DeployBrokerTokenFactory.s.sol @@ -0,0 +1,18 @@ +pragma solidity ^0.8.24; + +import {Script, console} from "forge-std/Script.sol"; +import {BrokerTokenFactory} from "../src/BrokerTokenFactory.sol"; + +contract DeployBrokerTokenFactory is Script { + function run() public { + string memory ownerStr = vm.envString("ERC20_FACTORY_OWNER"); + address owner = vm.parseAddress(ownerStr); + + vm.startBroadcast(); // start broadcasting transactions to the blockchain + BrokerTokenFactory factory = new BrokerTokenFactory(owner); + vm.stopBroadcast(); + + console.log("BrokerToken Factory address: %s", address(factory)); + } +} + From 532f8f2b9d0e62786633f5bceed11ceca9a0cb00 Mon Sep 17 00:00:00 2001 From: Max Pushkarov Date: Sat, 3 Aug 2024 14:10:31 +0300 Subject: [PATCH 7/7] style: run `forge fmt` --- script/DeployBrokerTokenFactory.s.sol | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/script/DeployBrokerTokenFactory.s.sol b/script/DeployBrokerTokenFactory.s.sol index e3cfb58..3cf91b7 100644 --- a/script/DeployBrokerTokenFactory.s.sol +++ b/script/DeployBrokerTokenFactory.s.sol @@ -4,15 +4,14 @@ import {Script, console} from "forge-std/Script.sol"; import {BrokerTokenFactory} from "../src/BrokerTokenFactory.sol"; contract DeployBrokerTokenFactory is Script { - function run() public { - string memory ownerStr = vm.envString("ERC20_FACTORY_OWNER"); - address owner = vm.parseAddress(ownerStr); + function run() public { + string memory ownerStr = vm.envString("ERC20_FACTORY_OWNER"); + address owner = vm.parseAddress(ownerStr); - vm.startBroadcast(); // start broadcasting transactions to the blockchain - BrokerTokenFactory factory = new BrokerTokenFactory(owner); - vm.stopBroadcast(); + vm.startBroadcast(); // start broadcasting transactions to the blockchain + BrokerTokenFactory factory = new BrokerTokenFactory(owner); + vm.stopBroadcast(); - console.log("BrokerToken Factory address: %s", address(factory)); - } + console.log("BrokerToken Factory address: %s", address(factory)); + } } -