This package provides a set of tools and scripts to help with the development of Solidity smart contracts:
- Utilities to simplify the testing of smart contracts using Foundry.
- Utilities to simplify the deployment of smart contracts using Foundry.
- Utilities to manage the existing deployments of smart contracts.
This package is still under development and should be used with caution. It is not recommended to use it in a production environment.
Forge docs are automatically deployed here.
In order to use this package, it needs to be installed as a dependency in your project. It is recommended to install it as a dev dependency.
npm install --save-dev @synapsecns/solidity-devops
# Or, if you are using yarn
yarn add --dev @synapsecns/solidity-devops
Following files are necessary to be present in the root of your project:
.env
: storage for the sensitive configuration variables.devops.json
: configuration file for the devops package.foundry.toml
: configuration file for Foundry.
Note: This file must be added to .gitignore
to avoid sharing sensitive information.
See the example .env file. Following structure is required:
Wallets
: defines the deployer wallets used for running the scripts. Assuming thechad
is the name of the wallet, the following values are required:CHAD_ADDRESS
: the address of the account to use for signingCHAD_TYPE
: the type of the wallet:keystore
: use the encrypted keystore file.CHAD_JSON
: the keystore file path
ledger
ortrezor
: use the hardware wallet.- TODO: find out if ledger/trezor specific options are needed
pk
: use the plaintext private key. STRONGLY DISCOURAGED for production usage, meant for local devnet purposes.CHAD_PK
: the private key to the wallet in 0x format.
- Any other value triggers the interactive prompt to enter the private key.
Chains
: defines the list of chains where the scripts will run. Assuming thechain
is the name of the chain, the following values are required:CHAIN_RPC
: the RPC endpoint of the chainCHAIN_VERIFIER
: verifier for the smart contracts. Possible values:etherscan
blockscout
sourcify
CHAIN_VERIFIER_URL
: the Verifier API endpoint (required if verifier is not sourcify)- Note: Blockscout URL needs to end with "/api?" for the verification to work.
CHAIN_VERIFIER_KEY
: the Verifier API key (required if verifier is not sourcify)- Note: Use any non-empty string for Blockscout API key: it is not required per se, but foundry will complain if it's empty.
See the example devops.json file. Following values are required:
chains
: list of chain-specific options forforge script
command.- Check the available options by running
forge script --help
. - Two additional options to handle the gas pricing are introduced:
--auto-gas-1559
: will fetch the current base fee and priority fee from the chain's RPC node, and use following values for submitting the transactions:maxPriorityFee = priorityFee
maxGasPrice = 2 * baseFee + priorityFee
--auto-gas-legacy
: will fetch the current gas price from the chain's RPC node, and use it for submitting the transactions.Note: these options are introduced as foundry script hardcodes the 3 Gwei priority fee, which is not ideal for all the chains.
- Check the available options by running
deployConfigs
: path to the directory that contains the deployment configuration files. These configuration files are expected to be either chain-specific or global:- The chain-specific configuration files should be located in
deployConfigsDir/{chainName}/{contractName}.dc.json
. - The global configuration files for production should be located in
deployConfigsDir/global/{contractName}.json
. - The global configuration files for other environments (e.g. testnet) should be located in
deployConfigsDir/global/{environment}/{contractName}.json
. - The configuration files usually include the variables required for the contract deployment or its subsequent management.
- The chain-specific configuration files should be located in
deployments
: path to the directory that contains the deployment artifact files. These files are automatically generated byfsr
and alike commands.forgeArtifacts
: path to the directory thatforge
uses to store the artifacts for the compiled contracts.- Must match the
out
value in thefoundry.toml
file.
- Must match the
freshDeployments
: path to the directory that contains the fresh deployment artifact files. These files are generated during the local run of theforge script
command.- It is recommended to add this directory to
.gitignore
to avoid unnecessary changes in the repository. - The artifacts in this directory are automatically moved into the
deployments
directory byfsr
and alike commands.Note: we opted to use this approach, as the local run of the
forge script
is always done before the actual broadcast of the deployment transactions. Therefore, the end results might not match the local run, if there was an unexpected on-chain revert, or if transactions were not included in the block. A separate job is automatically run to check all the new artifacts and move them to thedeployments
directory, if the on-chain deployment was successful.
- It is recommended to add this directory to
See the example foundry.toml file. Following values are required:
fs_permissions
:{ access = "read", path = "./" }
to allow reading files from the repository root{ access = "read-write", path = "<freshDeployments>" }
to allow reading/writing fresh deployment artifacts
rpc_endpoints
:- It is recommended to follow the structure defined in the example file to avoid duplication:
arbitrum = "${ARBITRUM_RPC}"
- It is recommended to follow the structure defined in the example file to avoid duplication:
etherscan
:- It is recommended to follow the structure defined in the example file to avoid duplication:
arbitrum = { key = "${ARBITRUM_VERIFIER_KEY}", url = "${ARBITRUM_VERIFIER_URL}" }
- You should omit values for chains that are using Sourcify for verification.
- It is recommended to follow the structure defined in the example file to avoid duplication:
See the Foundry Book for more information.
- Your scripts should inherit from the
SynapseScript
class (orSynapseScript06
if you're using Solidity 0.6 compiler).- This class already inherits from
forge-std
'sScript
class, so you can use all the methods from it. - See the example script for more information.
- This class already inherits from
- It is recommended to use separate scripts for initial deployments and subsequent configuration of the contracts.
- The initial deployment scripts should be named
Deploy{ContractName}.s.sol
. - The configuration scripts should be named
Configure{ContractName}.s.sol
.
- The initial deployment scripts should be named
Your main point of entry for running the scripts should be the npx fsr
command.
Note:
fsr
is a shorthand forforge script run
.
# npx fsr <path-to-script> <chain-name> <wallet-name> [<options>]
# To simulate the script without broadcasting, using wallet named "chad"
npx fsr script/DeployBasicContract.s.sol eth_sepolia chad
# To broadcast the script using wallet named "chad"
# NOTE: there is no need to add --verify option, as it is automatically added for the broadcasted scripts.
npx fsr script/DeployBasicContract.s.sol eth_sepolia chad --broadcast
This command is responsible for the following:
- Initializing the chain's deployment directories with the
.chainid
file, if they don't exist. - Logging the wallet's address, balance and nonce.
- Running the script using the
forge script
command.- This executes the
run()
method of the script. --verify
option is added if the script is broadcasted.
- This executes the
- Collecting the receipts for the newly deployed contracts, and saving their deployment artifacts.
You can also utilize the npx fsr-str
command to provide a single string argument for the running script:
- This executes the
run(string memory arg)
method of the script, passing the provided string argument.
# npx fsr-str <path-to-script> <chain-name> <wallet-name> <string-arg> [<options>]
# To simulate the script without broadcasting, using wallet named "chad"
npx fsr-str script/DeployBasicContract.s.sol eth_sepolia chad "AAAAAAAA"
# To broadcast the script using wallet named "chad"
# NOTE: there is no need to add --verify option, as it is automatically added for the broadcasted scripts.
npx fsr-str script/DeployBasicContract.s.sol eth_sepolia chad "AAAAAAAA" --broadcast
If for whatever reason the deployment script was interrupted, you can use npx sd
command to save the deployment artifacts.
Note:
sd
is a shorthand forsave deployment
.
# npx sd <chain-name> <contract-alias>
npx sd eth_sepolia BasicContract
# Or, if the contract alias is used
npx sd eth_sepolia BasicContract.Alias
You can verify the contracts with the saved deployment artifacts using the npx fvc
command.
Note:
fvc
is a shorthand forforge verify contract
.
# npx fvc <chain-name> <contract-alias>
npx fvc eth_sepolia BasicContract
# Or, if the contract alias is used
npx fvc eth_sepolia BasicContract.Alias
You can verify the proxy's implementation in Etherscan-alike explorers using the npx vp
command.
Note:
vp
is a shorthand forverify proxy
.
# npx vp <chain-name> <contract-alias>
npx vp eth_sepolia BasicContract
# Or, if the contract alias is used
npx vp eth_sepolia TransparentUpgradeableProxy.BasicContract