This repo contains Carmine Options AMM written in C1, version 2.3.1
.
The contracts are build using Scarb 2.3.0.
Install with:
curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh | sh -s -- -v 2.3.1
Then build by running scarb build
command.
Tests can be run with Starknet foundry 0.10.1.
Install by first installing snfoundryup
:
curl -L https://raw.githubusercontent.com/foundry-rs/starknet-foundry/master/scripts/install.sh | sh
And then install the correct version: snfoundryup -v 0.10.1
Now you can run tests with snforge test
.
Alternatively you can open this folder in VSCode Devcontainer, which comes with all the tooling installed.
The AMM is currently built on Cairo version 2.3.0. However while OpenZeppelin was porting their contracts to 2.3.0 the 2.3.1 came out in the meantime, so part of contracts (which we do not need) are built on top 2.3.1. and snforge 0.10.1 unfortunately does not support that so tests can't be run if we include OZ contracts in the Scarb.toml file. For that reason we just imported needed contracts directly.
Everything except for OZ smart contracts, src/amm_core/peripheries
folder and tests is intended for audit:
- src/amm_core/oracles/agg.cairo
- src/amm_core/oracles/oracle_helpers.cairo
- src/amm_core/oracles/pragma.cairo
- src/amm_core/pricing/fees.cairo
- src/amm_core/pricing/option_pricing.cairo
- src/amm_core/pricing/option_pricing_helpers.cairo
- src/amm_core/amm.cairo
- src/amm_core/constants.cairo
- src/amm_core/helpers.cairo
- src/amm_core/liquidity_pool.cairo
- src/amm_core/options.cairo
- src/amm_core/state.cairo
- src/amm_core/trading.cairo
- src/types/option_.cairo
- src/types/pool.cairo
- src/tokens/lptoken.cairo
- src/tokens/option_token.cairo
Unit tests are located in files containing relevant code, while integration tests are located in tests
folder. Currently there are integration tests for:
- Depositing liquidity
- Withdrawing liquidity
- Opening trade
- Closing trade
- Settling trade
- View functions
- Sandwich guard
Most of the tests also contain a couple of different scenarios.
Folder src/testing
contains various utilities for writing tests:
setup.cairo
- Contains function that will fully deploy the AMM (along with tokens representing ETH, USDC), set it up, add liquidity etc. The function is calleddeploy_setup
and it returns a tuple of two structs, where the first one isCtx
(context) which contains information needed for tests - addresses (AMM, tokens, LP tokens, OP tokens, admin...) strike, expiry etc. The second struct,Dispatchers
, provides dispatcher for every contract that is deployed in the tests (it's more convenient than having to create them in the test manually).test_utils.cairo
provides utilities for fetching all the information about current AMM state (plus some user balances etc.). To fetch theStats
struct, call thenew
method on it withCtx
andDispatchers
as args.Stats
also implementPrintTrait
for more convenient debugging.
You can look into tests/test_dummy.cairo
to see an example of how to write a new test - how to deploy the setup, prank the AMM, mock the Pragma price, fetch the AMM state etc.
Deployment described using starkli
, version 0.1.20 (e4d2307)
.
There will be a lot of invoking and deploying, so it might be useful to make some aliases:
alias sinv='starkli invoke --account /path/to/account --keystore /path/to/key.json --rpc http://rpc.address.here
alias depl='starkli deploy --account /path/to/account --keystore /path/to/key.json --rpc http://rpc.address.here
alias decl='starkli declare --account /path/to/account --keystore /path/to/key.json --rpc http://rpc.address.here
-
Build the contracts with
scarb build
-
Declare the AMM and tokens and export the hashes
-
AMM
decl ./target/dev/carmine_protocol_AMM.contract_class.json
export AMM_HASH=...
-
LP Token
decl ./target/dev/carmine_protocol_LPToken.contract_class.json
export LPT_HASH=...
-
OP Token
decl ./target/dev/carmine_protocol_OptionToken.contract_class.json
export OPT_HASH=...
-
-
Export some additional vars
export ETH_ADDR=0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7
export USDC_ADDR=0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8
export BTC_ADDR=0x03fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac
export INITIAL_VOL=1844674407370955161600
export CALL_TYPE=0
export PUT_TYPE=1
export LONG_SIDE=0
export SHORT_SIDE=1
export ETH_STRIKE_CALL=32281802128991715328000
export ETH_STRIKE_PUT=31359464925306237747200
- Note: Strikes and inital volatility are in Fixed format, meaning they are calculated as
value * 2**64
-
Deploy AMM
export OWNER_ADDR=...
depl $AMM_HASH $OWNER_ADDR
export AMM_ADDR=...
-
Deploy LP Tokens
- CALL
depl $LPT_HASH str:ETHCALL str:EC $AMM_ADDR
export ETH_CALL_LPT=...
- PUT
depl $LPT_HASH str:ETHPUT str:EP $AMM_ADDR
export ETH_PUT_LPT=...
- CALL
-
Add LP tokens to the AMM
-
export VOLADJSPD_ETHC=18446744073709551616
-
export VOLADJSPD_ETHP=11529215046068469760000
-
export MILLIE_USDC=1000000000000
-
export MILLIE_ETH=1000000000000000000000000
-
sinv $AMM_ADDR add_lptoken $USDC_ADDR $ETH_ADDR $CALL_TYPE $ETH_CALL_LPT $VOLADJSPD_ETHC 0 $MILLIE_ETH 0
-
sinv $AMM_ADDR add_lptoken $USDC_ADDR $ETH_ADDR $PUT_TYPE $ETH_PUT_LPT $VOLADJSPD_ETHP 0 $MILLIE_USDC 0
-
-
Deploy OP Tokens
-
export MATURITY=...
(UNIX timestamp) -
export ETH_STRIKE_CALL=...
(Fixed format) -
export ETH_STRIKE_PUT=...
(Fixed format) -
LONG CALL
depl $OPT_HASH str:ETH-LC str:ELC $AMM_ADDR $USDC_ADDR $ETH_ADDR $CALL_TYPE $ETH_STRIKE_CALL $MATURITY $LONG_SIDE
export OPT_LONG_CALL=...
-
SHORT CALL
depl $OPT_HASH str:ETH-SC str:ESC $AMM_ADDR $USDC_ADDR $ETH_ADDR $CALL_TYPE $ETH_STRIKE_CALL $MATURITY $SHORT_SIDE
export OPT_SHORT_CALL=...
-
LONG PUT
depl $OPT_HASH str:ETH-LP str:ELC $AMM_ADDR $USDC_ADDR $ETH_ADDR $PUT_TYPE $ETH_STRIKE_PUT $MATURITY $LONG_SIDE
export OPT_LONG_PUT=...
-
SHORT PUT
depl $OPT_HASH str:ETH-SP str:ESC $AMM_ADDR $USDC_ADDR $ETH_ADDR $PUT_TYPE $ETH_STRIKE_PUT $MATURITY $SHORT_SIDE
export OPT_SHORT_PUT=...
-
-
Add OP tokens to the AMM
-
export INITIAL_VOL=1844674407370955161600
-
CALLS
sinv $AMM_ADDR add_option_both_sides $MATURITY $ETH_STRIKE_CALL 0 $USDC_ADDR $ETH_ADDR 0 $ETH_CALL_LPT $OPT_LONG_CALL $OPT_SHORT_CALL $INITIAL_VOL 0
-
PUTS
sinv $AMM_ADDR add_option_both_sides $MATURITY $ETH_STRIKE_PUT 0 $USDC_ADDR $ETH_ADDR 1 $ETH_PUT_LPT $OPT_LONG_PUT $OPT_SHORT_PUT $INITIAL_VOL 0
-
-
Approve AMM for spending ETH/USDC
-
ETH
sinv $ETH_ADDR approve $AMM_ADDR 1000000000000000000 0
-
USDC
sinv $USDC_ADDR approve $AMM_ADDR 2000000000 0
-
-
Add liquidity
-
CALL
sinv $AMM_ADDR deposit_liquidity $ETH_ADDR $USDC_ADDR $ETH_ADDR $CALL_TYPE 5000000000000000 0
-
PUT
sinv $AMM_ADDR deposit_liquidity $USDC_ADDR $USDC_ADDR $ETH_ADDR $PUT_TYPE 1000000000 0
-
-
Check LP Token balance
-
CALL
starkli call $ETH_CALL_LPT balanceOf $OWNER_ADDR
-
PUT
starkli call $ETH_PUT_LPT balanceOf $OWNER_ADDR
-
-
Check AMM Lpool balances
- CALL
starkli call $AMM_ADDR get_lpool_balance $ETH_CALL_LPT
- PUT
starkli call $AMM_ADDR get_lpool_balance $ETH_PUT_LPT
- CALL
-
Set max option size and permission for trading halt (owner has that by default)
sinv $AMM_ADDR set_max_option_size_percent_of_voladjspd 50
export ALLOWED_TO_HALT_TRADING_ADDR=...
sinv $AMM_ADDR set_trading_halt_permission $ALLOWED_TO_HALT_TRADING_ADDR 1
-
YOLO into some Options
-
CALL
-
LONG
sinv $AMM_ADDR trade_open $CALL_TYPE $ETH_STRIKE_CALL 0 $MATURITY $LONG_SIDE 10000000000000 $USDC_ADDR $ETH_ADDR 23058430092136939520000 0 1701099575
-
SHORT
sinv $AMM_ADDR trade_open $CALL_TYPE $ETH_STRIKE_CALL 0 $MATURITY $SHORT_SIDE 10000000000000 $USDC_ADDR $ETH_ADDR 1 0 1701099575
-
-
PUT
-
LONG
sinv $AMM_ADDR trade_open $PUT_TYPE $ETH_STRIKE_PUT 0 $MATURITY $LONG_SIDE 10000000000000 $USDC_ADDR $ETH_ADDR 23058430092136939520000 0 1701099575
-
SHORT
sinv $AMM_ADDR trade_open $PUT_TYPE $ETH_STRIKE_PUT 0 $MATURITY $SHORT_SIDE 10000000000000 $USDC_ADDR $ETH_ADDR 1 0 1701099575
-
-
-
Un-Yolo some Option
- LONG CALL
sinv $AMM_ADDR trade_close $CALL_TYPE $ETH_STRIKE_CALL 0 $MATURITY $LONG_SIDE 10000000000000 $USDC_ADDR $ETH_ADDR 1 0 1701099575
- LONG CALL