This the Kwenta GitOps repo for deployment of the Synthetix protocol.
The following section is the Synthetix Guide to deployment, for Kwenta specific information, jump straight to Kwenta Deployment Notes.
- Run
yarn cannon setup
and ensure you have a reliable IPFS url for publishing.
- After publishing any new versions of the provisioned packages (
oracle-manager
,synthetix
andspot-market
), bump the versions throughout the cannonfiles to match. - Add new settings and invoke actions as necessary.
- Increment the version number and update the values in the network-specific omnibus cannonfiles as desired. The main version should match synthetix version, and if it a configuration change on the same version use a dash. Version: 3.3.5 Version with config changes: 3.3.5-1
Conduct the following process for each network:
-
Perform a dry-run and confirm that the actions that would be executed by Cannon are expected:
yarn cannon build omnibus-base-sepolia-andromeda.toml \ --dry-run \ --upgrade-from synthetix-omnibus:latest@andromeda \ --chain-id 84532 \ --provider-url https://base-sepolia.infura.io/v3/$INFURA_API_KEY
-
Remove the dry-run option to execute the upgrade:
yarn cannon build omnibus-base-sepolia-andromeda.toml \ --upgrade-from synthetix-omnibus:latest@andromeda \ --private-key $TESTNET_DEPLOYER_PRIVATE_KEY \ --provider-url https://base-sepolia.infura.io/v3/$INFURA_API_KEY
-
After this you can run the dry-run command again (without upgrade-from), and should see no changes
yarn cannon build omnibus-base-sepolia-andromeda.toml \ --dry-run \ --chain-id 84532 \ --provider-url https://base-sepolia.infura.io/v3/$INFURA_API_KEY
The --provider-url and --private-key parameters are unnecessary if using Frame
-
If you've updated the provisioned packages, verify your new contracts on Etherscan:
yarn cannon verify synthetix-omnibus:3.3.5-1@andromeda --chain-id 84531 --api-key $ETHERSCAN_API_KEY
-
Publish your new packages on the Cannon registry:
yarn cannon publish synthetix-omnibus:3.3.5-1@andromeda \ --chain-id 84531 \ --private-key $MAINNET_DEPLOYER_PRIVATE_KEY \ --tags latest,3 \ --include-provisioned
If you use frame: (The --private-key parameter is unnecessary if using Frame)
-
Commit and merge the change to this repository.
-
Run the Export ABIs action in the
v3-abi-exporter
repository.
Example based on omnibus-base-sepolia-andromeda.toml
IMPORTANT Restart Anvil node and apply upgrades after each full test suite execution because of the global system state change, which affects things like global collateral limits
-
Build locally with --dry-run
yarn cannon build omnibus-base-sepolia-andromeda.toml \ --dry-run \ --upgrade-from synthetix-omnibus:latest@andromeda \ --chain-id 84532 \ --provider-url https://sepolia.base.org \ | tee ./e2e/cannon-build.log
or
yarn build:andromeda
-
Fetch deployments and store as JSON files
yarn fetch-deployments
-
Run local Anvil node for the required network.
yarn cannon build omnibus-base-sepolia-andromeda.toml \ --port 8545 \ --keep-alive \ --dry-run \ --upgrade-from synthetix-omnibus:latest@andromeda \ --chain-id 84532 \ --provider-url https://sepolia.base.org
or
yarn start:andromeda
-
Execute tests
DEBUG='e2e:*' mocha e2e/tests/omnibus-base-sepolia-andromeda.toml/*.e2e.js
or
yarn test:base-sepolia
The following steps were used to deploy a forked "Kwenta" version of the protocol:
- Copied
omnibus-base-goerli-competition.toml
into a new filekwenta-omnibus-base-goerli-competition.toml
- Note that this version was chosen for copying, because it was used for a testnet competition on Base Goerli, and hence was best suited to deploying everything needed for a successful test deployment.
- Make critical changes to the
.toml
cannonfile:- Update the name of the of the deployment to
kwenta-synthetix-omnibus
instead ofsynthetix-omnibus
- a new name is needed so we can separate our system in the registry from the one synthetix have already deployed and are managing. - Update
setting.target_preset
to a new value just for our system (TODO: check why I did this & if it is really necessary). - Update
setting.salt
to a unique value. This is needed to avoid a collision with the already deployed system, as use of CREATE2 will cause the same addresses to be generated, without a unique salt. - Update the various
owner
settings to the chosen owner for the system. Without this change, it will not be possible to administrate the system. The following settings needs updating with this change:setting.owner
setting.pool_owner
setting.ccip_router
- normally this would be the Cross Chain Interoperability Protocol Router, but for testing purposes we will set it as the system owner here.
- Update
setting.deployer
address to the chosen deployer address. Without this change the deployment will fail. I used the sameowner
anddeployer
for simplicity (though in production it may be wise to use different addresses for security reasons) - I removed
invoke.unapprove_wrongfully_deployed_snx_pool
as this was not relevant to our system.
- Update the name of the of the deployment to
- Run a dry-run of the deployment to ensure it will be successful before executing against the actual chain:
cannon build kwenta-base-goerli-competition.toml --provider-url <BASE_GOERLI_RPC_URL> --private-key <DEPLOYER_PRIVATE_KEY> --dry-run
<BASE_GOERLI_RPC_URL>
should be an RPC url for an eth node on the Base Goerli network.<DEPLOYER_PRIVATE_KEY>
should be the private key for the EOA you want to deploy the system from. I used the Kwenta Testnet Admin (address:0xC2ecD777d06FFDF8B3179286BEabF52B67E9d991
).- This is the step to try and debug any issues with the deployment before using real ETH.
- Send a chunky amount of ETH (it cost me 0.17 ETH, but send extra!) to the deployment address. Gas costs are volatile and you don't want to get caught with a mid-deployment failure. A semi-deployed/configured system is hard to fix! The Synthetix system is expensive to deploy. It is large and consists of many different modules and proxies. In theory cannon provides functionality for recovering a deployment that failed mid-way, in practice I was not able to get this to work.
- Now you are ready for the real deal! Use this command to actually deploy the system 🔥 🚀 💫 (simply remove the
--dry-run
flag):
cannon build kwenta-base-goerli-competition.toml --provider-url <BASE_GOERLI_RPC_URL> --private-key <DEPLOYER_PRIVATE_KEY>
- Now verify ✅ the system on etherscan with the following command:
cannon verify kwenta-synthetix-omnibus-test-3:3.3.3-dev.e141cd8c --chain-id 84531 --api-key <ETHERSCAN_API_KEY>
<ETHERSCAN_API_KEY>
for everyone on Base Goerli is:PLACEHOLDER_STRING
kwenta-synthetix-omnibus-test-3:3.3.3-dev.e141cd8c
is comprised of two parts:kwenta-synthetix-omnibus-test-3
- defined as the name in the cannonfile.3.3.3-dev.e141cd8c
- the version defined in the cannonfile.
- Awesome, your contracts should be verified now! 🥳
- The final step - register your IPFS deployment on the cannon registry! This will allow you to view your contracts on the online registry. It will show you loads of useful information about your contracts, let you people download the ABIs and contract addresses, and provide a UI for interacting with the contracts (etherscan won't work with the router-proxy-architecture used in synthetix).
- To complete this step you need some mainnet ETH. Send some to the EOA on mainnet you want to use for the registry transaction.
- Execute the following command:
cannon publish kwenta-synthetix-omnibus-test-3:3.3.3-dev.e141cd8c --chain-id 84531 --private-key <KEY_THAT_HAS_ETH_ON_MAINNET>
- For those interested, this process writes data to the CannonRegistry contract on Ethereum mainnet. This is actually just the implementation of contract, it is upgradeable and has a proxy. You can see the code for the whole system here and specifically the code for the CannonRegistry contract here.
If you made it this far - congratulations! You just deployed synthetix! 🎉
But... we are not finished with smart contract tasks yet from Kwenta's perspective. We still need to do step 7:
- Deploy
smart-margin-v3
- for that you will need this repo - you can use the Deploy.s.sol script with forge.
The following steps needed completing once the smart contracts were deployed:
- Get the ABIs from the cannon registry site. Got to the deployment page - e.g. like this one, scroll down and click the download addresses + ABIs button.
- Update the FE with all the new addresses, including:
- Addresses for all synths - e.g.
sUSD
,sBTC
,sETH
,sLINK
,sOP
etc. - MarginEngine and depending on the FE setup, the new TrustMulticallForwarder address if applicable.
- A subgraph needs deploying for everything to work fully, however without doing that, the following shortcut can be helpful:
- Hardcode all settlement strategies to
0
.
- Hardcode all settlement strategies to
- PerpsV3MarketProxy
- AccountProxy
- Other stuff I am not aware of as a measly smart-contract engineer.
Kwenta has now deployed a version of Synthetix V3 on Base Goerli testnet. The name of this deployment is kwenta-synthetix-omnibus-test-3. To interact with this can either use the the UI here, or use this command via cannon:
cannon interact --chain-id 84531 --provider-url <BASE_GOERLI_RPC_URL> --private-key <PRIVATE_KEY> kwenta-synthetix-omnibus-test-3
84531
is the chain ID for Base Goerli.<BASE_GOERLI_RPC_URL>
should be an RPC url for an eth node on the Base Goerli network.<PRIVATE_KEY>
can be any private key you want to use when executing transactions against the deployment. Use the Kwenta Testnet Admin (address: 0xC2ecD777d06FFDF8B3179286BEabF52B67E9d991) private key if you want to do privileged actions.kwenta-synthetix-omnibus-test-3
is the name of our testnet deployment.
- Copied
omnibus-base-mainnet-andromeda.toml
and renamed tokwenta-omnibus-base-mainnet-andromeda.toml
- Changed the
name
andversion
- Copied
tomls/core.toml
renamed totomls/kwenta-core.toml
- Updated
setting.salt
andsetting.bundleSalt
fromsnax
tokwenta-snax
.
- Updated
- Updated
setting.salt
- Updated
setting.target_preset
- Updated
setting.owner
,setting.deployer
andsetting.pool_owner
- Created new scripts in
package.json
:build:kwenta-base-sepolia
andstart:kwenta-base-sepolia
- Ran those to as test run
- Then created a new tenderly fork for base sepolia, copied its url `<TENDERLY_URL>
- Created a new script, building off
build:kwenta-base-sepolia
, changing--provider-url
to<TENDERLY_URL>
, and adding the--private-key
argument and ran that.
The reason this seems to work deploying everything, despite using --upgrade-from
is because the salt is new. In theory I should be able to deploy this without --upgrade-from
, by ensuring that tomls/perps-factor
provision.perpsFactory
depends on depends = ["provision.system", "provision.spotFactory"]
and that options.synthetixPackage
and options.spotMarketPackage
line up with what is provisioned in tomls/kwenta-core.toml
and tomls/markets/spot-factory.toml
under provision.system
and provision.spotFactory
.
However in practice I could not get this to work, potentially due to a cannon bug.