New Market deployment

This document goes over the technical steps required to deploy a new market.

Launch new testnet market (perps-deploy)

You would need to have the credential of deployer's wallet for this to work.

Let's add a new market for testnet:

$ cargo run --bin perps-deploy testnet add-market --family osmobeta --market WIF_USDC
Error: No MarketConfigUpdate found for WIF_USDC

You would need to go and update market-config-updates.toml files. Once you update that, try executing the same command:

$ cargo run --bin perps-deploy testnet add-market --family osmobeta --market WIF_USDC
Error: No oracle market found for WIF_USDC

You would need to go and update the config-price.toml file. Once you would do that, you would be able to add the market without any further issues:

$ cargo run --bin perps-deploy testnet add-market --family osmobeta --market WIF_USDC
[2024-04-01T07:23:26Z INFO  perps_deploy::app] Connecting to https://grpc.osmotest5.osmosis.zone
[2024-04-01T07:23:27Z INFO  perps_deploy::instantiate] Finding CW20 for collateral asset USDC for market WIF_USDC
[2024-04-01T07:23:27Z INFO  perps_deploy::instantiate] Using existing CW20
[2024-04-01T07:23:28Z INFO  perps_deploy::instantiate] osmo12vhejqqdgnszlcs7nqdvlx3p5eqyudfslevx3k is already a faucet admin for osmo1ycrm74p7uc976hu2z428l27vxj8l44zu0x0yqjr8gh775qr6gtnq9f3zsz
[2024-04-01T07:23:31Z INFO  perps_deploy::instantiate] Minted in 0050BEC079BABDCC37D10CC93348F78096F177A3F0D471655EB164F09C6DD440
[2024-04-01T07:23:31Z INFO  perps_deploy::instantiate] Using CW20 osmo1l5wc2znxhmf9gutyknk9dwwcj6pk0a57sc4wc24qcd63ft08a7jqmkl58p
[2024-04-01T07:23:34Z INFO  perps_deploy::instantiate] Market WIF_USDC added at 4B5BB048451B4F201F09491E0407A1A8CEE0E53ED12275E0D0C5224EC6C78002
[2024-04-01T07:23:34Z INFO  perps_deploy::instantiate] New market address for WIF_USDC: osmo1wyyfac2mng86wurgdlgdk5pu4fcw7yr7twupxeewm6039rxwwheqj6amh2

If you had to update any specific parameter for that market, you can do it like this:

cargo run --bin perps-deploy testnet update-market-configs --family osmobeta --market-id WIF_USDC "{\"delta_neutrality_fee_sensitivity\": \"40000000\"}"

Once you have added a market in testnet, you would have to add liquidity. This can be done like this:

cargo run --bin perps-qa deposit-liquidity --contract-family osmobeta --market-id WIF_USDC

Launch new mainnet market (perps-deploy)

You can generate a mainnet multisig proposal for adding a new market with a command like the following, run within the levana-perps repo:

cargo run --bin perps-deploy mainnet add-market --factory injmainnet1 --market-id BTC_USD

The above command will print various things like the CW3 contract address and the message. Make sure to pretty print the json message for the smart-contract-gui to recognize it properly.

Initial setup

The new factory should be provided an initial gas fee to covert 6 months of price and crank bot operations. This can be estimated based on a price update occuring once every minute for the market, and use the most recent few transaction on chain to determine the average cost. (this changes over time based on improvements to Pyth oracle gas optimization).

Frontend support for new markets

  • Make sure to add a new market config entry in constants.ts. The market will not display in the frontend without this. This is where you define icons, tradingview price feed, and more.
  • Once a market is deployed, inside the frontend repo, run (cd etc/twitter-share/ && cargo run). This will generate a shell script for creating Twitter share HTML files per market. It will print out an error message for any market missing a share icon. If that happens, ask for a new icon on #ui-design and then upload to s3://static.meteors.levana.finance/cards/perps-markets. This will become visible at a URL like https://static.levana.finance/cards/perps-markets/ATOM.png. See static file hosting for more information.
    • Note that this executable internally has some logic for mapping market names. At time of writing, this only applies to mapping axlETH_USD to ETH_USD, which is also handled on the frontend.

Deploying a new factory in a new blockchain

Note that most of the step documented here is part of this screencast.

To enable multisigs and permission system on a blockchain, deploy these contracts on the chain:

Make sure to deploy both of them via the cosmos cli:

$ cosmos contract store-code $HOME/Downloads/cw3_flex_multisig.wasm
Code ID: 1189

Similarly for cw4-group.wasm:

$ cosmos contract store-code $HOME/Downloads/cw3_flex_multisig.wasm
Code ID: 1190

And then you need to make sure that cosmos binary supports it. Sample PR for it. Make sure to install the new cosmos binary in your $PATH.

Get all the addresses that will be used for multisig purpose. If you get an address for a specific blockchain (eg: Osmosis), you can convert it to another blockchain using cosmos cli (This will only for chains with the same derivation path. E.g. Injective and Sei wallet addresses can't be converted like this) Example:

$ cosmos wallet change-address-type osmo1x4dmdw3829cmuf3zf65dydr2mf8x229rfny5ds neutron
neutron1x4dmdw3829cmuf3zf65dydr2mf8x229r9h7xp9

Now create a new CW3 flex contract backed with CW4 group behind it. Let's create it for Levana Perps Owner purpose:

$ cosmos cw3 new-flex --weight-needed 0.6 --duration 3d --label "Levana Perps Owner" --member neutron17s76s29nyuu5p6xaqz0sndw3sgl78hy4gqm342  --member neutron1x4dmdw3829cmuf3zf65dydr2mf8x229r9h7xp9 --member neutron1z3s9600e2hm32u0n3ntcczeg6nvcsx5quef6dq --member neutron10zwektqxpzg3ma8hf6wvg3mm5htmpxhrxmc0ae --member neutron1rr0m0wz598g4jzgqlhmxsns7lsflkwnmklcuql
Created new CW4-group contract: neutron1ql4zrg4skj9y5v8cg5mua62nkgaup6zzpsaxpmdhaq89sglv6t6qffua0h
Created new CW3-flex contract: neutron1n9pkq0wljphqssvl5k7tjjpljxujzlffgnekw6aeve8tmgsr5ndq3kkmrz
Fixing permissions on the contracts to make the CW3 the admin
Admin permissions updated in DAC9134B57EC10976E17B93123A7FA4EF214BD0DD0D407FDC0FCDCD63FB4201D

Make sure to note the contract address in the output.

These are the options explanation:

FlagExplanation
--labelOn-chain label used for the CW3
--weight-neededPercentage of total weight needed to pass the proposal
--durationDuration. Accepts s, m, h, and d suffixes for seconds, minutes, hours, and days
--memberEqual-weighted voting members of the group

Note how you had to put all the 5 wallet address in that command. Repeat the same command as above, but with this label instead:

  • Levana Perps Treasury
  • Levana Perps Kill Switch
  • Levana Perps Wind Down
  • Levana Perps Migration Admin

You would have got 10 contract address (5 cw4-group and 5 cw-3). You would have to add them in the spreadsheet which Michael will provide.

Now let's deploy the contracts to the blockchain. Get the specific commit id from which you need to build the contracts. Switch to that commit id and run the following command from the levana-perps repository to build the contracts:

❯ just build-contracts
./.ci/contracts.sh
++ readlink -f ./.ci/contracts.sh
+ SCRIPT=/home/sibi/fpco/github/levana/levana-perps/.ci/contracts.sh
++ dirname /home/sibi/fpco/github/levana/levana-perps/.ci/contracts.sh
....
....
....
236f885abf5dc65722cfbf8be8bbd0317acf4d661a6a9a86695584b04aa232d3  levana_perpswap_cosmos_cw20.wasm
a6a1361a1d8604dfc1ac06a7c67c6b705837265bb3996b0b4d526a63e0ff6597  levana_perpswap_cosmos_factory.wasm
b93d2778bab1a8f93379b83cf5e34bb05f917a578efd2873c17bead52541baa2  levana_perpswap_cosmos_farming.wasm
ed4112522ac015fdda7671484b8371f0c288da2112586fdf62d32452eb0942eb  levana_perpswap_cosmos_faucet.wasm
cbfc0400d0c010406c2c5fa0f367e85df5e0184994e4dcf461ca9f381a341782  levana_perpswap_cosmos_hatching.wasm
1bdbf1069164a22dca98e4f1862d87411af11ba12e15d686007b76ca7bb52e00  levana_perpswap_cosmos_ibc_execute_proxy.wasm
17297d13f9fb2b932bff6df5cbb3a849fbbc5a20ef5dc23117b661a084b5f34f  levana_perpswap_cosmos_liquidity_token.wasm
2b2c8c28e2ba2124add8f889f4a3a0645e6735f67a7fefb0de374af2763321d7  levana_perpswap_cosmos_market.wasm
076db0ac7c2b41165d70e1532628ed708512176b77068ec640710c4dc8bff17a  levana_perpswap_cosmos_position_token.wasm
8b846b0bcca8cb348c7c5dcc2496927deca2cd52c0f7256dbce73f93b16c03dd  levana_perpswap_cosmos_rewards.wasm
bd7712b45c0098e016752dd903aa793fbfedc24db44bf8151a81f5b73c6f3242  levana_perpswap_cosmos_tracker.wasm

Confirm that the hashes match and then proceed towards storing the contracts on the chain.

$ cargo run --bin perps-deploy mainnet store-perps-contracts
[2024-05-08T08:26:18Z INFO  perps_deploy::app] Connecting to http://grpc-kralum.neutron-1.neutron.org
[2024-05-08T08:26:18Z INFO  perps_deploy::mainnet] Storing Factory...
[2024-05-08T08:26:22Z INFO  perps_deploy::mainnet] New code ID: 1191
[2024-05-08T08:26:22Z INFO  perps_deploy::mainnet] Storing Market...
[2024-05-08T08:26:30Z INFO  perps_deploy::mainnet] New code ID: 1192
[2024-05-08T08:26:30Z INFO  perps_deploy::mainnet] Storing LiquidityToken...
[2024-05-08T08:26:33Z INFO  perps_deploy::mainnet] New code ID: 1193
[2024-05-08T08:26:33Z INFO  perps_deploy::mainnet] Storing PositionToken...
[2024-05-08T08:26:41Z INFO  perps_deploy::mainnet] New code ID: 1194

And then you can instantiate the factory:

$ cargo run --bin perps-deploy mainnet instantiate-factory --factory-label "Levana Perpetual Swaps" --ident "ntrnmainnet1" --owner neutron1n9pkq0wljphqssvl5k7tjjpljxujzlffgnekw6aeve8tmgsr5ndq3kkmrz --dao neutron1d70f2z7ad6ttgkjf66k6q9cv0pf5xy7vcfm76jhjnduly670g8kqlzpxpm --kill-switch neutron142f7aql7any3gzk4f9uyqulalucx5ht8r94y5tsnj5vt4pwzq7pqjv5mdn --wind-down neutron1al43ntd6k45r4yp3h5c4cza5pt4vlzh47qadp6yx50pn5qyvmqwqxrdfa6 --migration-admin neutron1su4hspnnd2ulhxpqlw5lnxl9vyavnzcvfeernk3pt9gk0cdam3kqfvrmaw
Finished dev [unoptimized + debuginfo] target(s) in 0.15s
     Running `target/debug/perps-deploy mainnet instantiate-factory --factory-label 'Levana Perpetual Swaps' --ident ntrnmainnet1 --owner neutron1n9pkq0wljphqssvl5k7tjjpljxujzlffgnekw6aeve8tmgsr5ndq3kkmrz --dao neutron1d70f2z7ad6ttgkjf66k6q9cv0pf5xy7vcfm76jhjnduly670g8kqlzpxpm --kill-switch neutron142f7aql7any3gzk4f9uyqulalucx5ht8r94y5tsnj5vt4pwzq7pqjv5mdn --wind-down neutron1al43ntd6k45r4yp3h5c4cza5pt4vlzh47qadp6yx50pn5qyvmqwqxrdfa6 --migration-admin neutron1su4hspnnd2ulhxpqlw5lnxl9vyavnzcvfeernk3pt9gk0cdam3kqfvrmaw`
[2024-05-08T08:34:01Z INFO  perps_deploy::app] Connecting to http://grpc-kralum.neutron-1.neutron.org
[2024-05-08T08:34:01Z INFO  perps_deploy::mainnet] Instantiating a factory using code ID 1191
[2024-05-08T08:34:06Z INFO  perps_deploy::mainnet] Deployed fresh factory contract to: neutron1an8ls6d57c4qcvjq0jmm27jtrpk65twewfjqzdn7annefv7gadqsjs7uc3

Note that each of the address you have specified here is the contract address of the CW3-flex contract that you received from the cw3 new-flex sub command above.

Now that you have a factory, you can add markets to it:

$ cargo run --bin perps-deploy mainnet add-market --factory ntrnmainnet1 --market-id NTRN_USD
: Compiling perps-exes v0.1.0 (/home/sibi/fpco/github/levana/levana-perps/packages/perps-exes)
:     Finished dev [unoptimized + debuginfo] target(s) in 5.97s
:      Running `target/debug/perps-deploy mainnet add-market --factory ntrnmainnet1 --market-id NTRN_USD`
: [2024-05-08T08:45:46Z INFO  perps_deploy::app] Connecting to http://grpc-kralum.neutron-1.neutron.org
: [2024-05-08T08:45:47Z INFO  perps_deploy::mainnet] Validating spot price config for NTRN_USD
: [2024-05-08T08:45:47Z INFO  perps_deploy::mainnet] Need to make a proposal
: [2024-05-08T08:45:47Z INFO  perps_deploy::mainnet] CW3 contract: neutron1n9pkq0wljphqssvl5k7tjjpljxujzlffgnekw6aeve8tmgsr5ndq3kkmrz
: [2024-05-08T08:45:47Z INFO  perps_deploy::mainnet] Message: [{"wasm":{"execute":{"contract_addr":"neutron1an8ls6d57c4qcvjq0jmm27jtrpk65twewfjqzdn7annefv7gadqsjs7uc3","msg":"eyJhZGRfbWFya2V0Ijp7Im5ld19tYXJrZXQiOnsiY29uZmlnIjp7ImJvcnJvd19mZWVfcmF0ZV9taW5fYW5udWFsaXplZCI6IjAuMSIsImJvcnJvd19mZWVfc2Vuc2l0aXZpdHkiOiIwLjMiLCJjYXJyeV9sZXZlcmFnZSI6IjIiLCJjcmFua19mZWVfY2hhcmdlZCI6IjAuMDUiLCJjcmFua19mZWVfcmV3YXJkIjoiMC4wNDUiLCJjcmFua19mZWVfc3VyY2hhcmdlIjoiMC4wMjUiLCJkZWx0YV9uZXV0cmFsaXR5X2ZlZV9jYXAiOiIwLjAzIiwiZGVsdGFfbmV1dHJhbGl0eV9mZWVfc2Vuc2l0aXZpdHkiOiI4MDAwMDAwIiwiZGVsdGFfbmV1dHJhbGl0eV9mZWVfdGF4IjoiMC4yNSIsImV4cG9zdXJlX21hcmdpbl9yYXRpbyI6IjAuMDIiLCJmdW5kaW5nX3JhdGVfc2Vuc2l0aXZpdHkiOiIyIiwibGlxdWlkaXR5X2Nvb2xkb3duX3NlY29uZHMiOjg2NDAwLCJtYXhfbGV2ZXJhZ2UiOiI0IiwidGFyZ2V0X3V0aWxpemF0aW9uIjoiMC41IiwidHJhZGluZ19mZWVfY291bnRlcl9jb2xsYXRlcmFsIjoiMC4wMDIiLCJ0cmFkaW5nX2ZlZV9ub3Rpb25hbF9zaXplIjoiMC4wMDIifSwiaW5pdGlhbF9ib3Jyb3dfZmVlX3JhdGUiOiIwLjIiLCJtYXJrZXRfaWQiOiJOVFJOX1VTRCIsInNwb3RfcHJpY2UiOnsib3JhY2xlIjp7ImZlZWRzIjpbeyJkYXRhIjp7InB5dGgiOnsiYWdlX3RvbGVyYW5jZV9zZWNvbmRzIjoyMSwiaWQiOiJhOGU2NTE3OTY2YTUyY2IxZGY4NjRiMjc2NGYzNjI5ZmRlM2YyMWQyYjY0MGI1YzU3MmZjZDY1NGNiY2NkNjVlIn19LCJpbnZlcnRlZCI6ZmFsc2V9XSwiZmVlZHNfdXNkIjpbeyJkYXRhIjp7InB5dGgiOnsiYWdlX3RvbGVyYW5jZV9zZWNvbmRzIjoyMSwiaWQiOiJhOGU2NTE3OTY2YTUyY2IxZGY4NjRiMjc2NGYzNjI5ZmRlM2YyMWQyYjY0MGI1YzU3MmZjZDY1NGNiY2NkNjVlIn19LCJpbnZlcnRlZCI6ZmFsc2V9XSwicHl0aCI6eyJjb250cmFjdF9hZGRyZXNzIjoibmV1dHJvbjFtMmVtYzkzbTlncHdnc3JzZjJ2eWx2OXh2Z3FoNjU0NjMwdjdkZnJocmttcjVzbGx5NTNzcGc4NXd2IiwibmV0d29yayI6InN0YWJsZSJ9fX0sInRva2VuIjp7Im5hdGl2ZSI6eyJkZWNpbWFsX3BsYWNlcyI6NiwiZGVub20iOiJ1bnRybiJ9fX19fQ==","funds":[]}}}]
: [2024-05-08T08:45:47Z INFO  perps_deploy::mainnet] Simulation completed successfully

Create a multisig proposal for the above message and execute it to add the market. Also make sure to commit your levana-perps changes and send the appropriate PR.

There are other steps included in deploying a factory to mainnet: