This repository contains the smart contract suite used in Polygon's ecosystems. Recent iterations have focused on features for the Edge project. Edge-specific contracts may be spun off into their own repo in the future.
Note: You do not need to clone this repo in order to interact with Polygon POS or any other Polygon ecosystem.
There are a number of different contracts with different roles in the suite, as such an architecture diagram of the contents of contracts/
should be useful in understanding where to find what you're looking for.
One piece of terminology that is useful in understanding the layout and contracts themselves is the references to root
and child
. Chains such as POS and Edge assume that there is a base layer chain that data from other chains is committed to. In the case of POS, the root chain is Ethereum mainnet and the child is Polygon POS, while in the case of Edge, the root chain is Edge and the child chains are the various Supernets.
│ child/ "contracts that live on the child chain"
├─ tokens - "contracts for the bridging/management of native and ERC20/721/1155 assets"
├─ EIP1559Burn - "allows child native token to be burnt on root"
├─ ForkParams - "configurable softfork features read by the client each epoch"
├─ L2StateSender - "arbitrary message bridge (child -> root)"
├─ NetworkParams - "configurable network parameters read by the client each epoch"
├─ StateReceiver — "child chain component of a message bridge"
├─ System - "various infra/precompile addresses on the child chain"
├─ │ validator/ "contracts relating directly to validating"
├─ RewardPool - "reward distribution to validators for committed epochs"
├─ ValidatorSet - "validator voting power management, commits epochs for child chains"
│ common/ "libraries used on both the child and root chains"
├─ BLS - "BLS signature operations"
├─ BN256G2 - "elliptic curve operations on G2 for BN256 (used for BLS)"
├─ Merkle - "checks membership of a hash in a merkle tree"
│ interfaces/ "interfaces for all contracts"
├─ Errors - "commonly reused errors"
│ lib/ "libraries used for specific applications"
├─ AccessList - "checks address membership in protocol-level access controls"
├─ ChildManagerLib - "library for managing child chains on root"
├─ EIP712MetaTransaction - "template for process EIP712 structures"
├─ EIP712Upgradeable - "adapted from OpenZeppelin, allows for upgradeable EIP712 structures"
├─ GenesisLib - "facilitates generation of the validator set at genesis"
├─ ModExp — "modular exponentiation (from Hubble Project, for BLS)"
├─ SafeMathInt - "casts int256 to uint256 and vice versa with over/underflow checks"
├─ StakeManagerLib - "manages validator stake (deposit, withdrawal, etc)"
├─ WithdrawalQueue — "lib of operations for the rewards withdrawal queue"
│ mocks/ "mocks of various contracts for testing"
│ root/ "contracts that live on the root chain (Ethereum mainnet)"
├─ root predicates - "templates for processing asset bridging on root"
├─ | staking "contracts comprising the hub for staking on any child chain"
├─ CustomSupernetManager - "manages validator access, syncs voting power"
├─ StakeManager - "manages stake for all child chains"
├─ SupernetManager - "abstract template for managing Supernets"
├─ CheckpointManager - "receives and executes messages from child"
├─ ExitHelper - "processes exits from stored event roots in CheckpointManager"
├─ StateSender - "sends messages to child"
This repo is a hybrid Hardhat and Foundry environment. There are a number of add-ons, some of which we will detail here. Unlike standard Foundry environments, the contracts are located in contracts/
(as opposed to src/
) in order to conform with the general Hardhat project architecture. The Foundry/Solidity tests live in test/forge/
whereas the Hardhat/Typescript tests are at the root level of test/
. (For more details on the tests, see Running Tests in the Using This Repo section.) This can result in the actual test coverage on the repo being hard to read, as solidity-coverage
and Foundry's native coverage tools do not natively communicate with each other. (In addition, Foundry's tool does not currently reflect branch coverage in Solidity libraries properly (source), though this will likely be remediated in the future.)
Part of the rationale is that while Foundry provides a set of options well suited to testing bridges, there are still aspects of the codebase which cannot be tested in native Solidity, particularly
The following is a brief overview of some of the files and directories in the project root:
│ .github/workflows/ - "CI (Github Actions) script: formats, lints, runs tests, coverage, Slither"
│ contracts/ - "all smart contracts, including mocks, but excluding Foundry tests and libs"
│ docs/ - "smart contract docs autogenerated from natspec"
│ lib/ - "smart contract libraries utilized by Foundry"
│ scripts/ - "Hardhat scripts, currently not updated, may contain deployment scripts in the future"
│ test/ - "both HH/TS and Foundry/Sol tests"
│ ts/ - "Typescript libraries for BLS/Elliptic Curves for testing BLS/BN256G2"
│ types/ - "Typescript types"
│ .env.example - "example env var file for using the HH env to connect with public nets/testnets"
│ .eslint.js - "JavaScript/TypeScript linter settings"
│ .nvmrc - "recommended Node version using nvm"
│ .prettierrc - "code formatting settings"
│ .solcover.js - "solidity-coverage settings"
│ .solhint.json - "Solidity linter settings"
│ foundry.toml - "Foundry configuration file"
│ hardhat.config.ts - "Hardhat configuration file"
│ slither.config.json - "settings for the Slither static analyzer"
The package-lock.json
is also provided to ensure the ability to install the same versions of the npm packages used in development and testing.
In order to work with this repo locally, you will need Node (preferably using nvm) in order to work with the Hardhat part of the repo.
In addition, to work with Foundry, you will need to have it installed. The recommended method is to use their foundryup
tool, which can be installed (and automatically install Foundry) using this command:
curl -L https://foundry.paradigm.xyz | bash
Note that this only works on Linux and Mac. For Windows, or if foundryup
doesn't work, consult their documentation.
This repo is a hybrid Hardhat and Foundry environment. There are a number of add-ons, some of which we will detail here. Unlike standard Foundry environments, the contracts are located in contracts/
(as opposed to src/
) in order to conform with the general Hardhat project architecture. The Foundry/Solidity tests live in test/forge/
whereas the Hardhat/Typescript tests are at the root level of test/
. (For more details on the tests, see Running Tests in the Using This Repo section.)
Install Foundry libs:
In addition, to work with Foundry, you will need to have it installed. The recommended method is to use their foundryup
tool, which can be installed (and automatically install Foundry) using this command:
curl -L https://foundry.paradigm.xyz | bash
Note that this only works on Linux and Mac. For Windows, or if foundryup
doesn't work, consult their documentation.
You do not need to clone this repo in order to interact with the Polygon core contracts
If you would like to work with these contracts in a development environment, first clone the repo:
git clone git@github.com:maticnetwork/v3-contracts.git
If you have nvm installed (recommended), you can run nvm use #
to set your version of Node to the same as used in development and testing.
Install JS/TS (Hardhat) dependencies:
npm i
Install Foundry libs:
forge install
Deploying these contracts in the context of a production blockchain is out of the scope of this repo, as it requires a client that has support of the Edge specification integrated. At current, Edge maintains its own client here, which can be consulted.
One point that is worth emphasizing in this context is that from the perspective of launching a Supernet is understanding genesis contracts. Another is that for at least the time being, the decision has been made to proxify all genesis contracts in order to facilitate upgrades/updates without necessitating a hardfork or regenesis. All deployment scripts in script/deployment
use OpenZeppelin's TransparentUpgradeableProxy
.
Deployment scripts have been provided for each of the root chain contracts. (The child chain contracts are genesis contracts, and are not deployed traditionally; they are deployed by the client as a part of the genesis of the child chain.)
Some contracts in the Edge suite need be deployed only once on root. These contracts can deployed using the DeploySharedRootContracts
script, after sharedRootContractsConfig
has been filled with appropriate values.
Other contracts are deployed on root once per Supernet. These contracts can deployed using the DeployNewRootContractSet.s.sol
script, after rootContractSetConfig.json
has been filled with appropriate values.
Note that the script does not initialize CheckpointManager
. Instead, it protects it to be initializable only by the INITIATOR
address later.
Not all root contracts are deployed at this point, however. There are parts of the bridge that need the addresses of various child contracts in order to be initialized. These contracts can deployed using the DeployRootTokenContracts.s.sol
script, after rootTokenContractsConfig.json
has been filled with appropriate values.
Scripts are run by invoking:
forge <SCRIPT_NAME> \
--broadcast \
<SIGNING_METHOD> \
--rpc-url <RPC_URL> \
--verify \
--sig "run()"
For the signing method and other options, consult Foundry Book.
There are a few things that should be done to set up the repo once you've cloned it and installed the dependencies and libraries. An important step for various parts of the repo to work properly is to set up a .env
file. There is an .example.env
file provided, copy it and rename the copy .env
.
The v3 contract set is meant to be deployed across two blockchains, which are called the root chain and child chain. In the case of Polygon POS v3 itself, Ethereum mainnet is the root chain, while Polygon POS v3 is the child chain. In order to give users the ability to work with these contracts on the chains of their choice, four networks are configured in Hardhat: root
, rootTest
, child
, and childTest
. To interact with whichever networks you would like to use as root and/or child, you will need to add a URL pointing to an RPC endpoint on the relevant chain in your .env
file. This can be a RPC provider such as Ankr or Alchemy, in which case you would put the entire URL including the API key into the relevant line of the .env
, or could be a local node, in which case you would put https://localhost:<PORT_NUMBER>
(usually 8545).
A field for a private key is also provided in the .env
. You will need to input this if you are interacting with any public networks (for example, deploying the contracts to a testnet).
Lastly, there are fields for an Etherscan and Polygonscan for verifying any deployed contracts on the Ethereum or Polygon mainnets or testnets. (Some additional configuration may be required, only Eth mainnet, Goerli, Polygon POS v1, and Mumbai are configured as of this writing.)
Hardhat:
npx hardhat compile --show-stack-traces
hardhat-ts
automatically generates typings for you after compilation, to use in tests and scripts. You can import them like: import { ... } from "../typechain-types";
Similarly, the hardhat-dodoc
package autogenerates smart contract documentation in docs/
every time Hardhat compiles the contract. If you wish to disable this, uncomment the runOnCompile: false
line in the dodoc
object in hardhat.config.ts
.
Foundry:
forge build
As mentioned previously, there are two separate test suites, one in Hardhat/Typescript, and the other in Foundry/Solidity. The HH tests are structured more as scenario tests, generally running through an entire interaction or process, while the Foundry tests are structured more as unit tests. This is coincidental, and is not a set rule.
Hardhat:
npx hardhat test
The Hardhat tests have gas reporting enabled by default, you can disable them from hardhat.config.ts
by setting enabled
in the gasReporter
object in hardhat.config.ts
or by setting REPORT_GAS
to false
in the .env
.
Foundry:
forge test
Simple gas profiling is included in Foundry tests by default. For a more complete gas profile using Foundry, see their documentation.
Simple gas profiling is included in Foundry tests by default. For a more complete gas profile using Foundry, see their documentation.
The linters run from inside the Hardhat/JS environment.
npm run lint # runs all linters at once
npm run lint:sol # only runs solhint and prettier
npm run lint:ts # only runs prettier and eslint
We do not know of a way to see the general coverage from the TS and Solidity tests combined at this juncture. Instead, the coverage of each suite can be checked individually.
Hardhat:
npx hardhat coverage
# or
npm run coverage
Foundry:
forge coverage
First, install slither by following the instructions here. Then, run:
slither .
# or
npm run slither
There is a CI script for Github Actions in .github/workflows/
. Currently it runs:
- linters
- both test suites (fails if any tests fail)
- coverage report (currently only HH)
- Slither
This repo makes use of Dodoc, a Hardhat plugin from Primitive Finance which generates Markdown docs on contracts from their natspec. The docs are generated on every compile, and can be found in the docs/
directory.