Using Hardhat for Solidity and EthereumWe often avoid those pesky Graphical User Interfaces (GUI) and find a way to drop to a Command Line Interface (CLI). And so in Ethereum testing, we can use Remix and Ganache, but they take a bit of control away from the user. Here we see Remix being used to test a function in a smart contract [here]: But there’s another way … the Hardhat way: With Hardhat, we use command-line tools to create the compilation, testing and deployment of our code. This makes the whole process easier to script and automate. After installing Hardhat, we can check the accounts that it has created for us: % npx hardhat accounts 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC 0x90F79bf6EB2c4f870365E785982E1f101E93b906 0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65 0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc 0x976EA74026E726554dB657fA54763abd0C3a0aa9 0x14dC79964da2C08b23698B3D3cc7Ca32193d9955 We can then create a new folder and then run Hardhat: mkdir scrambled cd scrambled npx hardhat This creates a new project for us: and which contains our project files: scrambled % ls README.md node_modules scripts contracts package-lock.json test hardhat.config.js package.json The contracts folder is where we put our contracts, and the test folder is where we put our tests. First, let’s add our contract: cd contacts rm Greeter.sol nano scrambled.sol We then add the following to the contract: pragma solidity ^0.8.0; // SPDX-License-Identifier: MIT contract Scrambled { function scramble() view public returns (string memory) { string [5] memory phrases=["The future of the Internet, especially in expanding the range of applications, involves a much deeper degree of privacy, and authentication.", "The future is thus towards data encryption which is the science of cryptographics, and provides a mechanism for two entities to communicate securely with any other entity being able to read their messages.", "Typically all that is required is a reliable network connection. Our world is changing by the day, as traditional forms of business are being replaced, in many cases, by more reliable and faster ways of operating.", "It is one which, unlike earlier ages, encapsulates virtually the whole World. It is also one which allows the new industries to be based in any location without requiring any natural resources, or to be in any actual physical locations.", "With voting, the slow and cumbersome task of marking voting papers with the preferred candidate, is now being replaced by electronic voting. The traditional systems, though, have been around for hundreds if not thousands of years, and typically use well tried-and-tested mechanisms."]; string [26] memory alphabet=['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r', 's','t','u','v','w','x','y','z']; for (uint256 i = 0; i < alphabet.length; i++) { uint256 j=random(26,i); string memory tmp=alphabet[i]; alphabet[i]=alphabet[j]; alphabet[j]=tmp; } string memory scrambled=""; for (uint256 i = 0; i < alphabet.length; i++) { scrambled=string(abi.encodePacked(scrambled, alphabet[i])); } bytes memory word=bytes(_toLower(phrases[random(phrases.length,0)])); bytes memory map=bytes(scrambled); string memory rtn="Find the message from: "; for (uint256 i=0;i<word.length;i++) { if (uint8(word[i])<97) rtn=string(abi.encodePacked(rtn, word[i])); else { uint256 pos=uint8(word[i])-uint8(97); rtn=string(abi.encodePacked(rtn, (map[pos]))); } } rtn=string(abi.encodePacked(rtn, "\n\nThe mapping is:\nabcdefghijklmnopqrstuvwxyz\n")); rtn=string(abi.encodePacked(rtn, scrambled)); return string(rtn); } function random(uint number,uint i) view internal returns(uint){ return uint(keccak256(abi.encodePacked(block.timestamp,block.difficulty, msg.sender,uint(i)))) % number; } function _toLower(string memory str) internal pure returns (string memory) { bytes memory byteStr = bytes(str); bytes memory byteLower = new bytes(byteStr.length); for (uint i = 0; i < byteStr.length; i++) { if ((uint8(byteStr[i]) >= 65) && (uint8(byteStr[i]) <= 90)) { byteLower[i] = bytes1(uint8(byteStr[i]) + 32); } else { byteLower[i] = byteStr[i]; } } return string(byteLower); } } We then compile with: % npx hardhat compile Compiled 1 Solidity file successfully This shows that our smart contract has been successfully compiled. Now we go into the test folder, and there is a sample-test.js file. % cd test test % ls sample-test.js test % nano sample-test.js We can now edit this to add the details of the smart contract we have created: const { ethers } = require("hardhat"); describe("Scrambled", function () { it("Just starting it up ...", async function () { const sc = await ethers.getContractFactory("Scrambled"); scram = await sc.deploy(); await scram.deployed(); const chall = await scram.scramble(); console.log(chall); }); }); These use Mocha and which is a JavaScript test framework that integrates with Node.js. Our test in this case find and deploy the “Scrambled” smart contact, and then call up the scramble() method. We can then test this method with: % npx hardhat test Scrambled Find the message from: rmf dwrwnf yd rmf jhrfnhfr, felfcjkiig jh falkhqjhv rmf nkhvf yd kllijckrjyhe, jhxyixfe k owcm qfflfn qfvnff yd lnjxkcg, khq kwrmfhrjckrjyh. The mapping is: abcdefghijklmnopqrstuvwxyz kzcqfdvmjbuiohylsnerwxpagt ✔ Just starting it up ... (1271ms) 1 passing (1s) Running it again shows a different output (as we select a random phrase each time): % npx hardhat test Scrambled Find the message from: jkfn mvfksw, fne yavj tsq zrglebyvge ftyx vd gtbxksw mvfksw htheby jkfn fne hbedebbeq ztsqkqtfe, ky svj leksw behatzeq li eaezfbvskz mvfksw. fne fbtqkfkvsta yiyfegy, fnvrwn, ntme lees tbvrsq dvb nrsqbeqy kd svf fnvrytsqy vd ietby, tsq fihkztaai rye jeaa fbkeq-tsq-feyfeq gezntskygy. The mapping is: abcdefghijklmnopqrstuvwxyz tlzqedwnkpxagsvhubyfrmjcio ✔ Just starting it up ... (1504ms) 1 passing (2s) And that’s it … cool! Another cool feature is the ability to fallen the smart contact files into one. For this we can use: npx hardhat flatten Once ready, we can then create our own blockchain with: % npx hardhat node Started HTTP and WebSocket JSON-RPC server at http://127.0.0.1:8545/ Accounts ======== WARNING: These accounts, and their private keys, are publicly known. Any funds sent to them on Mainnet or any other live network WILL BE LOST. Account #0: 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266 (10000 ETH) Private Key: 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 Account #1: 0x70997970c51812dc3a010c7d01b50e0d17dc79c8 (10000 ETH) Private Key: 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d Account #2: 0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc (10000 ETH) Private Key: 0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a We can now link our application into this service. |