Bläddra i källkod

feat: Replace hardhat-deploy with ignition, upgrade dependencies and update documentation (#126)

* chore: Update deps

* feat: Implement BasicERC20Module

* feat: Implement BasicERC721Module

* feat: Implement BasicERC1155Module

* feat: Use parameters file for config

* feat: Use parameters file for config

* feat: Use parameters file for config

* chore: Update test BasicERC20

* chore: Add from owner to tests

* chore: Update test BasicERC721

* chore: Update test BasicERC1155

* chore: Format

* chore: Remove hardhat deploy

* chore: Remove named accounts

* chore: Update solidity version

* chore: Rename paramters json

* chore: Update license

* docs: Update docs to match latest changes

* chore: Bump deps and add contributors

* chore: Re-organise erc20 imports

* chore: Migrate to eslint 9.x
KovacZan 1 månad sedan
förälder
incheckning
68c5d08eed

+ 0 - 18
.eslintrc.json

@@ -1,18 +0,0 @@
-{
-	"env": {
-		"es2021": true
-	},
-	"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier"],
-	"parser": "@typescript-eslint/parser",
-	"parserOptions": {
-		"ecmaVersion": "latest",
-		"sourceType": "module"
-	},
-	"plugins": ["@typescript-eslint", "prettier"],
-	"rules": {
-		"prettier/prettier": "warn",
-		"@typescript-eslint/no-unused-vars": "warn",
-		"@typescript-eslint/no-explicit-any": "warn"
-	},
-	"ignorePatterns": ["node_modules", "coverage", "deployments", "artifacts", "cache", "typechain-types"]
-}

+ 2 - 2
.prettierrc.json

@@ -10,8 +10,8 @@
 		{
 			"files": "*.sol",
 			"options": {
-				"parser": "solidity-parse",
-				"printWidth": 80,
+				"parser": "slang",
+				"printWidth": 120,
 				"tabWidth": 4,
 				"useTabs": true,
 				"singleQuote": false,

+ 1 - 1
LICENSE

@@ -1,6 +1,6 @@
 MIT License
 
-Copyright (c) 2023 Protokol
+Copyright (c) 2025 Protokol
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal

+ 62 - 34
README.md

@@ -7,13 +7,13 @@ All you have to do is create a new repository from the template and start coding
 
 ## Hardhat Configuration
 
--   [Typechain](https://github.com/dethcrypto/TypeChain) plugin enabled (typescript type bindings for smart contracts)
--   [hardhat-deploy](https://github.com/wighawag/hardhat-deploy) plugin enabled
--   Testing environment configured and operational, with test coverage
--   Prettier and eslint configured for project files and solidity smart contract
--   [Solhint](https://github.com/protofire/solhint) configured for enforcing best practices
--   Github actions workflows prepared for CI/CD
--   Prepared Smart Contract Examples, Tests, Deployments and Tasks for Common ERC Standards (ERC20, ERC721, ERC1155)
+- [Typechain](https://github.com/dethcrypto/TypeChain) plugin enabled (typescript type bindings for smart contracts)
+- [Ignition](https://hardhat.org/ignition/docs/getting-started) for contract deployment
+- Testing environment configured and operational, with test coverage
+- Prettier and eslint configured for project files and solidity smart contract
+- [Solhint](https://github.com/protofire/solhint) configured for enforcing best practices
+- Github actions workflows prepared for CI/CD
+- Prepared Smart Contract Examples, Tests, Deployments and Tasks for Common ERC Standards (ERC20, ERC721, ERC1155)
 
 Check the Hardhat documentation for more information.
 
@@ -27,30 +27,44 @@ https://hardhat.org/getting-started/
 │   ├── BasicERC1155.sol
 │   ├── BasicERC20.sol
 │   └── BasicERC721.sol
-├── deploy
-│   ├── Deploy_BasicERC1155.ts
-│   ├── Deploy_BasicERC20.ts
-│   └── Deploy_BasicERC721.ts
-├── deployments
-├── hardhat.config.ts
+├── ignition
+│   ├── deployments
+│   ├── modules
+│   │   ├── BasicERC1155Module.ts
+│   │   ├── BasicERC20Module.ts
+│   │   └── BasicERC721Module.ts
+│   └── parameters
+│       └── custom.json
 ├── tasks
 │   ├── erc1155
+│   │   ├── base-uri.ts
+│   │   ├── contract-uri.ts
+│   │   └── mint.ts
 │   ├── erc20
+│   │   └── mint.ts
 │   ├── erc721
+│   │   ├── base-uri.ts
+│   │   ├── contract-uri.ts
+│   │   └── mint.ts
 │   └── utils
-└── test
-    ├── BasicERC1155.ts
-    ├── BasicERC20.ts
-    └── BasicERC721.ts
+│       ├── accounts.ts
+│       ├── balance.ts
+│       ├── block-number.ts
+│       └── send-eth.ts
+├── test
+│   ├── BasicERC1155.ts
+│   ├── BasicERC20.ts
+│   └── BasicERC721.ts
+└── hardhat.config.ts
 ```
 
 ## Supported Networks
 
--   Hardhat Network (localhost)
--   Ethereum Mainnet
--   Ethereum Sepolia Testnet
--   Polygon Mainnet
--   Polygon Mumbai Testnet
+- Hardhat Network (localhost)
+- Ethereum Mainnet
+- Ethereum Sepolia Testnet
+- Polygon Mainnet
+- Polygon Mumbai Testnet
 
 Feel free to add more networks in `hardhat.config.ts` file.
 
@@ -66,12 +80,12 @@ https://hardhat.org/guides/shorthand.html
 
 ### Common Shorthand Commands
 
--   `hh compile` - to compile smart contract and generate typechain ts bindings
--   `hh test` - to run tests
--   `hh deploy` - to deploy to local network (see options for more)
--   `hh node` - to run a localhost node
--   `hh help` - to see all available commands
--   `hh TABTAB` - to use autocomplete
+- `hh compile` - to compile smart contract and generate typechain ts bindings
+- `hh test` - to run tests
+- `hh igntion` - to deploy smart contracts
+- `hh node` - to run a localhost node
+- `hh help` - to see all available commands
+- `hh TABTAB` - to use autocomplete
 
 ## Usage
 
@@ -101,23 +115,37 @@ Make sure you include either `MNEMONIC` or `PRIVATE_KEY` in your `.env` file.
 
 > This is an example flow to deploy an ERC721 token to a public network and interact with it.
 
-#### 1. Deploy BasicERC721 Contract
+#### 1.1 Deploy BasicERC721 Contract
 
 ```shell
-hh deploy --network sepolia --tags BasicERC721
+hh ignition deploy ignition/modules/BasicERC721Module.ts --network sepolia
 ```
 
-#### 2. Verify Contract
+**Verify contract**
 
 ```shell
-hh --network sepolia etherscan-verify
+hh ignition verify chain-11155111
 ```
 
-#### 3. Interact With Contract - Mint
+#### 1.2 Deploy and Verify
+
+```shell
+hh ignition deploy ignition/modules/BasicERC721Module.ts --network sepolia --verify
+```
+
+#### 1.3 Deploy and Verify with Custom Parameters
+
+Look at `ignition/parameters/custom.json` to see how to adjust contract parameters
+
+```shell
+hh ignition deploy ignition/modules/BasicERC721Module.ts --network sepolia --verify --parameters ignition/parameters/custom.json
+```
+
+#### 2. Interact With Contract - Mint
 
 ```shell
 hh erc721-mint \
- --contract 0x77337983A7D1699FaF51a5f43b9907fB7B614097 \
+ --contract 0x1FEB5675Be6F256c4680BE447D6C353E02e04fb9 \
  --recipient 0x73faDd7E476a9Bc2dA6D1512A528366A3E50c3cF \
  --network sepolia
 ```

+ 5 - 24
contracts/BasicERC1155.sol

@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: MIT
-pragma solidity 0.8.20;
+pragma solidity 0.8.28;
 
 import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
 import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
@@ -12,13 +12,7 @@ import { ERC1155Supply } from "@openzeppelin/contracts/token/ERC1155/extensions/
  * This file was generated with Openzeppelin Wizard and later modified.
  * GO TO: https://wizard.openzeppelin.com/#erc1155
  */
-contract BasicERC1155 is
-	ERC1155,
-	Ownable,
-	ERC1155Pausable,
-	ERC1155Burnable,
-	ERC1155Supply
-{
+contract BasicERC1155 is ERC1155, Ownable, ERC1155Pausable, ERC1155Burnable, ERC1155Supply {
 	using Strings for uint256;
 
 	string public name;
@@ -54,19 +48,11 @@ contract BasicERC1155 is
 		_unpause();
 	}
 
-	function mint(
-		address account,
-		uint256 id,
-		uint256 amount
-	) external onlyOwner {
+	function mint(address account, uint256 id, uint256 amount) external onlyOwner {
 		_mint(account, id, amount, "");
 	}
 
-	function mintBatch(
-		address to,
-		uint256[] memory ids,
-		uint256[] memory amounts
-	) external onlyOwner {
+	function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts) external onlyOwner {
 		_mintBatch(to, ids, amounts, "");
 	}
 
@@ -79,12 +65,7 @@ contract BasicERC1155 is
 	 * This is useful for metadata published on ipfs where files have .json suffix
 	 */
 	function uri(uint256 id) public view override returns (string memory) {
-		return
-			bytes(super.uri(id)).length > 0
-				? string(
-					abi.encodePacked(super.uri(id), id.toString(), ".json")
-				)
-				: "";
+		return bytes(super.uri(id)).length > 0 ? string(abi.encodePacked(super.uri(id), id.toString(), ".json")) : "";
 	}
 
 	function _update(

+ 2 - 6
contracts/BasicERC20.sol

@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: MIT
-pragma solidity 0.8.20;
+pragma solidity 0.8.28;
 
 import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
 import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
@@ -29,11 +29,7 @@ contract BasicERC20 is ERC20, ERC20Burnable, ERC20Pausable, Ownable {
 		_mint(to, amount);
 	}
 
-	function _update(
-		address from,
-		address to,
-		uint256 value
-	) internal override(ERC20, ERC20Pausable) {
+	function _update(address from, address to, uint256 value) internal override(ERC20, ERC20Pausable) {
 		super._update(from, to, value);
 	}
 }

+ 9 - 32
contracts/BasicERC721.sol

@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: MIT
-pragma solidity 0.8.20;
+pragma solidity 0.8.28;
 
 import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
 import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
@@ -12,13 +12,7 @@ import { ERC721Burnable } from "@openzeppelin/contracts/token/ERC721/extensions/
  * This file was generated with Openzeppelin Wizard and later modified.
  * GO TO: https://wizard.openzeppelin.com/#erc721
  */
-contract BasicERC721 is
-	ERC721,
-	ERC721Enumerable,
-	ERC721Pausable,
-	Ownable,
-	ERC721Burnable
-{
+contract BasicERC721 is ERC721, ERC721Enumerable, ERC721Pausable, Ownable, ERC721Burnable {
 	using Strings for uint256;
 
 	uint256 private _nextTokenId;
@@ -71,42 +65,25 @@ contract BasicERC721 is
 	 * @dev Returns base uri and adds .json suffix
 	 * This is useful for metadata published on ipfs where files have .json suffix
 	 */
-	function tokenURI(
-		uint256 tokenId
-	) public view override returns (string memory) {
-		if (ownerOf(tokenId) == address(0))
-			revert ERC721NonexistentToken(tokenId);
-
-		return
-			bytes(_baseURI()).length > 0
-				? string(
-					abi.encodePacked(_baseURI(), tokenId.toString(), ".json")
-				)
-				: "";
+	function tokenURI(uint256 tokenId) public view override returns (string memory) {
+		if (ownerOf(tokenId) == address(0)) revert ERC721NonexistentToken(tokenId);
+
+		return bytes(_baseURI()).length > 0 ? string(abi.encodePacked(_baseURI(), tokenId.toString(), ".json")) : "";
 	}
 
 	function _update(
 		address to,
 		uint256 tokenId,
 		address auth
-	)
-		internal
-		override(ERC721, ERC721Enumerable, ERC721Pausable)
-		returns (address)
-	{
+	) internal override(ERC721, ERC721Enumerable, ERC721Pausable) returns (address) {
 		return super._update(to, tokenId, auth);
 	}
 
-	function _increaseBalance(
-		address account,
-		uint128 value
-	) internal override(ERC721, ERC721Enumerable) {
+	function _increaseBalance(address account, uint128 value) internal override(ERC721, ERC721Enumerable) {
 		super._increaseBalance(account, value);
 	}
 
-	function supportsInterface(
-		bytes4 interfaceId
-	) public view override(ERC721, ERC721Enumerable) returns (bool) {
+	function supportsInterface(bytes4 interfaceId) public view override(ERC721, ERC721Enumerable) returns (bool) {
 		return super.supportsInterface(interfaceId);
 	}
 }

+ 0 - 14
deploy/Deploy_BasicERC1155.ts

@@ -1,14 +0,0 @@
-import { DeployFunction } from "hardhat-deploy/types"
-import { HardhatRuntimeEnvironment } from "hardhat/types"
-
-const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
-	const { deployer, owner } = await hre.getNamedAccounts()
-
-	await hre.deployments.deploy("BasicERC1155", {
-		from: deployer,
-		args: ["ProtoToken", "PT", "ipfs://base-uri/", "ipfs://contract-uri", owner],
-		log: true,
-	})
-}
-export default func
-func.tags = ["erc1155"]

+ 0 - 14
deploy/Deploy_BasicERC20.ts

@@ -1,14 +0,0 @@
-import { DeployFunction } from "hardhat-deploy/types"
-import { HardhatRuntimeEnvironment } from "hardhat/types"
-
-const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
-	const { deployer, owner } = await hre.getNamedAccounts()
-
-	await hre.deployments.deploy("BasicERC20", {
-		from: deployer,
-		args: ["ProtoToken", "PT", owner],
-		log: true,
-	})
-}
-export default func
-func.tags = ["erc20"]

+ 0 - 14
deploy/Deploy_BasicERC721.ts

@@ -1,14 +0,0 @@
-import { DeployFunction } from "hardhat-deploy/types"
-import { HardhatRuntimeEnvironment } from "hardhat/types"
-
-const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
-	const { deployer, owner } = await hre.getNamedAccounts()
-
-	await hre.deployments.deploy("BasicERC721", {
-		from: deployer,
-		args: ["ProtoToken", "PT", "ipfs://base-uri/", "ipfs://contract-uri", owner],
-		log: true,
-	})
-}
-export default func
-func.tags = ["erc721"]

+ 48 - 0
eslint.config.mjs

@@ -0,0 +1,48 @@
+import { defineConfig, globalIgnores } from "eslint/config"
+import typescriptEslint from "@typescript-eslint/eslint-plugin"
+import prettier from "eslint-plugin-prettier"
+import tsParser from "@typescript-eslint/parser"
+import path from "node:path"
+import { fileURLToPath } from "node:url"
+import js from "@eslint/js"
+import { FlatCompat } from "@eslint/eslintrc"
+
+const __filename = fileURLToPath(import.meta.url)
+const __dirname = path.dirname(__filename)
+const compat = new FlatCompat({
+	baseDirectory: __dirname,
+	recommendedConfig: js.configs.recommended,
+	allConfig: js.configs.all,
+})
+
+export default defineConfig([
+	globalIgnores([
+		"**/node_modules",
+		"**/coverage",
+		"**/deployments",
+		"**/artifacts",
+		"**/cache",
+		"**/typechain-types",
+	]),
+	{
+		extends: compat.extends("eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier"),
+
+		plugins: {
+			"@typescript-eslint": typescriptEslint,
+			prettier,
+		},
+
+		languageOptions: {
+			globals: {},
+			parser: tsParser,
+			ecmaVersion: "latest",
+			sourceType: "module",
+		},
+
+		rules: {
+			"prettier/prettier": "warn",
+			"@typescript-eslint/no-unused-vars": "warn",
+			"@typescript-eslint/no-explicit-any": "warn",
+		},
+	},
+])

+ 2 - 26
hardhat.config.ts

@@ -2,27 +2,12 @@ import "@nomicfoundation/hardhat-toolbox"
 
 import { HardhatUserConfig } from "hardhat/config"
 
-import "hardhat-deploy"
 import "@nomiclabs/hardhat-solhint"
-import "hardhat-deploy"
 import "solidity-coverage"
 
 import "dotenv/config"
 
-import "./tasks/utils/accounts"
-import "./tasks/utils/balance"
-import "./tasks/utils/block-number"
-import "./tasks/utils/send-eth"
-
-import "./tasks/erc721/mint"
-import "./tasks/erc721/base-uri"
-import "./tasks/erc721/contract-uri"
-
-import "./tasks/erc20/mint"
-
-import "./tasks/erc1155/mint"
-import "./tasks/erc1155/base-uri"
-import "./tasks/erc1155/contract-uri"
+import "./tasks"
 
 const MAINNET_RPC_URL = process.env.MAINNET_RPC_URL || "https://eth-mainnet.g.alchemy.com/v2/your-api-key"
 const SEPOLIA_RPC_URL = process.env.SEPOLIA_RPC_URL || "https://eth-sepolia.g.alchemy.com/v2/your-api-key"
@@ -76,19 +61,10 @@ const config: HardhatUserConfig = {
 			polygonMumbai: POLYGONSCAN_API_KEY,
 		},
 	},
-	namedAccounts: {
-		deployer: {
-			default: 0, // here this will by default take the first account as deployer
-			mainnet: 0, // similarly on mainnet it will take the first account as deployer.
-		},
-		owner: {
-			default: 0,
-		},
-	},
 	solidity: {
 		compilers: [
 			{
-				version: "0.8.20",
+				version: "0.8.28",
 			},
 		],
 	},

+ 0 - 0
deployments/.gitkeep → ignition/deployments/.gitkeep


+ 22 - 0
ignition/modules/BasicERC1155Module.ts

@@ -0,0 +1,22 @@
+import { buildModule } from "@nomicfoundation/hardhat-ignition/modules"
+
+/**
+ * BasicERC1155Module for deploying the BasicERC1155 token contract
+ */
+const BasicERC1155Module = buildModule("BasicERC1155Module", (m) => {
+	// Contract parameters
+	const tokenName = m.getParameter("name", "Default Token Name")
+	const tokenSymbol = m.getParameter("symbol", "DTN")
+	const baseUri = m.getParameter("baseUri", "ipfs://base-uri/")
+	const contractUri = m.getParameter("contractUri", "ipfs://contract-uri")
+	// Account index 0 is the owner and deployer
+	const owner = m.getAccount(0)
+
+	const basicERC1155 = m.contract("BasicERC1155", [tokenName, tokenSymbol, baseUri, contractUri, owner], {
+		from: owner,
+	})
+
+	return { basicERC1155 }
+})
+
+export default BasicERC1155Module

+ 20 - 0
ignition/modules/BasicERC20Module.ts

@@ -0,0 +1,20 @@
+import { buildModule } from "@nomicfoundation/hardhat-ignition/modules"
+
+/**
+ * BasicERC20Module for deploying the BasicERC20 token contract
+ */
+const BasicERC20Module = buildModule("BasicERC20Module", (m) => {
+	// Contract parameters
+	const tokenName = m.getParameter("name", "Default Token Name")
+	const tokenSymbol = m.getParameter("symbol", "DTN")
+	// Account index 0 is the owner and deployer
+	const owner = m.getAccount(0)
+
+	const basicERC20 = m.contract("BasicERC20", [tokenName, tokenSymbol, owner], {
+		from: owner,
+	})
+
+	return { basicERC20 }
+})
+
+export default BasicERC20Module

+ 22 - 0
ignition/modules/BasicERC721Module.ts

@@ -0,0 +1,22 @@
+import { buildModule } from "@nomicfoundation/hardhat-ignition/modules"
+
+/**
+ * BasicERC721Module for deploying the BasicERC721 token contract
+ */
+const BasicERC721Module = buildModule("BasicERC721Module", (m) => {
+	// Contract parameters
+	const tokenName = m.getParameter("name", "Default Token Name")
+	const tokenSymbol = m.getParameter("symbol", "DTN")
+	const baseUri = m.getParameter("baseUri", "ipfs://base-uri/")
+	const contractUri = m.getParameter("contractUri", "ipfs://contract-uri")
+	// Account index 0 is the owner and deployer
+	const owner = m.getAccount(0)
+
+	const basicERC721 = m.contract("BasicERC721", [tokenName, tokenSymbol, baseUri, contractUri, owner], {
+		from: owner,
+	})
+
+	return { basicERC721 }
+})
+
+export default BasicERC721Module

+ 18 - 0
ignition/parameters/custom.json

@@ -0,0 +1,18 @@
+{
+	"BasicERC20Module": {
+		"name": "ProtoToken",
+		"symbol": "PT"
+	},
+	"BasicERC721Module": {
+		"name": "ProtoToken",
+		"symbol": "PT",
+		"baseUri": "ipfs://base-uri/",
+		"contractUri": "ipfs://contract-uri"
+	},
+	"BasicERC1155Module": {
+		"name": "ProtoToken",
+		"symbol": "PT",
+		"baseUri": "ipfs://base-uri/",
+		"contractUri": "ipfs://contract-uri"
+	}
+}

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 426 - 415
package-lock.json


+ 23 - 19
package.json

@@ -6,7 +6,7 @@
 		"compile": "hardhat compile",
 		"test": "hardhat test",
 		"coverage": "hardhat coverage",
-		"deploy": "hardhat deploy",
+		"deploy": "hardhat ignition deploy",
 		"node": "hardhat node",
 		"sol:format:check": "prettier --check --plugin=prettier-plugin-solidity 'contracts/**/*.sol'",
 		"sol:format:write": "prettier --write --plugin=prettier-plugin-solidity 'contracts/**/*.sol'",
@@ -16,29 +16,33 @@
 		"lint:check": "eslint .",
 		"lint:fix": "eslint --fix ."
 	},
-	"author": "Kristjan Kosic <kristjan@protokol.com>",
+	"contributors": [
+		"Kristjan Kosic <kristjan@protokol.com>",
+		"Žan Kovač <zan@protokol.com>"
+	],
 	"license": "MIT",
 	"dependencies": {
 		"@openzeppelin/contracts": "5.3.0"
 	},
 	"devDependencies": {
-		"@nomicfoundation/hardhat-toolbox": "^5.0.0",
-		"@nomiclabs/hardhat-solhint": "^4.0.0",
+		"@eslint/eslintrc": "^3.3.1",
+		"@eslint/js": "^9.30.0",
+		"@nomicfoundation/hardhat-toolbox": "^6.0.0",
+		"@nomiclabs/hardhat-solhint": "^4.0.2",
 		"@openzeppelin/test-helpers": "^0.5.16",
-		"@types/node": "^22.0.0",
-		"@typescript-eslint/eslint-plugin": "^8.0.0",
-		"@typescript-eslint/parser": "^8.0.0",
-		"dotenv": "^16.3.1",
-		"eslint": "^8.53.0",
-		"eslint-config-prettier": "^9.0.0",
-		"eslint-plugin-prettier": "^5.0.1",
-		"ethers": "^6.8.1",
-		"hardhat": "^2.19.0",
-		"hardhat-deploy": "^0.14.0",
-		"prettier": "^3.0.3",
-		"prettier-plugin-solidity": "^1.2.0",
-		"solhint": "^5.0.0",
-		"solidity-coverage": "^0.8.5",
-		"typescript": "^5.2.2"
+		"@types/node": "^22.15.34",
+		"@typescript-eslint/eslint-plugin": "^8.35.0",
+		"@typescript-eslint/parser": "^8.35.0",
+		"dotenv": "^17.0.0",
+		"eslint": "^9.30.0",
+		"eslint-config-prettier": "^10.1.5",
+		"eslint-plugin-prettier": "^5.5.1",
+		"ethers": "^6.14.4",
+		"hardhat": "^2.25.0",
+		"prettier": "^3.6.2",
+		"prettier-plugin-solidity": "^2.0.0",
+		"solhint": "^5.2.0",
+		"solidity-coverage": "^0.8.16",
+		"typescript": "^5.8.3"
 	}
 }

+ 1 - 1
tasks/erc1155/base-uri.ts

@@ -2,7 +2,7 @@ import { task } from "hardhat/config"
 
 /**
  Example:
- hardhat erc1155-base-uri \
+ npx hardhat erc1155-base-uri \
  --contract 0x320bd6de80d3D5361e1c9bB4CF1D7D9Ef24F3Ac7 \
  --uri https://ipfs.io/ipfs/new-base-uri-ipfs-hash/ \
  --network sepolia

+ 1 - 1
tasks/erc1155/contract-uri.ts

@@ -2,7 +2,7 @@ import { task } from "hardhat/config"
 
 /**
  Example:
- hardhat erc1155-contract-uri \
+ npx hardhat erc1155-contract-uri \
  --contract 0x320bd6de80d3D5361e1c9bB4CF1D7D9Ef24F3Ac7 \
  --uri https://ipfs.io/ipfs/new-contract-uri-ipfs-hash \
  --network sepolia

+ 3 - 0
tasks/erc1155/index.ts

@@ -0,0 +1,3 @@
+import "./base-uri"
+import "./contract-uri"
+import "./mint"

+ 1 - 1
tasks/erc1155/mint.ts

@@ -2,7 +2,7 @@ import { task } from "hardhat/config"
 
 /**
  Example:
- hardhat erc1155-mint \
+ npx hardhat erc1155-mint \
  --contract 0x320bd6de80d3D5361e1c9bB4CF1D7D9Ef24F3Ac7 \
  --recipient 0x73faDd7E476a9Bc2dA6D1512A528366A3E50c3cF \
  --id 1 \

+ 1 - 0
tasks/erc20/index.ts

@@ -0,0 +1 @@
+import "./mint"

+ 2 - 2
tasks/erc20/mint.ts

@@ -2,8 +2,8 @@ import { task } from "hardhat/config"
 
 /**
  Example:
- hardhat erc20-mint \
- --contract 0xca6C5326076fe4a1a2369D5Ed8Dd7162c922CD1D \
+ npx hardhat erc20-mint \
+ --contract 0xe48A08C8C941c86D671D17EF50892D518D6f2bf0 \
  --recipient 0x73faDd7E476a9Bc2dA6D1512A528366A3E50c3cF \
  --amount 10000 \
  --network sepolia

+ 1 - 1
tasks/erc721/base-uri.ts

@@ -2,7 +2,7 @@ import { task } from "hardhat/config"
 
 /**
  Example:
- hardhat erc721-base-uri \
+ npx hardhat erc721-base-uri \
  --contract 0x77337983A7D1699FaF51a5f43b9907fB7B614097 \
  --uri https://ipfs.io/ipfs/new-base-uri-ipfs-hash/ \
  --network sepolia

+ 1 - 1
tasks/erc721/contract-uri.ts

@@ -2,7 +2,7 @@ import { task } from "hardhat/config"
 
 /**
  Example:
- hardhat erc721-contract-uri \
+ npx hardhat erc721-contract-uri \
  --contract 0x77337983A7D1699FaF51a5f43b9907fB7B614097 \
  --uri https://ipfs.io/ipfs/new-contract-uri-ipfs-hash \
  --network sepolia

+ 3 - 0
tasks/erc721/index.ts

@@ -0,0 +1,3 @@
+import "./base-uri"
+import "./contract-uri"
+import "./mint"

+ 1 - 1
tasks/erc721/mint.ts

@@ -2,7 +2,7 @@ import { task } from "hardhat/config"
 
 /**
  Example:
- hardhat erc721-mint \
+ npx hardhat erc721-mint \
  --contract 0x77337983A7D1699FaF51a5f43b9907fB7B614097 \
  --recipient 0x73faDd7E476a9Bc2dA6D1512A528366A3E50c3cF \
  --network sepolia

+ 4 - 0
tasks/index.ts

@@ -0,0 +1,4 @@
+import "./erc20"
+import "./erc721"
+import "./erc1155"
+import "./utils"

+ 5 - 0
tasks/utils/accounts.ts

@@ -1,5 +1,10 @@
 import { task } from "hardhat/config"
 
+/**
+ Example:
+ npx hardhat accounts
+ */
+
 task("accounts", "Prints the list of accounts", async (_taskArgs, env) => {
 	const accounts = await env.ethers.getSigners()
 

+ 5 - 0
tasks/utils/balance.ts

@@ -1,5 +1,10 @@
 import { task } from "hardhat/config"
 
+/**
+ Example:
+ npx hardhat balance --account 0x7B36b05B0E2Ee8A66816473AD848e0da073F7019 --network sepolia
+ */
+
 task("balance", "Prints an account's balance")
 	.addParam("account", "The account's address")
 	.setAction(async (taskArgs, { ethers }) => {

+ 4 - 0
tasks/utils/block-number.ts

@@ -1,5 +1,9 @@
 import { task } from "hardhat/config"
 
+/**
+ Example:
+ npx hardhat block-number --network sepolia
+ */
 task("block-number", "Prints the current block number", async (_, { ethers }) => {
 	await ethers.provider.getBlockNumber().then((blockNumber) => {
 		console.log("Current block number: " + blockNumber)

+ 4 - 0
tasks/utils/index.ts

@@ -0,0 +1,4 @@
+import "./accounts"
+import "./balance"
+import "./block-number"
+import "./send-eth"

+ 5 - 0
tasks/utils/send-eth.ts

@@ -1,5 +1,10 @@
 import { task } from "hardhat/config"
 
+/**
+ Example:
+ npx hardhat send-eth --recipient 0x7B36b05B0E2Ee8A66816473AD848e0da073F7019 --value 0.1 --network sepolia
+ */
+
 task("send-eth", "Send ETH to an address")
 	.addParam<string>("recipient", "Recipient of ETH")
 	.addParam<string>("value", "Amount of ETH to send")

+ 17 - 18
test/BasicERC1155.ts

@@ -1,27 +1,26 @@
 import { expect } from "chai"
-import { deployments, ethers, getNamedAccounts } from "hardhat"
+import { ethers } from "hardhat"
+import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers"
 
 describe("BasicERC1155", () => {
-	const setupFixture = deployments.createFixture(async () => {
-		await deployments.fixture()
-		const signers = await getNamedAccounts()
+	const setupFixture = async () => {
+		const signers = await ethers.getSigners()
 
 		const name = "ProtoToken"
 		const symbol = "PT"
 		const baseURI = "ipfs://base-uri/"
 		const contractURI = "ipfs://contract-uri"
-		const owner = signers.deployer
+		const owner = signers[0].address
 
-		const contract = await ethers.deployContract(
-			"BasicERC1155",
-			[name, symbol, baseURI, contractURI, owner],
-			await ethers.getSigner(signers.deployer)
-		)
+		const BasicERC1155 = await ethers.getContractFactory("BasicERC1155")
+		const contract = await BasicERC1155.deploy(name, symbol, baseURI, contractURI, owner, {
+			from: owner,
+		})
 
 		return {
 			contract,
 			contractAddress: await contract.getAddress(),
-			deployer: signers.deployer,
+			deployer: owner,
 			accounts: await ethers.getSigners(),
 			contractConstructor: {
 				name,
@@ -31,10 +30,10 @@ describe("BasicERC1155", () => {
 				owner,
 			},
 		}
-	})
+	}
 
 	it("Should Return Valid Contract Configurations Passed In Constructor", async () => {
-		const { contractConstructor, contract } = await setupFixture()
+		const { contractConstructor, contract } = await loadFixture(setupFixture)
 
 		expect(await contract.name()).to.equal(contractConstructor.name)
 		expect(await contract.symbol()).to.equal(contractConstructor.symbol)
@@ -44,7 +43,7 @@ describe("BasicERC1155", () => {
 
 	describe("Minting Functionality", () => {
 		it("Should Increase Supply When Minting", async () => {
-			const { contract, deployer } = await setupFixture()
+			const { contract, deployer } = await loadFixture(setupFixture)
 
 			expect(await contract["totalSupply(uint256)"](1)).to.equal(0)
 			expect(await contract["totalSupply(uint256)"](2)).to.equal(0)
@@ -59,7 +58,7 @@ describe("BasicERC1155", () => {
 		})
 
 		it("Should Allow Minting Only to Contract Owner - mint", async () => {
-			const { contract, accounts } = await setupFixture()
+			const { contract, accounts } = await loadFixture(setupFixture)
 
 			await expect(contract.connect(accounts[1]).mint(accounts[1].address, 1, 1000))
 				.to.be.revertedWithCustomError(contract, "OwnableUnauthorizedAccount")
@@ -67,7 +66,7 @@ describe("BasicERC1155", () => {
 		})
 
 		it("Should Allow Minting Only to Contract Owner - mintBatch", async () => {
-			const { contract, accounts } = await setupFixture()
+			const { contract, accounts } = await loadFixture(setupFixture)
 
 			await expect(contract.connect(accounts[1]).mintBatch(accounts[1].address, [1], [1000]))
 				.to.be.revertedWithCustomError(contract, "OwnableUnauthorizedAccount")
@@ -77,13 +76,13 @@ describe("BasicERC1155", () => {
 
 	describe("Contract And Token Metadata", () => {
 		it("Should Return Correct Token URI", async () => {
-			const { contract, contractConstructor } = await setupFixture()
+			const { contract, contractConstructor } = await loadFixture(setupFixture)
 
 			expect(await contract.uri(1)).to.equal(`${contractConstructor.baseURI}1.json`)
 		})
 
 		it("Should Return Correct Contract URI", async () => {
-			const { contract, contractConstructor } = await setupFixture()
+			const { contract, contractConstructor } = await loadFixture(setupFixture)
 
 			expect(await contract.contractURI()).to.equal(contractConstructor.contractURI)
 		})

+ 14 - 15
test/BasicERC20.ts

@@ -1,25 +1,24 @@
 import { expect } from "chai"
-import { deployments, ethers, getNamedAccounts } from "hardhat"
+import { ethers } from "hardhat"
+import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers"
 
 describe("BasicERC20", () => {
-	const setupFixture = deployments.createFixture(async () => {
-		await deployments.fixture()
-		const signers = await getNamedAccounts()
+	const setupFixture = async () => {
+		const signers = await ethers.getSigners()
 
 		const name = "ProtoToken"
 		const symbol = "PT"
-		const owner = signers.deployer
+		const owner = signers[0].address
 
-		const contract = await ethers.deployContract(
-			"BasicERC20",
-			[name, symbol, owner],
-			await ethers.getSigner(signers.deployer)
-		)
+		const BasicERC20 = await ethers.getContractFactory("BasicERC20")
+		const contract = await BasicERC20.deploy(name, symbol, owner, {
+			from: owner,
+		})
 
 		return {
 			contract,
 			contractAddress: await contract.getAddress(),
-			deployer: signers.deployer,
+			deployer: owner,
 			accounts: await ethers.getSigners(),
 			contractConstructor: {
 				name,
@@ -27,10 +26,10 @@ describe("BasicERC20", () => {
 				owner,
 			},
 		}
-	})
+	}
 
 	it("Should Return Valid Contract Configurations Passed In Constructor", async () => {
-		const { contractConstructor, contract } = await setupFixture()
+		const { contractConstructor, contract } = await loadFixture(setupFixture)
 
 		expect(await contract.name()).to.equal(contractConstructor.name)
 		expect(await contract.symbol()).to.equal(contractConstructor.symbol)
@@ -39,7 +38,7 @@ describe("BasicERC20", () => {
 
 	describe("Minting Functionality", () => {
 		it("Should Increase Total Supply and User Supply When Minting", async () => {
-			const { contract, accounts } = await setupFixture()
+			const { contract, accounts } = await loadFixture(setupFixture)
 
 			expect(await contract.totalSupply()).to.equal(0)
 
@@ -52,7 +51,7 @@ describe("BasicERC20", () => {
 		})
 
 		it("Should Allow Only Owner to Mint Tokens", async () => {
-			const { contract, accounts } = await setupFixture()
+			const { contract, accounts } = await loadFixture(setupFixture)
 
 			await expect(contract.connect(accounts[1]).mint(accounts[1].address, 1000))
 				.to.be.revertedWithCustomError(contract, "OwnableUnauthorizedAccount")

+ 20 - 21
test/BasicERC721.ts

@@ -1,28 +1,27 @@
 import { expect } from "chai"
-import { deployments, ethers, getNamedAccounts } from "hardhat"
+import { ethers } from "hardhat"
 import { makeInterfaceId } from "@openzeppelin/test-helpers"
+import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers"
 
 describe("BasicERC721", () => {
-	const setupFixture = deployments.createFixture(async () => {
-		await deployments.fixture()
-		const signers = await getNamedAccounts()
+	const setupFixture = async () => {
+		const signers = await ethers.getSigners()
 
 		const name = "ProtoToken"
 		const symbol = "PT"
 		const baseURI = "ipfs://base-uri/"
 		const contractURI = "ipfs://contract-uri"
-		const owner = signers.deployer
+		const owner = signers[0].address
 
-		const contract = await ethers.deployContract(
-			"BasicERC721",
-			[name, symbol, baseURI, contractURI, owner],
-			await ethers.getSigner(signers.deployer)
-		)
+		const BasicERC721 = await ethers.getContractFactory("BasicERC721")
+		const contract = await BasicERC721.deploy(name, symbol, baseURI, contractURI, owner, {
+			from: owner,
+		})
 
 		return {
 			contract,
 			contractAddress: await contract.getAddress(),
-			deployer: signers.deployer,
+			deployer: owner,
 			accounts: await ethers.getSigners(),
 			contractConstructor: {
 				name,
@@ -32,10 +31,10 @@ describe("BasicERC721", () => {
 				owner,
 			},
 		}
-	})
+	}
 
 	it("Should Return Valid Contract Configurations Passed In Constructor", async () => {
-		const { contractConstructor, contract } = await setupFixture()
+		const { contractConstructor, contract } = await loadFixture(setupFixture)
 
 		expect(await contract.name()).to.equal(contractConstructor.name)
 		expect(await contract.symbol()).to.equal(contractConstructor.symbol)
@@ -45,7 +44,7 @@ describe("BasicERC721", () => {
 
 	describe("Minting Functionality", () => {
 		it("Should Increase Total Supply When Minting", async () => {
-			const { contract, deployer } = await setupFixture()
+			const { contract, deployer } = await loadFixture(setupFixture)
 
 			expect(await contract.totalSupply()).to.equal(0)
 
@@ -59,7 +58,7 @@ describe("BasicERC721", () => {
 		})
 
 		it("Should Mint Tokens With Correct Token IDs", async () => {
-			const { contract, accounts } = await setupFixture()
+			const { contract, accounts } = await loadFixture(setupFixture)
 
 			await contract.safeMint(await accounts[0].getAddress())
 
@@ -73,7 +72,7 @@ describe("BasicERC721", () => {
 		})
 
 		it("Should Allow Minting Only to Contract Owner", async () => {
-			const { contract, accounts } = await setupFixture()
+			const { contract, accounts } = await loadFixture(setupFixture)
 
 			await expect(contract.connect(accounts[1]).safeMint(await accounts[1].getAddress()))
 				.to.be.revertedWithCustomError(contract, "OwnableUnauthorizedAccount")
@@ -83,7 +82,7 @@ describe("BasicERC721", () => {
 
 	describe("Contract And Token Metadata", () => {
 		it("Should Return Correct Token URI", async () => {
-			const { contract, accounts, contractConstructor } = await setupFixture()
+			const { contract, accounts, contractConstructor } = await loadFixture(setupFixture)
 
 			await contract.safeMint(await accounts[0].getAddress())
 
@@ -91,7 +90,7 @@ describe("BasicERC721", () => {
 		})
 
 		it("Should Return Correct Token URI", async () => {
-			const { contract } = await setupFixture()
+			const { contract } = await loadFixture(setupFixture)
 
 			await expect(contract.tokenURI(1))
 				.to.be.revertedWithCustomError(contract, "ERC721NonexistentToken")
@@ -99,7 +98,7 @@ describe("BasicERC721", () => {
 		})
 
 		it("Should Return Correct Contract URI", async () => {
-			const { contract, contractConstructor } = await setupFixture()
+			const { contract, contractConstructor } = await loadFixture(setupFixture)
 
 			expect(await contract.contractURI()).to.equal(contractConstructor.contractURI)
 		})
@@ -107,7 +106,7 @@ describe("BasicERC721", () => {
 
 	describe("InterfaceId", () => {
 		it("Should Validate IERC721", async () => {
-			const { contract } = await setupFixture()
+			const { contract } = await loadFixture(setupFixture)
 
 			const erc721InterfaceId = makeInterfaceId.ERC165([
 				"balanceOf(address)",
@@ -125,7 +124,7 @@ describe("BasicERC721", () => {
 		})
 
 		it("Should Validate IERC721Enumerable", async () => {
-			const { contract } = await setupFixture()
+			const { contract } = await loadFixture(setupFixture)
 
 			const erc721EnumerableInterfaceId = makeInterfaceId.ERC165([
 				"totalSupply()",

Vissa filer visades inte eftersom för många filer har ändrats