-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: hardhat project that uses OZ ERC721 implementation
- Loading branch information
Showing
8 changed files
with
279 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
/artifacts | ||
/cache |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
# ERC721 Hardhat Demo | ||
|
||
This project contains a [non-fungible token](https://eips.ethereum.org/EIPS/eip-721) implementation | ||
that inherits from [OpenZeppelin's ERC721 implementation](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721). | ||
|
||
It uses the hardhat development framework to: | ||
|
||
- Compile | ||
- Test | ||
- Deploy | ||
- Verify | ||
|
||
the smart contract. | ||
|
||
Compilation and testing occur on `localhost`; | ||
whereas deployment and verification occur on Hedera Testnet (a public network). | ||
|
||
This project has been designed as a minimal example demonstration; | ||
and a starting point for projects. | ||
|
||
## Compile | ||
|
||
```shell | ||
npm run compile | ||
``` | ||
|
||
## Test | ||
|
||
```shell | ||
npm run test | ||
``` | ||
|
||
## Deploy | ||
|
||
```shell | ||
npm run deploy | ||
``` | ||
|
||
Then visit Hashscan (a Hedera network explorer) at the URL that is output, for example: | ||
[`https://hashscan.io/testnet/contract/0x6eae9247C122b3e3CDC621F61F757B809bF7455a`](https://hashscan.io/testnet/contract/0x6eae9247C122b3e3CDC621F61F757B809bF7455a). | ||
|
||
Under the *Contract Bytecode* section, you should see the EVM bytecode for this smart contract. | ||
|
||
## Verify | ||
|
||
```shell | ||
npm run verify | ||
``` | ||
|
||
Then visit Hashscan (a Hedera network explorer) at the URL that is output, for example: | ||
[`https://hashscan.io/testnet/contract/0x6eae9247C122b3e3CDC621F61F757B809bF7455a`](https://hashscan.io/testnet/contract/0x6eae9247C122b3e3CDC621F61F757B809bF7455a). | ||
|
||
Under the *Contract Bytecode* section, you should still see the EVM bytecode for this smart contract; | ||
and you show also see the Solidity source code as well. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.20; | ||
|
||
import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; | ||
|
||
contract MyNonFungibleToken is ERC721 { | ||
uint256 public tokenId = 0; | ||
|
||
constructor() ERC721("bguiz non fungible token", "BGZNFT") { | ||
create(); | ||
} | ||
|
||
function create() | ||
public | ||
returns (uint256) | ||
{ | ||
tokenId += 1; | ||
_mint(msg.sender, tokenId); | ||
return tokenId; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
const path = require('node:path'); | ||
|
||
const dotEnvPath = path.resolve(__dirname, '../.env'); | ||
require('dotenv').config({ | ||
path: dotEnvPath, | ||
}); | ||
|
||
// populates hre.ethers, hre.waffle, enables typechain, etc | ||
require('@nomicfoundation/hardhat-toolbox'); | ||
require('@nomicfoundation/hardhat-chai-matchers'); | ||
|
||
/* | ||
Set up a JSON-RPC endpoint for this project to connect to Hedera Testnet. | ||
Ref: https://docs.hedera.com/hedera/tutorials/more-tutorials/json-rpc-connections/ | ||
*/ | ||
const rpcUrlHederatestnet = process.env.RPC_URL_HEDERATESTNET; | ||
if (!rpcUrlHederatestnet || !rpcUrlHederatestnet.startsWith('http')) { | ||
throw new Error( | ||
'Missing RPC URL in RPC_URL_HEDERATESTNET env var', | ||
); | ||
} | ||
|
||
/* | ||
Issue the following command to generate a BIP-39 seed phrase | ||
and save it in the env file: | ||
npx [email protected] | ||
*/ | ||
const seedPhrase = process.env.BIP39_SEED_PHRASE; | ||
if (!seedPhrase || seedPhrase.split(' ').length < 12) { | ||
throw new Error( | ||
'Missing BIP-39 seed phrase in BIP39_SEED_PHRASE env var', | ||
); | ||
} | ||
|
||
const accounts = { | ||
mnemonic: seedPhrase, | ||
// Ref: https://github.com/hashgraph/hedera-sdk-js/blob/1a73f3f1329a48702f2a5170260bd05f186e0ca3/packages/cryptography/src/Mnemonic.js#L34 | ||
path: "m/44'/60'/0'/0", | ||
// path: "m/44'/3030'/0'/0", | ||
initialIndex: 0, | ||
count: 10, | ||
}; | ||
|
||
const hardhatConfig = { | ||
solidity: { | ||
version: '0.8.20', | ||
settings: { | ||
optimizer: { | ||
enabled: true, | ||
runs: 200, | ||
}, | ||
}, | ||
}, | ||
networks: { | ||
hardhat: { | ||
accounts, | ||
}, | ||
hederatestnet: { | ||
chainId: 296, | ||
url: rpcUrlHederatestnet, | ||
gasMultiplier: 1.1, | ||
accounts, | ||
}, | ||
}, | ||
sourcify: { | ||
enabled: true, | ||
apiUrl: 'https://server-verify.hashscan.io', | ||
browserUrl: 'https://repository-verify.hashscan.io', | ||
}, | ||
etherscan: { | ||
enabled: false, | ||
}, | ||
mocha: { | ||
timeout: 6_000_000, | ||
}, | ||
}; | ||
|
||
module.exports = hardhatConfig; | ||
|
||
/* | ||
To verify that we're able to connect to Hedera Testnet successfully: | ||
npx hardhat console --network hederatestnet | ||
OR | ||
npm run console | ||
// latest block number | ||
(await require('hardhat').network.provider.send('eth_getBlockByNumber', ['latest', false])).number | ||
// the default EOA that will be used in deployment transactions | ||
(await hre.ethers.getSigners())[0].address | ||
.exit | ||
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
{ | ||
"name": "erc20-hardhat-demo", | ||
"private": true, | ||
"type": "module", | ||
"version": "0.0.0", | ||
"description": "ERC20 Hardhat Demo", | ||
"main": "index.js", | ||
"scripts": { | ||
"compile": "npx hardhat compile", | ||
"test": "npx hardhat test", | ||
"console:hederatestnet": "npx hardhat console --network hederatestnet", | ||
"console": "npm run console:hederatestnet", | ||
"deploy:hederatestnet": "npx hardhat run --network hederatestnet scripts/deploy.js", | ||
"deploy": "npm run deploy:hederatestnet", | ||
"verify:hederatestnet": "npx hardhat run --network hederatestnet scripts/verify.js", | ||
"verify": "npm run verify:hederatestnet" | ||
}, | ||
"keywords": [ | ||
"hedera" | ||
], | ||
"author": "bguiz", | ||
"license": "MIT", | ||
"devDependencies": { | ||
"@nomicfoundation/hardhat-chai-matchers": "2.0.3", | ||
"@nomicfoundation/hardhat-toolbox": "4.0.0", | ||
"@openzeppelin/contracts": "5.0.1", | ||
"dotenv": "16.3.1", | ||
"hardhat": "2.19.4" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import path from 'node:path'; | ||
import fs from 'node:fs/promises'; | ||
import { fileURLToPath } from 'node:url'; | ||
import hre from 'hardhat'; | ||
|
||
async function main() { | ||
const scName = 'MyNonFungibleToken'; | ||
const MyFungibleToken = await ethers.getContractFactory(scName); | ||
console.log('Deploying...'); | ||
const myFungibleToken = await MyFungibleToken.deploy(); | ||
await myFungibleToken.waitForDeployment(); | ||
const deployedAddress = await myFungibleToken.getAddress(); | ||
console.log('Deployed:', deployedAddress); | ||
try { | ||
const dirName = path.dirname(fileURLToPath(import.meta.url)); | ||
const filePath = path.resolve(dirName, '../cache/deploy.json'); | ||
const fileContents = { | ||
[hre.network.name]: { | ||
[scName]: { | ||
deployedAddress, | ||
}, | ||
}, | ||
}; | ||
await fs.writeFile(filePath, JSON.stringify(fileContents, undefined, 2)); | ||
} catch (ex) { | ||
console.error(ex); | ||
} | ||
const hashscanNetworkName = (hre.network.name).replace('hedera', ''); | ||
console.log(`${scName} - https://hashscan.io/${hashscanNetworkName}/contract/${deployedAddress}`); | ||
} | ||
|
||
main(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import path from 'node:path'; | ||
import fs from 'node:fs/promises'; | ||
import { fileURLToPath } from 'node:url'; | ||
import hre from 'hardhat'; | ||
import util from 'node:util'; | ||
import { exec } from 'node:child_process'; | ||
|
||
const childProcessExecAsPromise = util.promisify(exec); | ||
|
||
async function main() { | ||
const scName = 'MyNonFungibleToken'; | ||
try { | ||
const dirName = path.dirname(fileURLToPath(import.meta.url)); | ||
const filePath = path.resolve(dirName, '../cache/deploy.json'); | ||
const fileContentsRaw = await fs.readFile(filePath); | ||
const fileContents = JSON.parse(fileContentsRaw); | ||
const deployments = fileContents[hre.network.name]; | ||
Object.keys(deployments).forEach(async (scName) => { | ||
const deployedAddress = deployments[scName].deployedAddress; | ||
console.log('Verifying', scName, 'at', deployedAddress, 'on', hre.network.name, '...'); | ||
await hre.run('verify:sourcify', { | ||
address: deployedAddress, | ||
}); | ||
const hashscanNetworkName = (hre.network.name).replace('hedera', ''); | ||
console.log(`${scName} - https://hashscan.io/${hashscanNetworkName}/contract/${deployedAddress}`); | ||
}); | ||
} catch (ex) { | ||
console.error(ex); | ||
} | ||
} | ||
|
||
main(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { expect } from 'chai'; | ||
import hre from 'hardhat'; | ||
|
||
describe('MyNonFungibleToken', function () { | ||
it('should have an initial supply', async function () { | ||
const [account1] = await hre.ethers.getSigners(); | ||
const acount1Adress = await account1.getAddress(); | ||
const myNonFungibleToken = await hre.ethers.deployContract('MyNonFungibleToken'); | ||
|
||
const [ownerOfNft1] = await myNonFungibleToken.ownerOf.staticCallResult(1n); | ||
expect(ownerOfNft1).to.equal(acount1Adress); | ||
}); | ||
}); |