Skip to content

circlefin/buidl-wallet-contracts

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

36 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

buidl-wallet-contracts

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

Setup

  1. Run git submodule update --init --recursive to update/download all libraries.
  2. Run yarn install to install any additional dependencies.
  3. Run curl -L https://foundry.paradigm.xyz | bash and follow the outputted instructions to source env file.
  4. Run foundryup
  5. 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.

Development

Lint

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.

Test

To run tests using Foundry, follow the steps below:

  1. Run yarn build
  2. Run yarn test

Test Coverage

To generate a viewable test coverage report, run:

  • brew install lcov if not yet installed
  • forge 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.)

Continuous Integration

We use Github actions to run linter and all the tests. The workflow configuration can be found in .github/workflows/ci.yml

Release

We are using Conventional Commit structure to automatically generate releases.

Export Interface

To export contract bytecode & ABI for programmable wallet:

  1. 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.
  2. Execute make abigen
  3. Interface files will appear under abigen folder
  4. After changes are merged, release new repository tag
  5. update buidl-wallet-contracts go mod version of programmable-wallet, and import bytecode from abigen folder

For running integration tests in Anvil node, run make anvil-tests. This runs the python tests in test/anvil

Gas Report

Function report

  • Run yarn build
  • Run yarn gasreport

E2E gas benchmarking

  • anvil

  • update .env (pointing to local) and source .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

Chain Expansion Guide

This section explains how to expand the existing smart contracts to new blockchains.

Prerequisites

Fund deployer and owner

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 RPC URLs to foundry

  1. Add new blockchain to [rpc_endpoints] in foundry.toml following the format of blockchain_a = ${BLOCKCHAIN_A_RPC_URL}
  2. 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).
  3. Add new blockchain (e.g. "blockchain_a") to getChains() function in ./script/bytecode-deploy/100_Constants.sol.
  4. Since the length of getChains() changed above, update the length of local chain list generated by getChains() in deployment scripts.

Deploy & Verify UpgradableMSCAFactory and dependency smart contracts.

Deploy, setup and verify UpgradableMSCAFactory compatible with ERC-4337 v0.7 and ERC-6900 v0.7.

Run deploy commands:

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

Setup UpgradableMSCAFactory:

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

Verify contracts on block explorers.

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 & Verify EPv0.7 SponsorPaymaster

Deploy, setup and verify SponsorPaymaster compatible with ERC-4337 v0.7.

Run deploy command

1. Replace the placeholders and run the command in `script/cmd/DeploySponsorPaymaster`.
2. Replace the placeholders and run the command in `script/cmd/DeploySponsorPaymasterProxy`.

Setup SponsorPaymaster

Need to use block explorer to run addStake and setVerifyingSigner from owner address.

Verify SponsorPaymaster

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

Develop a New Smart Contract

Start a Local Network (optional, for testing)

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.

Deploy & Verify

scripts and artifacts under ./script/bytecode-deploy are using bytecode deployment and standard json input verification.

artifact generation

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:

  1. Force build the smart contract.
  2. Copy the necessary build outputs from ./out to ./script/bytecode-deploy/build-output. Sometimes it's more than the contract itself.
  3. 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

Deployment script

This step is not needed for chain expansion. We only need to add deployment script if new smart contracts are added.

  1. Writing a new deployment script. There are examples files ending in s.sol in script/bytecode-deploy.
  2. Salt mining with cast create2 to find a salt that generates the address with 8 leading zeros.
  3. Use the salt in deployment script.
  4. Adjust the chains in 100_Constants.sol accordingly.

Deploy

Deployment scripts are under script/bytecode-deploy. Deploy command is:

forge script script/bytecode-deploy/<SCRIPT_FILE>  -vvvv --slow --broadcast --force --multi

Verification

Use the standard json output and constructor arg file under script/bytecode-deploy.standard-json-input to verify smart contracts in block explorer.

Troubleshooting

1. make: *** [test] Error 137

If you encountered this error after executing make test, try increasing memory resource for docker engine.

2. Encounter ERROR: failed to solve: operating system is not supported when executing make build

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.

3. Docker container foundry:latest not found

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.

4. API key errors when running deploy scripts on a local blockchain

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.

5. failed to read artifact source file for ...

Run forge clean && forge build.