Skip to content

Instantly share code, notes, and snippets.

@llSourcell
Last active November 7, 2022 21:08
Show Gist options
  • Save llSourcell/2e7596974ddbf2640466bef088031900 to your computer and use it in GitHub Desktop.
Save llSourcell/2e7596974ddbf2640466bef088031900 to your computer and use it in GitHub Desktop.

Getting Started with Smart Contracts on Polygon PoS (4 parts)

1 Polygon PoS Explained

2 Mint an NFT

3 Stake Polygon Token

4 Create ERC-20 Tokens

Polygon PoS Explained

Polygon is a decentralised Ethereum scaling platform that enables developers to build scalable user-friendly dApps with low transaction fees without ever sacrificing on security. Polygon's live blockchain in production is called Polygon Proof-of-Stake or PoS for short. In this guide, we'll learn how to build and deploy our first Solidity smart contracts to Polygon PoS.

Key Features of Polygon
  • Speed The Polygon Network uses a high-throughput blockchain with consensus provided by a group of Block Producers selected by stakeholders at each checkpoint. A Proof of Stake layer is used to validate blocks and periodically post proofs of Block Producers to the Ethereum mainnet. This enables rapid block confirmation rates of about 2 seconds while preserving a high amount of decentralization, resulting in excellent throughput for the network.
  • Scalability Polygon Network achieves a hypothetical transaction speed of fewer than 2 seconds on a single sidechain. Using multiple sidechains helps the network to handle millions of transactions per second. This mechanism (already demonstrated in the first Matic sidechain) allows the Polygon network to scale easily.
  • Security Polygon's smart contracts rely on Ethereum’s security. To safeguard the network, it employs three critical security models. It uses Ethereum's staking management contracts and a group of incentivized validators running Heimdall and Bor nodes. Developers can also implement both models (Hybrid) into their dApp.

Building on Polygon

If you are an Ethereum developer, you are already a Polygon developer. Simply switch to the Polygon RPC and get started. All the tools you are familiar with on the Ethereum blockchain are supported on Polygon by default, such as Truffle, Remix, and Web3js.

You can deploy decentralized applications to either Polygon Mumbai Testnet or the Mainnet. The Polygon Mumbai Testnet connects with the Ethereum GoΓ«rli Testnet, which acts as its ParentChain. You can find all the network-related details in the network documentation.

Deploying to the Polygon Network

Wallets

To interact with the Polygon Network, you need to have an Ethereum-based wallet because Polygon runs on Ethereum Virtual Machine (EVM). You can choose to set up a Metamask or Arkane Wallet. More information on wallet-related details and why you need one can be found in our wallet documentation.

Smart Contracts

Polygon supports many services you can use to test, compile, debug, and deploy decentralized applications onto the Polygon Network. These include deployment using Alchemy, Chainstack, QuickNode, Remix, Truffle, Hardhat, and Replit.

Connecting to Polygon

You can add Polygon to Metamask or directly use Arkane, which allows you to connect to Polygon using RPC.

In order to connect with the Polygon network to read blockchain information, we recommend using the Alchemy SDK.
{
// Javascript
// Setup: npm install alchemy-sdk
const { Alchemy, Network } = require("alchemy-sdk");

const settings = {
  apiKey: "demo", // Can replace with your API Key from https://www.alchemy.com
  network: Network.MATIC_MAINNET, // Can replace with MATIC_MUMBAI
};

const alchemy = new Alchemy(settings);

async function main() {
  const latestBlock = await alchemy.core.getBlockNumber();
  console.log("The latest block number is", latestBlock);
}

main();

Polygon prides itself in being the ultimate Layer-2 scaling solution for Ethereum. You don't have to worry about the underlying architecture while moving or deploying your dApps to the Polygon Network as long as it is EVM-compatible. Use Polygon as a faster transaction layer: Deploying your dApp to the Polygon Mainnet allows you to leverage Polygon as a faster transaction layer for your dApp. Additionally, you can get your tokens mapped by us. If this is overwhelming, that’s alright! You can jump right into the action and start hacking with 3 solidity tutorials below. You’ve got this!

What is Polygon's consensus engine?

  • A Proof of Work
  • B Proof of Stake
  • C Proof of Storage
  • D Proof of Spacetime

2 Mint your first NFT

🎫 Create a simple NFT to learn basics of Polygon PoS. You'll use πŸ‘·β€β™€οΈ HardHat to compile and deploy smart contracts. Then, you'll use a template React app full of important Polygon components and hooks. Finally, you'll deploy an NFT to a public network to share with friends! πŸš€

🌟 The final deliverable is an app that lets users purchase and transfer NFTs. Deploy your contracts to a testnet then build and upload your app to a public web server.

Checkpoint 0: πŸ“¦ Install πŸ“š

Required:

  • Git
  • Node (🧨 Currently use Node v16 as v17 & v18 are unstable 🧨)
  • Yarn

(⚠️ Don't install the linux package yarn make sure you install yarn with npm i -g yarn or even sudo npm i -g yarn!)

git clone https://github.com/llsourcell/scaffold-eth-challenges.git challenge-0-simple-nft
cd challenge-0-simple-nft
git checkout challenge-0-simple-nft
yarn install
yarn chain

in a second terminal window, start your πŸ“± frontend:

cd challenge-0-simple-nft
yarn start

in a third terminal window, πŸ›° deploy your contract:

cd challenge-0-simple-nft
yarn deploy 

You can yarn deploy --reset to deploy a new contract any time.

πŸ“± Open http://localhost:3000 to see the app


Checkpoint 1: ⛽️ Gas & Wallets πŸ‘›

⛽️ You'll need to get some funds from the faucet for gas.

image

🦊 At first, please don't connect MetaMask. If you already connected, please click logout:

image

πŸ”₯ We'll use burner wallets on localhost...

πŸ‘› Explore how burner wallets work by opening a new incognito window and navigate it to http://localhost:3000. You'll notice it has a new wallet address in the top right. Copy the incognito browsers' address and send localhost test funds to it from your first browser:

image

πŸ‘¨πŸ»β€πŸš’ When you close the incognito window, the account is gone forever. Burner wallets are great for local development but you'll move to more permanent wallets when you interact with public networks.


Checkpoint 2: πŸ–¨ Minting

✏️ Mint some NFTs! Click the MINT NFT button in the YourCollectables tab.

MintNFT

πŸ‘€ You should see your collectibles start to show up:

nft3

πŸ‘› Open an incognito window and navigate to http://localhost:3000

🎟 Transfer an NFT to the incognito window address using the UI:

nft5

πŸ‘› Try to mint an NFT from the incognito window.

Can you mint an NFT with no funds in this address? You might need to grab funds from the faucet to pay the gas!

πŸ•΅πŸ»β€β™‚οΈ Inspect the Debug Contracts tab to figure out what address is the owner of YourCollectible?

πŸ” You can also check out your smart contract YourCollectible.sol in packages/hardhat/contracts.

πŸ’Ό Take a quick look at your deploy script 00_deploy_your_contract.js in packages/hardhat/deploy.

πŸ“ If you want to make frontend edits, open App.jsx in packages/react-app/src.


Checkpoint 3: πŸ’Ύ Deploy it! πŸ›°

πŸ›° Ready to deploy to a public testnet?!?

Change the defaultNetwork in packages/hardhat/hardhat.config.js to mumbai

networkSelect

πŸ” Generate a deployer address with yarn generate

nft7

πŸ‘› View your deployer address using yarn account

nft8

⛽️ Use a faucet like https://faucet.polygon.technology/ or https://faucet.polygon.technology/ to fund your deployer address.

βš”οΈ Side Quest: Keep a πŸ§‘β€πŸŽ€ punkwallet.io on your phone's home screen and keep it loaded with testnet eth. πŸ§™β€β™‚οΈ You'll look like a wizard when you can fund your deployer address from your phone in seconds.

πŸš€ Deploy your NFT smart contract:

yarn deploy

πŸ’¬ Hint: You can set the defaultNetwork in hardhat.config.js to mumbai OR you can yarn deploy --network mumbai.


Checkpoint 4: 🚒 Ship it! 🚁

✏️ Edit your frontend App.jsx in packages/react-app/src to change the targetNetwork to NETWORKS.mumbai:

image

You should see the correct network in the frontend (http://localhost:3000):

nft10

🦊 At this moment, you will need to connect the dapp to a browser wallet where you have some ether available to mint tokens. Keep in mind that the address you generated in the previous step to deploy the contract will likely be different from the one you have configured in your wallet.

🎫 Ready to mint a batch of NFTs for reals? Use the MINT NFT button.

MintNFT2

πŸ“¦ Build your frontend:

yarn build

πŸ’½ Upload your app to surge:

yarn surge

(You could also yarn s3 or maybe even yarn ipfs?)

😬 Windows users beware! You may have to change the surge code in packages/react-app/package.json to just "surge": "surge ./build",

βš™ If you get a permissions error yarn surge again until you get a unique URL, or customize it in the command line.

⚠️ Run the automated testing function to make sure your app passes

yarn test

testOutput


Checkpoint 5: πŸ“œ Contract Verification

Update the api-key in packages/hardhat/package.json file. You can get your key here.

Screen Shot 2021-11-30 at 10 21 01 AM

Now you are ready to run the yarn verify --network your_network command to verify your contracts on etherscan πŸ›°

It is okay if it says your contract is already verified. Copy the address of YourCollectable.sol and search it on mumbai polygonscan to find the correct URL you need to submit this challenge.


Checkpoint 6: πŸ’ͺ Flex!

πŸ‘©β€β€οΈβ€πŸ‘¨ Share your public url with a friend and ask them for their address to send them a collectible :)

nft15


How many times can an NFT be replicated?

  • A Once
  • B Never
  • C Infinitely
  • D Twice

3 Stake Polygon

A superpower of Polygon is allowing you, the builder, to create a simple set of rules that an adversarial group of players can use to work together. In this challenge, you create a decentralized application where users can coordinate a group funding effort. If the users cooperate, the money is collected in a second smart contract. If they defect, the worst that can happen is everyone gets their money back. The users only have to trust the code.

🏦 Build a Staker.sol contract that collects ETH from numerous addresses using a payable stake() function and keeps track of balances. After some deadline if it has at least some threshold of ETH, it sends it to an ExampleExternalContract and triggers the complete() action sending the full balance. If not enough ETH is collected, allow users to withdraw().

πŸŽ› Building the frontend to display the information and UI is just as important as writing the contract. The goal is to deploy the contract and the app to allow anyone to stake using your app. Use a Stake(address,uint256) event to all stakes.

🌟 The final deliverable is deploying a Dapp that lets users send ether to a contract and stake if the conditions are met, then yarn build and yarn surge your app to a public webserver.


Checkpoint 0: πŸ“¦ install πŸ“š

git clone https://github.com/llsourcell/scaffold-eth-challenges.git challenge-1-decentralized-staking

cd challenge-1-decentralized-staking

git checkout challenge-1-decentralized-staking

yarn install

πŸ” Edit your smart contract Staker.sol in packages/hardhat/contracts


Checkpoint 1: πŸ”­ Environment πŸ“Ί

You'll have three terminals up for:

yarn start   (react app frontend)
yarn chain   (hardhat backend)
yarn deploy  (to compile, deploy, and publish your contracts to the frontend)

πŸ’» View your frontend at http://localhost:3000/

πŸ‘©β€πŸ’» Rerun yarn deploy --reset whenever you want to deploy new contracts to the frontend.


Checkpoint 2: πŸ₯© Staking πŸ’΅

You'll need to track individual balances using a mapping:

mapping ( address => uint256 ) public balances;

And also track a constant threshold at 1 ether

uint256 public constant threshold = 1 ether;

πŸ‘©β€πŸ’» Write your stake() function and test it with the Debug Contracts tab in the frontend

πŸ’Έ Need more funds from the faucet? Enter your frontend address into the wallet to get as much as you need! Wallet_Medium

✏ Need to troubleshoot your code? If you import hardhat/console.sol to your contract, you can call console.log() right in your Solidity code. The output will appear in your yarn chain terminal.

πŸ₯… Goals

  • Do you see the balance of the Staker contract go up when you stake()?
  • Is your balance correctly tracked?
  • Do you see the events in the Staker UI tab?

Checkpoint 3: πŸ”¬ State Machine / Timing ⏱

βš™οΈ Think of your smart contract like a state machine. First, there is a stake period. Then, if you have gathered the threshold worth of ETH, there is a success state. Or, we go into a withdraw state to let users withdraw their funds.

Set a deadline of block.timestamp + 30 seconds

uint256 public deadline = block.timestamp + 30 seconds;

πŸ‘¨β€πŸ« Smart contracts can't execute automatically, you always need to have a transaction execute to change state. Because of this, you will need to have an execute() function that anyone can call, just once, after the deadline has expired.

πŸ‘©β€πŸ’» Write your execute() function and test it with the Debug Contracts tab

Check the ExampleExternalContract.sol for the bool you can use to test if it has been completed or not. But do not edit the ExampleExternalContract.sol as it can slow the auto grading.

If the address(this).balance of the contract is over the threshold by the deadline, you will want to call: exampleExternalContract.complete{value: address(this).balance}()

If the balance is less than the threshold, you want to set a openForWithdraw bool to true and allow users to withdraw() their funds.

(You'll have 30 seconds after deploying until the deadline is reached, you can adjust this in the contract.)

πŸ‘©β€πŸ’» Create a timeLeft() function including public view returns (uint256) that returns how much time is left.

⚠️ Be careful! if block.timestamp >= deadline you want to return 0;

⏳ The time will only update if a transaction occurs. You can see the time update by getting funds from the faucet just to trigger a new block.

πŸ‘©β€πŸ’» You can call yarn deploy --reset any time you want a fresh contract

πŸ₯… Goals

  • Can you see timeLeft counting down in the Staker UI tab when you trigger a transaction with the faucet?
  • If you stake() enough ETH before the deadline, does it call complete()?
  • If you don't stake() enough can you withdraw() your funds?

Checkpoint 4: πŸ’΅ Receive Function / UX πŸ™Ž

πŸŽ€ To improve the user experience, set your contract up so it accepts ETH sent to it and calls stake(). You will use what is called the receive() function.

Use the receive() function in solidity to "catch" ETH sent to the contract and call stake() to update balances.


πŸ₯… Goals

  • If you send ETH directly to the contract address does it update your balance?

βš”οΈ Side Quests

  • Can execute get called more than once, and is that okay?
  • Can you stake and withdraw freely after the deadline, and is that okay?
  • What are other implications of anyone being able to withdraw for someone?

🐸 It's a trap!

  • Make sure funds can't get trapped in the contract! Try sending funds after you have executed! What happens?
  • Try to create a modifier called notCompleted. It will check that ExampleExternalContract is not completed yet. Use it to protect your execute and withdraw functions.

⚠️ Test it!

  • Now is a good time to run yarn test to run the automated testing function. It will test that you hit the core checkpoints. You are looking for all green checkmarks and passing tests!

Checkpoint 5: 🚒 Ship it 🚁

πŸ“‘ Edit the defaultNetwork to your choice of public EVM networks in packages/hardhat/hardhat.config.js

πŸ‘©β€πŸš€ You will want to run yarn account to see if you have a deployer address

πŸ” If you don't have one, run yarn generate to create a mnemonic and save it locally for deploying.

⛽️ You will need to send ETH to your deployer address with your wallet.

πŸ“ If you plan on submitting this challenge, be sure to set your deadline to at least block.timestamp + 72 hours

πŸš€ Run yarn deploy to deploy your smart contract to a public network (selected in hardhat.config.js)


Checkpoint 6: 🎚 Frontend πŸ§˜β€β™€οΈ

πŸ“ Edit the targetNetwork in App.jsx (in packages/react-app/src) to be the public network where you deployed your smart contract.

πŸ’» View your frontend at http://localhost:3000/

πŸ“‘ When you are ready to ship the frontend app...

πŸ“¦ Run yarn build to package up your frontend.

πŸ’½ Upload your app to surge with yarn surge (you could also yarn s3 or maybe even yarn ipfs?)

😬 Windows users beware! You may have to change the surge code in packages/react-app/package.json to just "surge": "surge ./build",

βš™ If you get a permissions error yarn surge again until you get a unique URL, or customize it in the command line.

πŸ“ you will use this deploy URL to submit to SpeedRunEthereum.com.

πŸš” Traffic to your url might break the Infura rate limit, edit your key: constants.js in packages/ract-app/src.


Checkpoint 7: πŸ“œ Contract Verification

Update the api-key in packages/hardhat/package.json file. You can get your key here.

Screen Shot 2021-11-30 at 10 21 01 AM

Now you are ready to run the yarn verify --network your_network command to verify your contracts on etherscan πŸ›°

Why use a faucet?

  • A Developer access to test tokens
  • B Free Money
  • C No reason
  • D Costs money

4 Create an ERC-20 Token

πŸ€– Smart contracts are kind of like "always on" vending machines that anyone can access. Let's make a decentralized, digital currency. Then, let's build an unstoppable vending machine that will buy and sell the currency. We'll learn about the "approve" pattern for ERC20s and how contract to contract interactions work.

🏡 Create YourToken.sol smart contract that inherits the ERC20 token standard from OpenZeppelin. Set your token to _mint() 1000 (* 10 ** 18) tokens to the msg.sender. Then create a Vendor.sol contract that sells your token using a payable buyTokens() function.

πŸŽ› Edit the frontend that invites the user to <input\> an amount of tokens they want to buy. We'll display a preview of the amount of ETH (or USD) it will cost with a confirm button.

πŸ” It will be important to verify your token's source code in the block explorer after you deploy. Supporters will want to be sure that it has a fixed supply and you can't just mint more.

🧫 Everything starts by ✏️ Editing YourToken.sol in packages/hardhat/contracts


Checkpoint 0: πŸ“¦ Install πŸ“š

git clone https://github.com/scaffold-eth/scaffold-eth-challenges challenge-2-token-vendor
cd challenge-2-token-vendor
git checkout challenge-2-token-vendor
yarn install

πŸ” Edit your smart contract YourToken.sol in packages/hardhat/contracts


Checkpoint 1: πŸ”­ Environment πŸ“Ί

You'll have three terminals up for:

yarn chain   (hardhat backend)
yarn start   (react app frontend)
yarn deploy  (to compile, deploy, and publish your contracts to the frontend)

πŸ‘€ Visit your frontend at http://localhost:3000

πŸ‘©β€πŸ’» Rerun yarn deploy --reset whenever you want to deploy new contracts to the frontend.

ignore any warnings, we'll get to that...


Checkpoint 2: 🏡Your Token πŸ’΅

πŸ‘©β€πŸ’» Edit YourToken.sol to inherit the ERC20 token standard from OpenZeppelin

Mint 1000 (* 10 ** 18) to your frontend address using the constructor().

(Your frontend address is the address in the top right of http://localhost:3000)

You can yarn deploy --reset to deploy your contract until you get it right.

πŸ₯… Goals

  • Can you check the balanceOf() your frontend address in the YourToken of the Debug Contracts tab?
  • Can you transfer() your token to another account and check that account's balanceOf?

(Use an incognito window to create a new address and try sending to that new address. Use the transfer() function in the Debug Contracts tab.)


Checkpoint 3: βš–οΈ Vendor πŸ€–

πŸ‘©β€πŸ’» Edit the Vendor.sol contract with a payable buyTokens() function

Use a price variable named tokensPerEth set to 100:

uint256 public constant tokensPerEth = 100;

πŸ“ The buyTokens() function in Vendor.sol should use msg.value and tokensPerEth to calculate an amount of tokens to yourToken.transfer() to msg.sender.

πŸ“Ÿ Emit event BuyTokens(address buyer, uint256 amountOfETH, uint256 amountOfTokens) when tokens are purchased.

Edit deploy/01_deploy_vendor.js to deploy the Vendor (uncomment Vendor deploy lines).

πŸ₯… Goals

  • When you try to buy tokens from the vendor, you should get an error: 'ERC20: transfer amount exceeds balance'

⚠️ this is because the Vendor contract doesn't have any YourTokens yet!

βš”οΈ Side Quest: send tokens from your frontend address to the Vendor contract address and then try to buy them.

✏️ We can't hard code the vendor address like we did above when deploying to the network because we won't know the vendor address at the time we create the token contract.

✏️ So instead, edit YourToken.sol to mint the tokens to the msg.sender (deployer) in the constructor().

✏️ Then, edit deploy/01_deploy_vendor.js to transfer 1000 tokens to vendor.address.

await yourToken.transfer( vendor.address, ethers.utils.parseEther("1000") );

You can yarn deploy --reset to deploy your contract until you get it right.

(You will use the YourToken UI tab and the frontend for most of your testing. Most of the UI is already built for you for this challenge.)

πŸ₯… Goals

  • Does the Vendor address start with a balanceOf 1000 in YourToken on the Debug Contracts tab?
  • Can you buy 10 tokens for 0.1 ETH?
  • Can you transfer tokens to a different account?

πŸ“ Edit Vendor.sol to inherit Ownable.

In deploy/01_deploy_vendor.js you will need to call transferOwnership() on the Vendor to make your frontend address the owner:

await vendor.transferOwnership("**YOUR FRONTEND ADDRESS**");

πŸ₯… Goals

  • Is your frontend address the owner of the Vendor?

πŸ“ Finally, add a withdraw() function in Vendor.sol that lets the owner withdraw ETH from the vendor.

πŸ₯… Goals

  • Can only the owner withdraw the ETH from the Vendor?

βš”οΈ Side Quests

  • Can anyone withdraw? Test everything!
  • What if you minted 2000 and only sent 1000 to the Vendor?

Checkpoint 4: πŸ€” Vendor Buyback 🀯

πŸ‘©β€πŸ« The hardest part of this challenge is to build your Vendor to buy the tokens back.

🧐 The reason why this is hard is the approve() pattern in ERC20s.

πŸ˜• First, the user has to call approve() on the YourToken contract, approving the Vendor contract address to take some amount of tokens.

🀨 Then, the user makes a second transaction to the Vendor contract to sellTokens(uint256 amount).

πŸ€“ The Vendor should call yourToken.transferFrom(msg.sender, address(this), theAmount) and if the user has approved the Vendor correctly, tokens should transfer to the Vendor and ETH should be sent to the user.

πŸ“ Edit Vendor.sol and add a sellTokens(uint256 amount) function!

⚠️ You will need extra UI for calling approve() before calling sellTokens(uint256 amount).

πŸ”¨ Use the Debug Contracts tab to call the approve and sellTokens() at first but then...

πŸ” Look in the App.jsx for the extra approve/sell UI to uncomment!

πŸ₯… Goal

  • Can you sell tokens back to the vendor?
  • Do you receive the right amount of ETH for the tokens?

βš”οΈ Side Quest

  • Should we disable the owner withdraw to keep liquidity in the Vendor?
  • It would be a good idea to display Sell Token Events. Create the event and emit it in your Vendor.sol and look at buyTokensEvents in your App.jsx for an example of how to update your frontend.

⚠️ Test it!

  • Now is a good time to run yarn test to run the automated testing function. It will test that you hit the core checkpoints. You are looking for all green checkmarks and passing tests!

Checkpoint 5: πŸ’Ύ Deploy it! πŸ›°

πŸ“‘ Edit the defaultNetwork in packages/hardhat/hardhat.config.js, as well as targetNetwork in packages/react-app/src/App.jsx, to your choice of public EVM networks

πŸ‘©β€πŸš€ You will want to run yarn account to see if you have a deployer address.

πŸ” If you don't have one, run yarn generate to create a mnemonic and save it locally for deploying.

πŸ›° Use a faucet like faucet.paradigm.xyz to fund your deployer address (run yarn account again to view balances)

πŸš€ Run yarn deploy to deploy to your public network of choice (πŸ˜… wherever you can get ⛽️ gas)

πŸ”¬ Inspect the block explorer for the network you deployed to... make sure your contract is there.


Checkpoint 6: 🚒 Ship it! 🚁

πŸ“¦ Run yarn build to package up your frontend.

πŸ’½ Upload your app to surge with yarn surge (you could also yarn s3 or maybe even yarn ipfs?)

😬 Windows users beware! You may have to change the surge code in packages/react-app/package.json to just "surge": "surge ./build",

βš™ If you get a permissions error yarn surge again until you get a unique URL, or customize it in the command line.

πŸš” Traffic to your url might break the Infura rate limit, edit your key: constants.js in packages/react-app/src.


Checkpoint 7: πŸ“œ Contract Verification

Update the api-key in packages/hardhat/package.json. You can get your key here.

Now you are ready to run the yarn verify --network your_network command to verify your contracts on etherscan πŸ›°

πŸ‘€ You may see an address for both YouToken and Vendor. You will want the Vendor address.

Why type of standard is ERC20?

  • A W3C
  • B Ethereum
  • C Mozilla
  • D Brave
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment