Official repository for all smart wallet contracts used by Circle web3 API/SDK.
This repository includes support for both the Hardhat and Foundry frameworks. Going forward, all new code / tests / scripts should be built on Foundry. Hardhat is currently only included for legacy contracts in the following folders:
src/account/v1
src/paymaster/v1/permissioned
- Run
git submodule update --init --recursive
to update/download all libraries. - Run
yarn install
to install any additional dependencies. - Run
curl -L https://foundry.paradigm.xyz | bash
and follow the outputted instructions to source env file. - Run
foundryup
- Create a
.env
file and provide the required API keys, wallets (can be generated for deployment), and configuration values. You can look at the.env.example
for reference.
Run yarn lint
to lint all .sol
files in the src
and test
directories. Run yarn format:check
and yarn format:write
to check for, and fix formatting issues, respectively.
To run tests using Foundry, follow the steps below:
- Run
yarn build
- Run
yarn test
To generate a viewable test coverage report, run:
brew install lcov
if not yet installedforge coverage --ir-minimum --report lcov && genhtml lcov.info -o report --branch-coverage && open report/index.html
(Note: some contracts like WeightedMultisigPlugin require using --ir-minimum because of stack depth. To build coverage faster locally, comment out this and dependent contracts and omit --ir-minimum flag.)
We use Github actions to run linter and all the tests. The workflow configuration can be found in .github/workflows/ci.yml
We are using Conventional Commit structure to automatically generate releases.
To export contract bytecode & ABI for programmable wallet:
- Execute
forge build src/msca/6900/v0.7 --force --extra-output-files abi evm
. Replace v0.7 with v0.8 if you want v0.8. - Execute
make abigen
- Interface files will appear under
abigen
folder - After changes are merged, release new repository tag
- update
buidl-wallet-contracts
go mod version of programmable-wallet, and import bytecode fromabigen
folder
For running integration tests in Anvil node, run make anvil-tests
. This runs the python tests in test/anvil
- Run
yarn build
- Run
yarn gasreport
-
anvil
-
update
.env
(pointing to local) andsource .env
-
deploy (only choose the account type you're interested in benchmarking)
-
forge script script/<SCRIPT_NAME> --rpc-url $RPC_URL --broadcast --verify -vvvv --slow --watch
Example:
forge script script/001_DeployPluginManager.s.sol --rpc-url $RPC_URL --broadcast --verify -vvvv --slow --watch
-
-
cast code $address
This section explains how to expand the existing smart contracts to new blockchains.
Make sure there are enough native tokens for the new chain in the deployer address (for contract deployment) and temporary owner
address (for setup and stake). Otherwise, you may hit insufficient fund
error at any step.
- Add new blockchain to
[rpc_endpoints]
infoundry.toml
following the format ofblockchain_a = ${BLOCKCHAIN_A_RPC_URL}
- Update
.env.example
with the new RPC URL env var (e.g.BLOCKCHAIN_A_RPC_URL
), also update your local.env
to set up the new env var (e.g.BLOCKCHAIN_A_RPC_URL=https://blockchaina.rpc.com
). - Add new blockchain (e.g.
"blockchain_a"
) togetChains()
function in./script/bytecode-deploy/100_Constants.sol
. - Since the length of
getChains()
changed above, update the length of local chain list generated bygetChains()
in deployment scripts.
Deploy, setup and verify UpgradableMSCAFactory compatible with ERC-4337 v0.7 and ERC-6900 v0.7.
Note that deploy commands attempt to deploy on all chains listed in foundry.toml
.
# Deploy PluginManager
forge script script/bytecode-deploy/101_DeployPluginManager.s.sol -vvvv --slow --broadcast --force --multi
# Deploy UpgradableMSCAFactory
forge script script/bytecode-deploy/102_DeployUpgradableMSCAFactory.s.sol -vvvv --slow --broadcast --force --multi
# Deploy ColdStorageAddressBookPlugin
forge script script/bytecode-deploy/103_DeployColdStorageAddressBookPlugin.s.sol -vvvv --slow --broadcast --force --multi
# Deploy WeightedWebauthnMultisigPlugin
forge script script/bytecode-deploy/104_DeployWeightedWebauthnMultisigPlugin.s.sol -vvvv --slow --broadcast --force --multi
Update chains[]
list in 105_SetUpgradableMSCAFactoryPlugins.s.sol
and 106_StakeUpgradableMSCAFactory.s.sol
. Update stakeValue
list in 106_StakeUpgradableMSCAFactory.s.sol
. And run
forge script script/bytecode-deploy/105_SetUpgradableMSCAFactoryPlugins.s.sol -vvvv --slow --broadcast --force --multi
forge script script/bytecode-deploy/106_StakeUpgradableMSCAFactory.s.sol -vvvv --slow --broadcast --force --multi
Use the json files in script/bytecode-deploy/standard-json-input
to verify smart contracts. If the smart contract has
constructor arguments, it's recorded in *_constructor_arg
files. Select the following options in block explorers verify contract UI:
- Compiler Type:
Solidity(Standard-Json-Input)
- Compiler Version:
v0.8.24
- License Type:
GNU GPLv3
Deploy, setup and verify SponsorPaymaster compatible with ERC-4337 v0.7.
1. Replace the placeholders and run the command in `script/cmd/DeploySponsorPaymaster`.
2. Replace the placeholders and run the command in `script/cmd/DeploySponsorPaymasterProxy`.
Need to use block explorer to run addStake
and setVerifyingSigner
from owner address.
Use script/verify/SponsorPaymaster.json
and script/verify/SponsorPaymasterProxy.json
to verify. Select the
following options in block explorers verify contract UI:
- Compiler Type:
Solidity(Standard-Json-Input)
- Compiler Version:
v0.8.24
- License Type:
GNU GPLv3
npx hardhat node
(if using hardhat stack)
make anvil
(if using foundry stack). To get a list of pre-funded addresses, you can look at the beginning of the logs in the anvil
Docker container, or reference https://github.com/foundry-rs/foundry/blob/0d8302880b79fa9c3c4aa52ab446583dece19a34/crates/anvil/README.md?plain=1#L48.
scripts and artifacts under ./script/bytecode-deploy
are using bytecode deployment and standard json input verification.
These steps are not needed for chain expansion. They're documented to show how to properly add artifacts if new deployment scripts are added.
For each smart contract needs to be deployed, repeat the following steps:
- Force build the smart contract.
- Copy the necessary build outputs from
./out
to./script/bytecode-deploy/build-output
. Sometimes it's more than the contract itself. - Generate the standard json input to
./script/bytecode-deploy/standard-json-input
.
The full set of commands are:
# PluginManager
forge build src/msca/6900/v0.7/managers/PluginManager.sol --force
cp out/PluginManager.sol/PluginManager.json script/bytecode-deploy/build-output/PluginManager.json
forge verify-contract -c <CHAIN_ID> --optimizer-runs 200 --via-ir <PLUGIN_MANAGER_ADDRESS> src/msca/6900/v0.7/managers/PluginManager.sol:PluginManager --show-standard-json-input > script/bytecode-deploy/standard-json-input/PluginManager.json
# UpgradableMSCAFactory (Build outputs of UpgradableMSCA and ERC1967Proxy are added for SDK)
forge build src/msca/6900/v0.7/factories/UpgradableMSCAFactory.sol --force
cp out/UpgradableMSCAFactory.sol/UpgradableMSCAFactory.json script/bytecode-deploy/build-output/UpgradableMSCAFactory.json
cp out/UpgradableMSCA.sol/UpgradableMSCA.json script/bytecode-deploy/build-output/UpgradableMSCA.json
cp out/ERC1967Proxy.sol/ERC1967Proxy.json script/bytecode-deploy/build-output/ERC1967Proxy.json
forge verify-contract -c <CHAIN_ID> --optimizer-runs 200 --via-ir <FACTORY_ADDRESS> --constructor-args $(cast abi-encode "constructor(address,address,address)" <MSCA_FACTORY_OWNER_ADDRESS> <ENTRY_POINT_V07> <PLUGIN_MANAGER_ADDRESS>) src/msca/6900/v0.7/factories/UpgradableMSCAFactory.sol:UpgradableMSCAFactory --show-standard-json-input > script/bytecode-deploy/standard-json-input/UpgradableMSCAFactory.json
cast abi-encode "constructor(address,address,address)" <MSCA_FACTORY_OWNER_ADDRESS> <ENTRY_POINT_V07> <PLUGIN_MANAGER_ADDRESS> | sed -e "s/^0x//" > script/bytecode-deploy/standard-json-input/UpgradableMSCAFactory_constructor_args
# UpgradableMSCA (build output of UpgradableMSCAFactory is used for verification, we only need to generate constructor args)
cast abi-encode "constructor(address,address)" <ENTRY_POINT_V07> <PLUGIN_MANAGER_ADDRESS> | sed -e "s/^0x//" > script/bytecode-deploy/standard-json-input/UpgradableMSCA_constructor_args
# ColdStorageAddressBookPlugin
forge build src/msca/6900/v0.7/plugns/v1_0_0/addressbook/ColdStorageAddressBookPlugin.sol --force
cp out/ColdStorageAddressBookPlugin.sol/ColdStorageAddressBookPlugin.json script/bytecode-deploy/build-output/ColdStorageAddressBookPlugin.json
forge verify-contract -c <CHAIN_ID> --optimizer-runs 200 --via-ir <PLUGIN_ADDRESS> src/msca/6900/v0.7/plugins/v1_0_0/addressbook/ColdStorageAddressBookPlugin.sol:ColdStorageAddressBookPlugin --show-standard-json-input > script/bytecode-deploy/standard-json-input/ColdStorageAddressBookPlugin.json
# WeightedWebauthnMultisigPlugin
forge build src/msca/6900/v0.7/plugins/v1_0_0/multisig/WeightedWebauthnMultisigPlugin.sol --force
cp out/WeightedWebauthnMultisigPlugin.sol/WeightedWebauthnMultisigPlugin.json script/bytecode-deploy/build-output/WeightedWebauthnMultisigPlugin.json
forge verify-contract -c <CHAIN_ID> --optimizer-runs 200 --via-ir <FACTORY_ADDRESS> --constructor-args $(cast abi-encode "constructor(address)" <ENTRY_POINT_V07>) src/msca/6900/v0.7/plugins/v1_0_0/multisig/WeightedWebauthnMultisigPlugin.sol:WeightedWebauthnMultisigPlugin --show-standard-json-input > script/bytecode-deploy/standard-json-input/WeightedWebauthnMultisigPlugin.json
cast abi-encode "constructor(address)" <ENTRY_POINT_V07> | sed -e "s/^0x//" > script/bytecode-deploy/standard-json-input/WeightedWebauthnMultisigPlugin_constructor_args
This step is not needed for chain expansion. We only need to add deployment script if new smart contracts are added.
- Writing a new deployment script. There are examples files ending in s.sol in script/bytecode-deploy.
- Salt mining with
cast create2
to find a salt that generates the address with 8 leading zeros. - Use the salt in deployment script.
- Adjust the chains in
100_Constants.sol
accordingly.
Deployment scripts are under script/bytecode-deploy. Deploy command is:
forge script script/bytecode-deploy/<SCRIPT_FILE> -vvvv --slow --broadcast --force --multi
Use the standard json output and constructor arg file under script/bytecode-deploy.standard-json-input to verify smart contracts in block explorer.
If you encountered this error after executing make test
, try increasing memory resource for docker engine.
If you are using macbook with M1 or newer chips, try enabling Use Rosetta for x86/amd64 emulation on Apple Silicon
under Features in development
in Docker settings.
As an alternative to the above, if you are using macbook with M1 or newer chips, try adding the --platform=linux/amd64
flag to the build
Make command. If you encounter this error while running make anvil
, make sure to run make
before.
When deploying contract deployment scripts from the /script
folder on a local chain (started up using make anvil
), you can remove the --verify
flag if you are getting errors related to the API key, such as Missing etherscan key for chain 31337
.
Run forge clean && forge build
.