This series of learning plans:
fist and formost,I want to say thinks to Patrick Collins for this fantastic course
Full Stack Web3 Development with JavaScript
The learning plan was to learn some lessons of this course:
- β Ethers.js Simple Storage
- β Hardhat Simple Storage
- β Hardhat Fund Me
- β NextJS Smart Contract Lottery (Full Stack)
- β [Hardhat DeFi & Aave]
- β NextJS NFT Marketplace (Full Stack)
Daily Updates Include:
- New knowledge encountered in today's study -β π harvest
- My practice (if I had done it) -β π practice
- learning summary and feelings -β π sum & F
lesson 1
5 Mar:
π harvest:
decompile bytecode
docs.ethers
πΉ.use private key in js
PRIVATE_KEY_PASSWORD=password node deploy.js
// clear history
history -c
build a script to encrypt our private key.
πΉ.transaction response and transaction receipts
const deploymentReceipt = await contract.waitForDeployment();
console.log(`Contract deployed to ${await contract.getAddress()}`);
// @ztmy
// transaction receipts and transaction response are different.
// receipt is what you get when you wait for a transaction to finish.
// And then response is just what you initially get.
console.log("Here is the transaction:")
console.log(contract.deploymentTransaction())
console.log("Here is the receipt:")
console.log(deploymentReceipt)
πΉ.create a task
// create a tesk at tesks folder
const { task } = require("hardhat/config")
task("block-number", "Prints the current block number").setAction(
// @ztmy hre: hardhat runtime environment
async (taskArgs, hre) => {
const blockNumber = await hre.ethers.provider.getBlockNumber()
console.log(`Current block number: ${blockNumber}`)
}
)
module.exports = {}
// hardhat.config.js
// import this task
require("./tasks/block-number")
yarn hardhat block-number --network rinkeby
scripts and tasks both can basically do the same thing.
πΉ.hardhat node
# start a local hardhat test net
yarn hardhat node
localhost: {
url: "http://127.0.0.1:8545",
chainId: 31337,
},
πΉ.hardhat console
yarn hardhat console --net work localhost
you can do anything in these consoles(terminal), and they're great ways to quickly test and tinker in interact with contracts.
lesson 2
6 Mar:
π harvest:
πΉ.hardhat unit test
const { ethers } = require("hardhat")
const { expect, assert } = require("chai")
// describe("SimpleStorage", () => {})
describe("SimpleStorage", function () {
let simpleStorageFactory, simpleStorage
beforeEach(async function () {
simpleStorageFactory = await ethers.getContractFactory("SimpleStorage")
simpleStorage = await simpleStorageFactory.deploy()
})
// @ ztmy write a unit test
it("Should start with a favorite number of 0", async function () {
const currentValue = await simpleStorage.retrieve()
const expectedValue = "0"
// assert
// expect
assert.equal(currentValue.toString(), expectedValue)
// expect(currentValue.toString()).to.equal(expectedValue)
})
}
run only specific tests:
yarn hardhat test --grep store
// use only keyword
it.only("Should start with a favorite number of 0", async function ()
πΉ.gas reporter & coinmarketcap ->[t=34730]
gasReporter: {
enabled: true,
currency: "USD",
outputFile: "gas-report.txt",
noColors: true,
// has the USD price of each one of these transactions
coinmarketcap: COINMARKETCAP_API_KEY,
},
πΉ.coverage -> [t=35080]
lesson 3
πΉ.use hardhat to deploy
const fundMe = await deploy("FundMe", {
from: deployer,
args: [ethUsdPriceFeedAddress],
log: true,
// we need to wait if on a live network so we can verify properly
waitConfirmations: network.config.blockConfirmations || 1,
})
πΉ.get recent deoploy & connect
// To get the most recently deployed instance, you'll need the deployed addresses
// You might need to get these from your deployment artifacts or a helper function
const fundMeDeployment = await hre.deployments.get("FundMe");
const mockV3AggregatorDeployment = await hre.deployments.get(
"MockV3Aggregator"
);
// Connect to the deployed contracts with the deployer as signer
fundMe = FundMeFactory.attach(fundMeDeployment.address).connect(
deployer
);
mockV3Aggregator = MockV3AggregatorFactory.attach(
mockV3AggregatorDeployment.address
).connect(deployer);
This sets the signer (wallet) that will be used when sending transactions to this contract. The "deployer" variable is typically a wallet/signer object. When you call methods on this contract that change state (non-view functions), they'll be signed by this deployer account.
// @ztmy connect to other address to test require ower.
it("Only allows the owner to withdraw", async function () {
const accounts = await ethers.getSigners();
const fundMeConnectedContract = await fundMe.connect(accounts[1]);
await expect(fundMeConnectedContract.withdraw()).to.be.revertedWithCustomError(fundMe,
"FundMe__NotOwner"
);
πΉ.Staging Tests
// Staging Tests - Need to be run on an actual test network, such as Sepolia.
developmentChains.includes(network.name)
? describe.skip
: describe("FundMe Staging Tests", function ()
// Unit Tests - run only on local hardhat or localhost.
!developmentChains.includes(network.name)
? describe.skip
: describe("FundMe", function ()
Staging : Testing our code in a real environment that is not prod.this is the last step in your development journey.
lesson 4
7 Mar:
π harvest:
πΉ.Common contract-related Ethers operations
// Get contract factories
const ContractFactory = await ethers.getContractFactory("Contract");
// Get deployment Information
const ContractDeployment = await hre.deployments.get(
"Contract"
);
// Get contract instance
Contract = await ethers.getContractAt(
"Contract",
ContractDeployment.address
)
// Connect to the deployed contracts with the deployer
fundMe = Contract .connect(deployer);
πΉ.get return from Event
// create VRFV2 Subscription
VRFCoordinatorV2_5MockAddress = VRFCoordinatorV2_5MockDeployment.address
const transactionResponse = await VRFCoordinatorV2_5Mock.createSubscription()
const transactionReceipt = await transactionResponse.wait()
// @ztmy transaction After sending a transaction, we can only get a transaction response and cannot get the return value directly.
// @ztmy We can only find Events from the response to get these information
// Query events from the VRFCoordinatorV2_5Mock contract
const events = await VRFCoordinatorV2_5Mock.queryFilter(
// - Use filters.SubscriptionCreated() to only get SubscriptionCreated events
VRFCoordinatorV2_5Mock.filters.SubscriptionCreated()
)
subscriptionId = events[0].args[0]
log(subscriptionId)
8 Mar:
π harvest:
πΉ.Moralis
const { enableWeb3, isWeb3Enabled, isWeb3EnableLoading, account, Moralis, deactivateWeb3 } =
useMoralis()
- lets front-end developers get on-chain data directly without running their own blockchain nodes
- provides Web3 login, wallet connection, transaction query and other functions to simplify dApp development
But no longer update.
πΉ.web3uikit
Beautiful and lightweight UI components for web3 developers.
But no longer update, only support react 18.
πΉ.Front-end stack
- React+Next.js
- Ethers.js/viem/web3j.s
- RainbowKit + wagmi
Now, we can scaffold a RainbowKit(web3uikit) + wagmi(Moralis) + Next.js app as an alternative.
πΉ.create a update-front-end.js
const frontEndContractsFile = "../nextjs-smartcontract-lottery-fcc/constants/contractAddresses.json"
const frontEndAbiFile = "../nextjs-smartcontract-lottery-fcc/constants/abi.json"
async function updateAbi() {
const raffle = await ethers.getContract("Raffle")
fs.writeFileSync(frontEndAbiFile, raffle.interface.format(ethers.utils.FormatTypes.json))
}
...
create a update-front-end.js under the deploy folder, when we redeployment contract, we can run this to automated the process of updating our contract information and pass them to front end codebase.
πΉ.the rest of work
- create a hook entranceFee and show it.
- add notification provider.
- show numPlayers,recentWinner.
- run mockOffchain to test.
- use tailwindcss to Optimized style. ->[t=18.05.55]
- use fleek to deploy front end.
π sum & F
I only learned the basic idea of making a front end, and I will use the latest set of dependencies in my later practice.
lesson 5
9 Mar:
π harvest:
πΉ.Forking
networks: {
hardhat: {
chainId: 31337,
forking: {
url: MAINNET_RPC_URL
}
},
}
const iWeth = await ethers.getContractAt(
"IWeth",
// @ztmy get Contract derictly from forked main net
"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
signer
)
- Pros: Quick, easy, resemble what's on mainnet
- Cons: We need an API, some contracts are complex to work with
πΉ.hardhat-deploy
module.exports = async ({getNamedAccounts, deployments}) => {
const {deploy} = deployments;
const {deployer} = await getNamedAccounts();
await deploy('MyContract', {
from: deployer,
args: ['Hello'],
log: true,
});
};
// only execute deploy scripts with the given tags
module.exports.tags = ['MyContract'];
yarn add --dev hardhat-deploy
We us hardhat-deploy to deploy contract, this is a community plugin.
Community plugins
πΉ.Aave Borrow
- getWeth
- getLendingPool
- approveErc20
- deposit
- getBorrowUserData
- getDaiPrice
- borrowDai
- getBorrowUserData
- repay
- getBorrowUserData
lesson 5
9 Mar:
π harvest:
πΉ.__
πΉ.__
πΉ.__
πΉ.__
πΉ.__
Top comments (0)