Bittrees, Inc (BGOV) Equity Contract (based on ERC-1155)
Includes:
- configuration for deploying to any EVM chain
- suite of tests
- run tests locally (via
npm test
) - use Chai matchers from Waffle (instead of OpenZeppelin Test Helpers)
- includes Github Action to run tests
- run gas report
- run code coverage report
- run tests locally (via
- generates TypeScript bindings via TypeChain (in
contract/typechain-types
) - monorepo-ready -- all contract code and tools are in
./contract
to make it easy to add UI or other pieces - solhint linter config (and then install plugin for your editor that supports solhint syntax highlighting)
- format files with Prettier (
npm run style
) - turn on Solidity optimization (1000 means optimize for more high-frequency usage of contract). Compiler Options
- add hardhat-etherscan for verifying contracts on PolygonScan (or Etherscan), which means uploading the source code so it's available for contract users to view/verify. For more info see hardhat-etherscan plugin.
- in VSCode, optionally run your whole environment in a Docker container (config in
.devcontainer
). Learn more about VSCode: Remote Development in Containers
Install dependencies and run tests to make sure things are working.
cd contract
npm install
npm test
npm run test:gas # to also show gas reporting
npm run test:coverage # to show coverage, details in contract/coverage/index.html
Deploying an upgradeable contract is a bit more complex and 3 contracts are required on initial deploy.
There are two deploy scenarios:
- First-time deploy of all 3 contracts.
- Subsequent upgrades of just your 1 contract.
- copy
.env.sample
to.env
. Then view and edit.env
for further instructions on configuring your RPC endpoints, private key and Etherscan API key. - for deploys to testnet, ensure your wallet account has some test currency to deploy. For example, on Polygon you want test MATIC via https://faucet.polygon.technology/ For local testing, Hardhat already provides test currency for you on the local chain.
Scenario 1: First-time deploy of all 3 contracts (Proxy, Admin and your actual contract)
- cd contract
- deploy via
npx hardhat run --network testnet scripts/deploy.js
- once deployed, you'll see
Deployer wallet public key
. Head over to Etherscan (or Polygonscan) and view that account. You'll see 3 contracts recently deployed.- The first chronologically deployed contract is yours (example: https://mumbai.polygonscan.com/address/0xc858c56f9137aea2508474aa17658de460febb7d#code). Let's call this
CONTRACT_ADDRESS
. - The second contract is called "ProxyAdmin" (example: https://mumbai.polygonscan.com/address/0xec34f10619f7c0cf30d92d17993e10316a01c884#code).
- The third is called "TransparentUpgradeableProxy" (example: https://mumbai.polygonscan.com/address/0xbf1774e5ba0fe942c7498b67ff93c509b723eb67#code) and this is the address that matches the
OpenZeppelin Proxy deployed to
in the output after running the deploy script. Let's call thisPROXY_ADDRESS
.
- The first chronologically deployed contract is yours (example: https://mumbai.polygonscan.com/address/0xc858c56f9137aea2508474aa17658de460febb7d#code). Let's call this
- upload source code so others can verify it on-chain via
npx hardhat verify --network testnet CONTRACT_ADDRESS
. Head back to Etherscan or Polygonscan and view #1 again. You should now see actual source code in the contract. PROXY_ADDRESS
is that actual address used to interact with the contract, view on OpenSea, etc.- you can interact manually via the console -- see Playing with Contract below
- you can interact with on Etherscan or Polygonscan
- IMPORTANT You'll notice new files in
.openzeppelin
folder. It's important you keep these files and check them into the repository. They are required for upgrading the contract.
Scenario 2: Upgrade your contract
If you upgrade contract without making any changes, the system will continue to use currently deployed version.
- cd contract
- update
UPGRADEABLE_PROXY_ADDRESS
environment variables in.env
and set to thePROXY_ADDRESS
from above. This is always the Proxy contract address which doesn't change. Only theCONTACT_ADDRESS
changes when upgrading. - upgrade via
npx hardhat run --network testnet scripts/deploy-upgrade.js
- find the newly deployed contract (
CONTRACT_ADDRESS
) from steps above. You'll find the newest contract recently deployed by the deployer wallet labeled as "Contract Creation". - upload source code so others can verify it on-chain via
npx hardhat verify --network testnet CONTRACT_ADDRESS
. Head back to Etherscan or Polygonscan and view #1 again. You should now see actual source code in the contract. PROXY_ADDRESS
is that actual address used to interact with the contract, view on OpenSea, etc.- you can interact manually via the console -- see Playing with Contract below
- you can interact with on Etherscan or Polygonscan
- IMPORTANT You'll notice changed files in
.openzeppelin
folder. It's important you keep these files and check them into the repository. They are required for upgrading the contract.
First, set transfer ProxyAdmin to Gnosis Safe -- update scripts/transfer-ownership.js
with Safe address.
npx hardhat run --network testnet scripts/transfer-ownership.js
Second, propose upgrade:
npx hardhat run --network testnet scripts/propose-upgrade.js
This will create the new implementation contract (under the deployer wallet), which you can verify:
# for example:
npx hardhat verify --network testnet 0xB715b1824fd05044F773a9f72E44d3ca0c123461
Lastly, go into Defender and approve upgrade.
If you're happy with everything after testing locally and on testnet, it's time to deploy to production on Mainnet.
Use same instructions above for deploying to testnet but use --network mainnet
command option instead.
You can interact with the contract directly in two ways:
-
on Etherscan or Polygonscan
-
You can interact with your contract in real-time via the Hardhat console.
- First you connect to your contract
- Then you interact with your contract
If you want to go the console route:
First, Connect to your Contract
Running console session on testnet
- If you deployed contract to testnet, find your contract address, then just run
npx hardhat console --network testnet
. - Jump down to the example interactive console session.
Running console session on mainnet
- If you deployed contract to mainnet, find your contract address, then just run
npx hardhat console --network mainnet
. - Jump down to the example interactive console session.
Second, Interact with your Contract
Now that you've connected to your contract above via hardhat console
, let's play with it.
// first let's ensure we have the right wallet
// run `listAccounts`
// - if you're running on local hardhat you'll see a bunch of accounts created
// - if you're interacting with a contract on testnet or mainnet and you should see your public wallet account (the match for your private key in your `.env` file)
await ethers.provider.listAccounts();
const Contract = await ethers.getContractFactory('BittreesResearchEquity');
const contract = await Contract.attach('<proxy contract address goes here>');
await contract.setMintPrice('1000000000000000'); // this wei represents 0.001 whole coin (e.g. ETH or MATIC)
// you'll need to wait a bit until value is stored on the blockchain before retrieving in next step
await contract.mintPrice();
// let's mint an NFT using our same owner who deployed the contract for convenience
const owner = (await ethers.provider.listAccounts())[0];
await contract.mintItem(owner, {value: '1000000000000000'});
await contract.ownerOf(1);
Head over to Etherscan or Polygonscan, find your CONTRACT_ADDRESS
, click "contact" then "write", and run the mintItem
function to mint a new NFT. Use 0.001
for price (has to be >= mintPrice) and the public wallet address of who will be getting the NFT.
If deployed on Polygon's Mumbai (testnet) you can view by going to https://testnets.opensea.io/assets and filter by MUMBAI chain. You'll see your NFT. Here's an example query.
Which then has a link to the "Unidentified contract - 2l2TWfgZSS" OpenSea collection at https://testnets.opensea.io/collection/unidentified-contract-2l2twfgzss