├── .gitignore ├── .gitmodules ├── .rustfmt.toml ├── Anchor.toml ├── Cargo.toml ├── LICENSE ├── README.md ├── build.sh ├── client ├── dexterity │ ├── __init__.py │ ├── codegen │ │ ├── alpha_risk_engine │ │ │ ├── __init__.py │ │ │ ├── accounts.py │ │ │ ├── addrs.py │ │ │ ├── instructions │ │ │ │ ├── __init__.py │ │ │ │ ├── create_risk_state_account.py │ │ │ │ ├── instruction_tag.py │ │ │ │ ├── validate_account_health.py │ │ │ │ └── validate_account_liquidation.py │ │ │ └── types │ │ │ │ ├── __init__.py │ │ │ │ └── health.py │ │ ├── dex │ │ │ ├── __init__.py │ │ │ ├── accounts.py │ │ │ ├── addrs.py │ │ │ ├── constants.py │ │ │ ├── instructions │ │ │ │ ├── __init__.py │ │ │ │ ├── cancel_order.py │ │ │ │ ├── choose_successor.py │ │ │ │ ├── claim_authority.py │ │ │ │ ├── clear_expired_orderbook.py │ │ │ │ ├── consume_orderbook_events.py │ │ │ │ ├── deposit_funds.py │ │ │ │ ├── initialize_combo.py │ │ │ │ ├── initialize_market_product.py │ │ │ │ ├── initialize_market_product_group.py │ │ │ │ ├── initialize_trader_risk_group.py │ │ │ │ ├── instruction_tag.py │ │ │ │ ├── new_order.py │ │ │ │ ├── remove_market_product.py │ │ │ │ ├── sweep_fees.py │ │ │ │ ├── transfer_full_position.py │ │ │ │ ├── update_product_funding.py │ │ │ │ ├── update_trader_funding.py │ │ │ │ └── withdraw_funds.py │ │ │ └── types │ │ │ │ ├── __init__.py │ │ │ │ ├── account_tag.py │ │ │ │ ├── action_status.py │ │ │ │ ├── bitset.py │ │ │ │ ├── call_back_info.py │ │ │ │ ├── cancel_order_params.py │ │ │ │ ├── clear_expired_orderbook_params.py │ │ │ │ ├── combo.py │ │ │ │ ├── consume_orderbook_events_params.py │ │ │ │ ├── deposit_funds_params.py │ │ │ │ ├── dex_error.py │ │ │ │ ├── fractional.py │ │ │ │ ├── health_info.py │ │ │ │ ├── health_result.py │ │ │ │ ├── health_status.py │ │ │ │ ├── initialize_combo_params.py │ │ │ │ ├── initialize_market_product_group_params.py │ │ │ │ ├── initialize_market_product_params.py │ │ │ │ ├── leg.py │ │ │ │ ├── liquidation_info.py │ │ │ │ ├── market_product_group.py │ │ │ │ ├── new_order_params.py │ │ │ │ ├── open_orders.py │ │ │ │ ├── open_orders_metadata.py │ │ │ │ ├── open_orders_node.py │ │ │ │ ├── operation_type.py │ │ │ │ ├── order_info.py │ │ │ │ ├── order_type.py │ │ │ │ ├── outright.py │ │ │ │ ├── params.py │ │ │ │ ├── price_ewma.py │ │ │ │ ├── product.py │ │ │ │ ├── product_array.py │ │ │ │ ├── product_metadata.py │ │ │ │ ├── product_status.py │ │ │ │ ├── risk_output_register.py │ │ │ │ ├── social_loss.py │ │ │ │ ├── trader_fee_params.py │ │ │ │ ├── trader_fees.py │ │ │ │ ├── trader_position.py │ │ │ │ ├── trader_risk_group.py │ │ │ │ ├── update_product_funding_params.py │ │ │ │ ├── util_error.py │ │ │ │ └── withdraw_funds_params.py │ │ ├── instruments │ │ │ ├── __init__.py │ │ │ ├── accounts.py │ │ │ ├── addrs.py │ │ │ ├── instructions │ │ │ │ ├── __init__.py │ │ │ │ ├── close_derivative_account.py │ │ │ │ ├── initialize_derivative.py │ │ │ │ ├── initialize_fixed_income.py │ │ │ │ ├── instruction_tag.py │ │ │ │ ├── settle_derivative.py │ │ │ │ └── settle_fixed_income.py │ │ │ └── types │ │ │ │ ├── __init__.py │ │ │ │ ├── account_tag.py │ │ │ │ ├── derivative_error.py │ │ │ │ ├── derivative_metadata.py │ │ │ │ ├── expiration_status.py │ │ │ │ ├── fixed_income_metadata.py │ │ │ │ ├── initialize_derivative_params.py │ │ │ │ ├── initialize_fixed_income_params.py │ │ │ │ ├── instrument_type.py │ │ │ │ └── oracle_type.py │ │ └── noop_risk_engine │ │ │ ├── __init__.py │ │ │ ├── addrs.py │ │ │ └── instructions │ │ │ ├── __init__.py │ │ │ ├── create_risk_state_account.py │ │ │ ├── instruction_tag.py │ │ │ ├── validate_account_health.py │ │ │ └── validate_account_liquidation.py │ ├── constant_fees │ │ ├── actions.py │ │ ├── addrs.py │ │ ├── instructions.py │ │ └── state.py │ ├── dex │ │ ├── actions.py │ │ ├── addrs.py │ │ └── sdk_context.py │ ├── dummy_oracle │ │ ├── actions.py │ │ ├── instructions │ │ │ ├── __init__.py │ │ │ ├── common.py │ │ │ ├── initialize_clock.py │ │ │ ├── initialize_oracle.py │ │ │ ├── update_clock.py │ │ │ └── update_price.py │ │ └── state │ │ │ ├── __init__.py │ │ │ ├── clock.py │ │ │ ├── common.py │ │ │ └── oracle_price.py │ ├── instruments │ │ ├── actions.py │ │ └── instructions │ │ │ ├── __init__.py │ │ │ ├── initialize_derivative.py │ │ │ └── initialize_fixed_income.py │ ├── program_ids.py │ ├── risk │ │ └── actions.py │ ├── scripts │ │ ├── build │ │ ├── discriminant.py │ │ ├── extract_program_ids.py │ │ ├── generate_code.py │ │ ├── get_trader_risk_groups_key.py │ │ ├── keypair_to_b58.py │ │ └── start_test_validator.py │ └── utils │ │ ├── __init__.py │ │ ├── aob │ │ ├── __init__.py │ │ ├── instructions.py │ │ └── state │ │ │ ├── __init__.py │ │ │ ├── base.py │ │ │ ├── event_queue.py │ │ │ ├── market_state.py │ │ │ └── slab.py │ │ ├── random_hash.py │ │ └── solana.py ├── poetry.lock ├── pyproject.toml └── requirements.txt ├── deploy_all.sh ├── dexteritysdk ├── Cargo.toml └── src │ ├── admin.rs │ ├── bootstrap.rs │ ├── common │ ├── mod.rs │ └── utils.rs │ ├── context.rs │ ├── instrument │ ├── initialize_derivative.rs │ ├── mod.rs │ └── settle_derivative.rs │ ├── lib.rs │ ├── oracle │ ├── create_clock.rs │ ├── create_oracle.rs │ ├── mod.rs │ ├── update_clock.rs │ └── update_oracle.rs │ ├── processor │ ├── cancel_order.rs │ ├── clear_expired_orderbook.rs │ ├── combo.rs │ ├── consume_orderbook_events.rs │ ├── deposit_funds.rs │ ├── fees.rs │ ├── market_product.rs │ ├── market_product_group.rs │ ├── mod.rs │ ├── new_order.rs │ ├── orderbook.rs │ ├── remove_market_product.rs │ ├── trader_risk_group.rs │ ├── transfer_full_position.rs │ ├── update_product_funding.rs │ └── update_trader_funding.rs │ ├── sdk_client.rs │ ├── state.rs │ └── trader.rs ├── master_program_config.json ├── package.json ├── programs ├── dex │ ├── Cargo.toml │ ├── src │ │ ├── error.rs │ │ ├── lib.rs │ │ ├── processor │ │ │ ├── cancel_order.rs │ │ │ ├── change_authority.rs │ │ │ ├── clear_expired_orderbook.rs │ │ │ ├── consume_orderbook_events.rs │ │ │ ├── deposit_funds.rs │ │ │ ├── initialize_combo.rs │ │ │ ├── initialize_market_product.rs │ │ │ ├── initialize_market_product_group.rs │ │ │ ├── initialize_trader_risk_group.rs │ │ │ ├── mod.rs │ │ │ ├── new_order.rs │ │ │ ├── remove_market_product.rs │ │ │ ├── sweep_fees.rs │ │ │ ├── transfer_full_position.rs │ │ │ ├── update_product_funding.rs │ │ │ ├── update_trader_funding.rs │ │ │ └── withdraw_funds.rs │ │ ├── state │ │ │ ├── callback_info.rs │ │ │ ├── constants.rs │ │ │ ├── enums.rs │ │ │ ├── fee_model.rs │ │ │ ├── market_product_group.rs │ │ │ ├── mod.rs │ │ │ ├── open_orders.rs │ │ │ ├── products.rs │ │ │ ├── risk_engine_register.rs │ │ │ └── trader_risk_group.rs │ │ └── utils │ │ │ ├── bitset.rs │ │ │ ├── cpi.rs │ │ │ ├── loadable.rs │ │ │ ├── logs.rs │ │ │ ├── mod.rs │ │ │ ├── numeric.rs │ │ │ ├── orderbook.rs │ │ │ ├── param.rs │ │ │ └── validation.rs │ └── tests │ │ ├── setup.rs │ │ ├── test_alpha_risk_engine.rs │ │ ├── test_combo_alpha_risk_engine.rs │ │ ├── test_combo_orders.rs │ │ ├── test_expiration.rs │ │ ├── test_funding.rs │ │ ├── test_liquidation_simple_risk_engine.rs │ │ ├── test_new_order_rounding_logic.rs │ │ ├── test_no_negative_order_size.rs │ │ ├── test_orderbook_layering.rs │ │ ├── test_replace_trader_position.rs │ │ ├── test_self_trade.rs │ │ ├── test_simple_trade.rs │ │ └── test_sweep_fees.rs ├── dummy-oracle │ ├── Cargo.toml │ └── src │ │ ├── entrypoint.rs │ │ ├── error.rs │ │ ├── instruction.rs │ │ ├── lib.rs │ │ ├── processor.rs │ │ ├── processor │ │ ├── initialize_clock.rs │ │ ├── initialize_oracle.rs │ │ ├── update_clock.rs │ │ └── update_price.rs │ │ ├── state.rs │ │ └── utils.rs ├── fees │ └── constant-fees │ │ ├── Cargo.toml │ │ └── src │ │ └── lib.rs ├── instruments │ ├── Cargo.toml │ ├── Xargo.toml │ └── src │ │ ├── error.rs │ │ ├── lib.rs │ │ ├── oracle.rs │ │ ├── processor │ │ ├── close_derivative_account.rs │ │ ├── initialize_derivative.rs │ │ ├── mod.rs │ │ └── settle_derivative.rs │ │ └── state │ │ ├── constants.rs │ │ ├── derivative_metadata.rs │ │ ├── enums.rs │ │ └── mod.rs └── risk │ ├── alpha-risk-engine │ ├── Cargo.toml │ └── src │ │ └── lib.rs │ └── noop-risk-engine │ ├── Cargo.toml │ └── src │ └── lib.rs ├── test.sh └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | dist/ 3 | node_modules/ 4 | docs/ 5 | .env 6 | venv 7 | wallet.json 8 | out.log 9 | Cargo.lock 10 | __pycache__/ 11 | .idea/ 12 | protocols/.idea/ 13 | *.pyc 14 | *.ipynb_checkpoints 15 | .vscode/ 16 | deploy_key.json 17 | client/.vscode 18 | CMakeLists.txt 19 | cmake-build-debug -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "programs/agnostic-orderbook"] 2 | path = programs/agnostic-orderbook 3 | url = https://github.com/Bonfida/agnostic-orderbook.git 4 | -------------------------------------------------------------------------------- /Anchor.toml: -------------------------------------------------------------------------------- 1 | [programs.localnet] 2 | instruments = "instruments11111111111111111111111111111111" 3 | dex = "Dex1111111111111111111111111111111111111111" 4 | 5 | [registry] 6 | url = "https://anchor.projectserum.com" 7 | 8 | [provider] 9 | cluster = "localnet" 10 | wallet = "~/.config/solana/id.json" 11 | 12 | [scripts] 13 | test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts" 14 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = [ 4 | "programs/instruments", 5 | "programs/dex", 6 | "programs/agnostic-orderbook/program", 7 | "programs/dummy-oracle", 8 | "programs/risk/*", 9 | "programs/fees/*" 10 | ] 11 | 12 | exclude = [ 13 | "dexteritysdk", 14 | ] 15 | 16 | [profile.release] 17 | lto = "fat" 18 | codegen-units = 1 19 | 20 | [profile.release.build-override] 21 | opt-level = 3 22 | incremental = false 23 | codegen-units = 1 24 | 25 | 26 | [profile.dev] 27 | split-debuginfo = "unpacked" 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dexterity 2 | ## What is Dexterity 3 | At a high level, Dexterity is a smart contract (or collection of smart contracts) that allow for the creation of a decentralized exchange on the Solana blockchain. The modular design of these contracts allows operators to create generic instruments with customizable risk and fee models. 4 | 5 | ## To Deploy 6 | In order to deploy Dexterity, you will need to modify the mock keys in `master_program_config.json` to match the target program IDs. The build script will automatically fill in the keys into the program files. 7 | 8 | If you would like to use the `deploy_all.sh` script. Paste the upgrade authority keypair for each of these contracts into the file `~/.config/solana/dexterity_shared.json`. Be sure to not commit this file. 9 | 10 | ## Build and Run Tests 11 | **Requirements:** 12 | - rust nightly 13 | - solana clis 14 | - [Optional] solana-test-validator 15 | 16 | First, install poetry for the python client (only needed the first time around): 17 | 18 | ```bash 19 | cd client 20 | poetry install 21 | ``` 22 | 23 | Then build and test the protocol 24 | 25 | ```bash 26 | git submodule init 27 | git submodule update 28 | ./build.sh 29 | ./test.sh 30 | ``` 31 | 32 | Note that if you use the `--replace` option in the `build.sh` script, you will need to explicitly call `cargo build-bpf` in the root directory to seed the target folder with program keypair files. 33 | -------------------------------------------------------------------------------- /client/dexterity/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solana-labs/dexterity/56c8341fe64183d200767c646050260ef99a6f70/client/dexterity/__init__.py -------------------------------------------------------------------------------- /client/dexterity/codegen/alpha_risk_engine/__init__.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | import dexterity.codegen.alpha_risk_engine.accounts as accounts 3 | import dexterity.codegen.alpha_risk_engine.instructions as instructions 4 | import dexterity.codegen.alpha_risk_engine.types as types 5 | 6 | # LOCK-END 7 | 8 | 9 | -------------------------------------------------------------------------------- /client/dexterity/codegen/alpha_risk_engine/accounts.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from dexterity.codegen.alpha_risk_engine.types.health import Health 3 | from podite import ( 4 | Enum, 5 | U64, 6 | pod, 7 | ) 8 | from solmate.anchor import AccountDiscriminant 9 | 10 | # LOCK-END 11 | 12 | 13 | # LOCK-BEGIN[accounts]: DON'T MODIFY 14 | @pod 15 | class Accounts(Enum[U64]): 16 | HEALTH = AccountDiscriminant(field=Health) 17 | # LOCK-END 18 | 19 | @classmethod 20 | def to_bytes(cls, obj, **kwargs): 21 | return cls.pack(obj, converter="bytes", **kwargs) 22 | 23 | @classmethod 24 | def from_bytes(cls, raw, **kwargs): 25 | return cls.unpack(raw, converter="bytes", **kwargs) 26 | -------------------------------------------------------------------------------- /client/dexterity/codegen/alpha_risk_engine/addrs.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from solana.publickey import PublicKey 3 | 4 | # LOCK-END 5 | 6 | 7 | # LOCK-BEGIN[addresses]: DON'T MODIFY 8 | # LOCK-END 9 | -------------------------------------------------------------------------------- /client/dexterity/codegen/alpha_risk_engine/instructions/__init__.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from .create_risk_state_account import ( 3 | CreateRiskStateAccountIx, 4 | create_risk_state_account, 5 | ) 6 | from .instruction_tag import InstructionTag 7 | from .validate_account_health import ( 8 | ValidateAccountHealthIx, 9 | validate_account_health, 10 | ) 11 | from .validate_account_liquidation import ( 12 | ValidateAccountLiquidationIx, 13 | validate_account_liquidation, 14 | ) 15 | 16 | # LOCK-END 17 | -------------------------------------------------------------------------------- /client/dexterity/codegen/alpha_risk_engine/instructions/instruction_tag.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from podite import ( 3 | Enum, 4 | U64, 5 | pod, 6 | ) 7 | from solmate.anchor import InstructionDiscriminant 8 | 9 | # LOCK-END 10 | 11 | 12 | # LOCK-BEGIN[instruction_tag]: DON'T MODIFY 13 | @pod 14 | class InstructionTag(Enum[U64]): 15 | VALIDATE_ACCOUNT_HEALTH = InstructionDiscriminant() 16 | VALIDATE_ACCOUNT_LIQUIDATION = InstructionDiscriminant() 17 | CREATE_RISK_STATE_ACCOUNT = InstructionDiscriminant() 18 | # LOCK-END 19 | -------------------------------------------------------------------------------- /client/dexterity/codegen/alpha_risk_engine/types/__init__.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from .health import Health 3 | 4 | # LOCK-END 5 | -------------------------------------------------------------------------------- /client/dexterity/codegen/alpha_risk_engine/types/health.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from dexterity.codegen.dex.types.fractional import Fractional 3 | from podite import ( 4 | Vec, 5 | pod, 6 | ) 7 | 8 | # LOCK-END 9 | 10 | 11 | # LOCK-BEGIN[class(Health)]: DON'T MODIFY 12 | @pod 13 | class Health: 14 | margin_req: Fractional 15 | portfolio_value: Fractional 16 | total_abs_dollar_position: Fractional 17 | abs_dollar_position: Vec[Fractional] 18 | # LOCK-END 19 | 20 | @classmethod 21 | def to_bytes(cls, obj, **kwargs): 22 | return cls.pack(obj, converter="bytes", **kwargs) 23 | 24 | @classmethod 25 | def from_bytes(cls, raw, **kwargs): 26 | return cls.unpack(raw, converter="bytes", **kwargs) 27 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/__init__.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | import dexterity.codegen.dex.accounts as accounts 3 | import dexterity.codegen.dex.constants as constants 4 | import dexterity.codegen.dex.instructions as instructions 5 | import dexterity.codegen.dex.types as types 6 | 7 | # LOCK-END 8 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/accounts.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from dexterity.codegen.dex.types.market_product_group import MarketProductGroup 3 | from dexterity.codegen.dex.types.product_array import ProductArray 4 | from dexterity.codegen.dex.types.risk_output_register import RiskOutputRegister 5 | from dexterity.codegen.dex.types.trader_risk_group import TraderRiskGroup 6 | from podite import ( 7 | Enum, 8 | U64, 9 | pod, 10 | ) 11 | from solmate.anchor import AccountDiscriminant 12 | 13 | # LOCK-END 14 | 15 | from podite import AutoTagTypeValueManager 16 | 17 | # LOCK-BEGIN[accounts]: DON'T MODIFY 18 | @pod 19 | class Accounts(Enum[U64]): 20 | MARKET_PRODUCT_GROUP = AccountDiscriminant(field=MarketProductGroup) 21 | PRODUCT_ARRAY = AccountDiscriminant(field=ProductArray) 22 | RISK_OUTPUT_REGISTER = AccountDiscriminant(field=RiskOutputRegister) 23 | TRADER_RISK_GROUP = AccountDiscriminant(field=TraderRiskGroup) 24 | # LOCK-END 25 | 26 | @classmethod 27 | def to_bytes(cls, obj, **kwargs): 28 | return cls.pack(obj, converter="bytes", **kwargs) 29 | 30 | @classmethod 31 | def from_bytes(cls, raw, **kwargs): 32 | return cls.unpack(raw, converter="bytes", format="FORMAT_ZERO_COPY", **kwargs) 33 | 34 | @classmethod 35 | def _from_bytes_partial(cls, buffer, format="FORMAT_ZERO_COPY", **kwargs): 36 | # accounts don't have the same size variants, so must manually use zero-copy and 37 | # set auto tag type. 38 | # TODO make this api cleaner 39 | with AutoTagTypeValueManager(U64): 40 | return super()._inner_from_bytes_partial(buffer, format="FORMAT_ZERO_COPY", **kwargs) 41 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/addrs.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from solana.publickey import PublicKey 3 | 4 | # LOCK-END 5 | 6 | 7 | # LOCK-BEGIN[addresses]: DON'T MODIFY 8 | # LOCK-END 9 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/constants.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from podite import U64 3 | from solmate.dtypes import Usize 4 | 5 | # LOCK-END 6 | 7 | 8 | # LOCK-BEGIN[constants]: DON'T MODIFY 9 | NAME_LEN: Usize = 16 10 | MAX_OUTRIGHTS: Usize = 128 11 | MAX_PRODUCTS: Usize = 256 12 | HEALTH_BUFFER_LEN: Usize = 32 13 | MAX_TRADER_POSITIONS: Usize = 16 14 | MAX_OPEN_ORDERS_PER_POSITION: U64 = 256 15 | MAX_OPEN_ORDERS: Usize = 1024 16 | ANCHOR_DISCRIMINANT_LEN: Usize = 8 17 | SENTINEL: Usize = 0 18 | CALLBACK_INFO_LEN: U64 = 40 19 | CALLBACK_ID_LEN: U64 = 32 20 | MAX_COMBOS: Usize = 128 21 | MAX_LEGS: Usize = 4 22 | SLOTS_1_MIN: U64 = 150 23 | SLOTS_5_MIN: U64 = 750 24 | SLOTS_15_MIN: U64 = 2250 25 | SLOTS_60_MIN: U64 = 9000 26 | # LOCK-END 27 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/instructions/__init__.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from .cancel_order import ( 3 | CancelOrderIx, 4 | cancel_order, 5 | ) 6 | from .choose_successor import ( 7 | ChooseSuccessorIx, 8 | choose_successor, 9 | ) 10 | from .claim_authority import ( 11 | ClaimAuthorityIx, 12 | claim_authority, 13 | ) 14 | from .clear_expired_orderbook import ( 15 | ClearExpiredOrderbookIx, 16 | clear_expired_orderbook, 17 | ) 18 | from .consume_orderbook_events import ( 19 | ConsumeOrderbookEventsIx, 20 | consume_orderbook_events, 21 | ) 22 | from .deposit_funds import ( 23 | DepositFundsIx, 24 | deposit_funds, 25 | ) 26 | from .initialize_combo import ( 27 | InitializeComboIx, 28 | initialize_combo, 29 | ) 30 | from .initialize_market_product import ( 31 | InitializeMarketProductIx, 32 | initialize_market_product, 33 | ) 34 | from .initialize_market_product_group import ( 35 | InitializeMarketProductGroupIx, 36 | initialize_market_product_group, 37 | ) 38 | from .initialize_trader_risk_group import ( 39 | InitializeTraderRiskGroupIx, 40 | initialize_trader_risk_group, 41 | ) 42 | from .instruction_tag import InstructionTag 43 | from .new_order import ( 44 | NewOrderIx, 45 | new_order, 46 | ) 47 | from .remove_market_product import ( 48 | RemoveMarketProductIx, 49 | remove_market_product, 50 | ) 51 | from .sweep_fees import ( 52 | SweepFeesIx, 53 | sweep_fees, 54 | ) 55 | from .transfer_full_position import ( 56 | TransferFullPositionIx, 57 | transfer_full_position, 58 | ) 59 | from .update_product_funding import ( 60 | UpdateProductFundingIx, 61 | update_product_funding, 62 | ) 63 | from .update_trader_funding import ( 64 | UpdateTraderFundingIx, 65 | update_trader_funding, 66 | ) 67 | from .withdraw_funds import ( 68 | WithdrawFundsIx, 69 | withdraw_funds, 70 | ) 71 | 72 | # LOCK-END 73 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/instructions/choose_successor.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from .instruction_tag import InstructionTag 3 | from dataclasses import dataclass 4 | from io import BytesIO 5 | from podite import BYTES_CATALOG 6 | from solana.publickey import PublicKey 7 | from solana.transaction import ( 8 | AccountMeta, 9 | TransactionInstruction, 10 | ) 11 | from solmate.utils import to_account_meta 12 | from typing import ( 13 | List, 14 | Optional, 15 | Union, 16 | ) 17 | 18 | # LOCK-END 19 | 20 | 21 | # LOCK-BEGIN[ix_cls(choose_successor)]: DON'T MODIFY 22 | @dataclass 23 | class ChooseSuccessorIx: 24 | program_id: PublicKey 25 | 26 | # account metas 27 | market_product_group: AccountMeta 28 | authority: AccountMeta 29 | new_authority: AccountMeta 30 | remaining_accounts: Optional[List[AccountMeta]] 31 | 32 | def to_instruction(self): 33 | keys = [] 34 | keys.append(self.market_product_group) 35 | keys.append(self.authority) 36 | keys.append(self.new_authority) 37 | if self.remaining_accounts is not None: 38 | keys.extend(self.remaining_accounts) 39 | 40 | buffer = BytesIO() 41 | buffer.write(InstructionTag.to_bytes(InstructionTag.CHOOSE_SUCCESSOR)) 42 | 43 | return TransactionInstruction( 44 | keys=keys, 45 | program_id=self.program_id, 46 | data=buffer.getvalue(), 47 | ) 48 | 49 | # LOCK-END 50 | 51 | 52 | # LOCK-BEGIN[ix_fn(choose_successor)]: DON'T MODIFY 53 | def choose_successor( 54 | market_product_group: Union[str, PublicKey, AccountMeta], 55 | authority: Union[str, PublicKey, AccountMeta], 56 | new_authority: Union[str, PublicKey, AccountMeta], 57 | remaining_accounts: Optional[List[AccountMeta]] = None, 58 | program_id: Optional[PublicKey] = None, 59 | ): 60 | if program_id is None: 61 | program_id = PublicKey("Dex1111111111111111111111111111111111111111") 62 | 63 | if isinstance(market_product_group, (str, PublicKey)): 64 | market_product_group = to_account_meta( 65 | market_product_group, 66 | is_signer=False, 67 | is_writable=True, 68 | ) 69 | if isinstance(authority, (str, PublicKey)): 70 | authority = to_account_meta( 71 | authority, 72 | is_signer=True, 73 | is_writable=False, 74 | ) 75 | if isinstance(new_authority, (str, PublicKey)): 76 | new_authority = to_account_meta( 77 | new_authority, 78 | is_signer=False, 79 | is_writable=False, 80 | ) 81 | 82 | return ChooseSuccessorIx( 83 | program_id=program_id, 84 | market_product_group=market_product_group, 85 | authority=authority, 86 | new_authority=new_authority, 87 | remaining_accounts=remaining_accounts, 88 | ).to_instruction() 89 | 90 | # LOCK-END 91 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/instructions/claim_authority.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from .instruction_tag import InstructionTag 3 | from dataclasses import dataclass 4 | from io import BytesIO 5 | from podite import BYTES_CATALOG 6 | from solana.publickey import PublicKey 7 | from solana.transaction import ( 8 | AccountMeta, 9 | TransactionInstruction, 10 | ) 11 | from solmate.utils import to_account_meta 12 | from typing import ( 13 | List, 14 | Optional, 15 | Union, 16 | ) 17 | 18 | # LOCK-END 19 | 20 | 21 | # LOCK-BEGIN[ix_cls(claim_authority)]: DON'T MODIFY 22 | @dataclass 23 | class ClaimAuthorityIx: 24 | program_id: PublicKey 25 | 26 | # account metas 27 | market_product_group: AccountMeta 28 | new_authority: AccountMeta 29 | remaining_accounts: Optional[List[AccountMeta]] 30 | 31 | def to_instruction(self): 32 | keys = [] 33 | keys.append(self.market_product_group) 34 | keys.append(self.new_authority) 35 | if self.remaining_accounts is not None: 36 | keys.extend(self.remaining_accounts) 37 | 38 | buffer = BytesIO() 39 | buffer.write(InstructionTag.to_bytes(InstructionTag.CLAIM_AUTHORITY)) 40 | 41 | return TransactionInstruction( 42 | keys=keys, 43 | program_id=self.program_id, 44 | data=buffer.getvalue(), 45 | ) 46 | 47 | # LOCK-END 48 | 49 | 50 | # LOCK-BEGIN[ix_fn(claim_authority)]: DON'T MODIFY 51 | def claim_authority( 52 | market_product_group: Union[str, PublicKey, AccountMeta], 53 | new_authority: Union[str, PublicKey, AccountMeta], 54 | remaining_accounts: Optional[List[AccountMeta]] = None, 55 | program_id: Optional[PublicKey] = None, 56 | ): 57 | if program_id is None: 58 | program_id = PublicKey("Dex1111111111111111111111111111111111111111") 59 | 60 | if isinstance(market_product_group, (str, PublicKey)): 61 | market_product_group = to_account_meta( 62 | market_product_group, 63 | is_signer=False, 64 | is_writable=True, 65 | ) 66 | if isinstance(new_authority, (str, PublicKey)): 67 | new_authority = to_account_meta( 68 | new_authority, 69 | is_signer=True, 70 | is_writable=False, 71 | ) 72 | 73 | return ClaimAuthorityIx( 74 | program_id=program_id, 75 | market_product_group=market_product_group, 76 | new_authority=new_authority, 77 | remaining_accounts=remaining_accounts, 78 | ).to_instruction() 79 | 80 | # LOCK-END 81 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/instructions/initialize_combo.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from .instruction_tag import InstructionTag 3 | from dataclasses import dataclass 4 | from dexterity.codegen.dex.types import InitializeComboParams 5 | from io import BytesIO 6 | from podite import BYTES_CATALOG 7 | from solana.publickey import PublicKey 8 | from solana.transaction import ( 9 | AccountMeta, 10 | TransactionInstruction, 11 | ) 12 | from solmate.utils import to_account_meta 13 | from typing import ( 14 | List, 15 | Optional, 16 | Union, 17 | ) 18 | 19 | # LOCK-END 20 | 21 | 22 | # LOCK-BEGIN[ix_cls(initialize_combo)]: DON'T MODIFY 23 | @dataclass 24 | class InitializeComboIx: 25 | program_id: PublicKey 26 | 27 | # account metas 28 | authority: AccountMeta 29 | market_product_group: AccountMeta 30 | orderbook: AccountMeta 31 | remaining_accounts: Optional[List[AccountMeta]] 32 | 33 | # data fields 34 | params: InitializeComboParams 35 | 36 | def to_instruction(self): 37 | keys = [] 38 | keys.append(self.authority) 39 | keys.append(self.market_product_group) 40 | keys.append(self.orderbook) 41 | if self.remaining_accounts is not None: 42 | keys.extend(self.remaining_accounts) 43 | 44 | buffer = BytesIO() 45 | buffer.write(InstructionTag.to_bytes(InstructionTag.INITIALIZE_COMBO)) 46 | buffer.write(BYTES_CATALOG.pack(InitializeComboParams, self.params)) 47 | 48 | return TransactionInstruction( 49 | keys=keys, 50 | program_id=self.program_id, 51 | data=buffer.getvalue(), 52 | ) 53 | 54 | # LOCK-END 55 | 56 | 57 | # LOCK-BEGIN[ix_fn(initialize_combo)]: DON'T MODIFY 58 | def initialize_combo( 59 | authority: Union[str, PublicKey, AccountMeta], 60 | market_product_group: Union[str, PublicKey, AccountMeta], 61 | orderbook: Union[str, PublicKey, AccountMeta], 62 | params: InitializeComboParams, 63 | remaining_accounts: Optional[List[AccountMeta]] = None, 64 | program_id: Optional[PublicKey] = None, 65 | ): 66 | if program_id is None: 67 | program_id = PublicKey("Dex1111111111111111111111111111111111111111") 68 | 69 | if isinstance(authority, (str, PublicKey)): 70 | authority = to_account_meta( 71 | authority, 72 | is_signer=True, 73 | is_writable=False, 74 | ) 75 | if isinstance(market_product_group, (str, PublicKey)): 76 | market_product_group = to_account_meta( 77 | market_product_group, 78 | is_signer=False, 79 | is_writable=True, 80 | ) 81 | if isinstance(orderbook, (str, PublicKey)): 82 | orderbook = to_account_meta( 83 | orderbook, 84 | is_signer=False, 85 | is_writable=False, 86 | ) 87 | 88 | return InitializeComboIx( 89 | program_id=program_id, 90 | authority=authority, 91 | market_product_group=market_product_group, 92 | orderbook=orderbook, 93 | remaining_accounts=remaining_accounts, 94 | params=params, 95 | ).to_instruction() 96 | 97 | # LOCK-END 98 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/instructions/instruction_tag.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from podite import ( 3 | Enum, 4 | U64, 5 | pod, 6 | ) 7 | from solmate.anchor import InstructionDiscriminant 8 | 9 | # LOCK-END 10 | 11 | 12 | # LOCK-BEGIN[instruction_tag]: DON'T MODIFY 13 | @pod 14 | class InstructionTag(Enum[U64]): 15 | INITIALIZE_MARKET_PRODUCT_GROUP = InstructionDiscriminant() 16 | INITIALIZE_MARKET_PRODUCT = InstructionDiscriminant() 17 | REMOVE_MARKET_PRODUCT = InstructionDiscriminant() 18 | INITIALIZE_TRADER_RISK_GROUP = InstructionDiscriminant() 19 | NEW_ORDER = InstructionDiscriminant() 20 | CONSUME_ORDERBOOK_EVENTS = InstructionDiscriminant() 21 | CANCEL_ORDER = InstructionDiscriminant() 22 | DEPOSIT_FUNDS = InstructionDiscriminant() 23 | WITHDRAW_FUNDS = InstructionDiscriminant() 24 | UPDATE_PRODUCT_FUNDING = InstructionDiscriminant() 25 | TRANSFER_FULL_POSITION = InstructionDiscriminant() 26 | INITIALIZE_COMBO = InstructionDiscriminant() 27 | UPDATE_TRADER_FUNDING = InstructionDiscriminant() 28 | CLEAR_EXPIRED_ORDERBOOK = InstructionDiscriminant() 29 | SWEEP_FEES = InstructionDiscriminant() 30 | CHOOSE_SUCCESSOR = InstructionDiscriminant() 31 | CLAIM_AUTHORITY = InstructionDiscriminant() 32 | # LOCK-END 33 | 34 | 35 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/instructions/update_product_funding.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from .instruction_tag import InstructionTag 3 | from dataclasses import dataclass 4 | from dexterity.codegen.dex.types import UpdateProductFundingParams 5 | from io import BytesIO 6 | from podite import BYTES_CATALOG 7 | from solana.publickey import PublicKey 8 | from solana.transaction import ( 9 | AccountMeta, 10 | TransactionInstruction, 11 | ) 12 | from solmate.utils import to_account_meta 13 | from typing import ( 14 | List, 15 | Optional, 16 | Union, 17 | ) 18 | 19 | # LOCK-END 20 | 21 | 22 | # LOCK-BEGIN[ix_cls(update_product_funding)]: DON'T MODIFY 23 | @dataclass 24 | class UpdateProductFundingIx: 25 | program_id: PublicKey 26 | 27 | # account metas 28 | market_product_group: AccountMeta 29 | product: AccountMeta 30 | remaining_accounts: Optional[List[AccountMeta]] 31 | 32 | # data fields 33 | params: UpdateProductFundingParams 34 | 35 | def to_instruction(self): 36 | keys = [] 37 | keys.append(self.market_product_group) 38 | keys.append(self.product) 39 | if self.remaining_accounts is not None: 40 | keys.extend(self.remaining_accounts) 41 | 42 | buffer = BytesIO() 43 | buffer.write(InstructionTag.to_bytes(InstructionTag.UPDATE_PRODUCT_FUNDING)) 44 | buffer.write(BYTES_CATALOG.pack(UpdateProductFundingParams, self.params)) 45 | 46 | return TransactionInstruction( 47 | keys=keys, 48 | program_id=self.program_id, 49 | data=buffer.getvalue(), 50 | ) 51 | 52 | # LOCK-END 53 | 54 | 55 | # LOCK-BEGIN[ix_fn(update_product_funding)]: DON'T MODIFY 56 | def update_product_funding( 57 | market_product_group: Union[str, PublicKey, AccountMeta], 58 | product: Union[str, PublicKey, AccountMeta], 59 | params: UpdateProductFundingParams, 60 | remaining_accounts: Optional[List[AccountMeta]] = None, 61 | program_id: Optional[PublicKey] = None, 62 | ): 63 | if program_id is None: 64 | program_id = PublicKey("Dex1111111111111111111111111111111111111111") 65 | 66 | if isinstance(market_product_group, (str, PublicKey)): 67 | market_product_group = to_account_meta( 68 | market_product_group, 69 | is_signer=False, 70 | is_writable=True, 71 | ) 72 | if isinstance(product, (str, PublicKey)): 73 | product = to_account_meta( 74 | product, 75 | is_signer=True, 76 | is_writable=False, 77 | ) 78 | 79 | return UpdateProductFundingIx( 80 | program_id=program_id, 81 | market_product_group=market_product_group, 82 | product=product, 83 | remaining_accounts=remaining_accounts, 84 | params=params, 85 | ).to_instruction() 86 | 87 | # LOCK-END 88 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/instructions/update_trader_funding.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from .instruction_tag import InstructionTag 3 | from dataclasses import dataclass 4 | from io import BytesIO 5 | from podite import BYTES_CATALOG 6 | from solana.publickey import PublicKey 7 | from solana.transaction import ( 8 | AccountMeta, 9 | TransactionInstruction, 10 | ) 11 | from solmate.utils import to_account_meta 12 | from typing import ( 13 | List, 14 | Optional, 15 | Union, 16 | ) 17 | 18 | # LOCK-END 19 | 20 | 21 | # LOCK-BEGIN[ix_cls(update_trader_funding)]: DON'T MODIFY 22 | @dataclass 23 | class UpdateTraderFundingIx: 24 | program_id: PublicKey 25 | 26 | # account metas 27 | market_product_group: AccountMeta 28 | trader_risk_group: AccountMeta 29 | remaining_accounts: Optional[List[AccountMeta]] 30 | 31 | def to_instruction(self): 32 | keys = [] 33 | keys.append(self.market_product_group) 34 | keys.append(self.trader_risk_group) 35 | if self.remaining_accounts is not None: 36 | keys.extend(self.remaining_accounts) 37 | 38 | buffer = BytesIO() 39 | buffer.write(InstructionTag.to_bytes(InstructionTag.UPDATE_TRADER_FUNDING)) 40 | 41 | return TransactionInstruction( 42 | keys=keys, 43 | program_id=self.program_id, 44 | data=buffer.getvalue(), 45 | ) 46 | 47 | # LOCK-END 48 | 49 | 50 | # LOCK-BEGIN[ix_fn(update_trader_funding)]: DON'T MODIFY 51 | def update_trader_funding( 52 | market_product_group: Union[str, PublicKey, AccountMeta], 53 | trader_risk_group: Union[str, PublicKey, AccountMeta], 54 | remaining_accounts: Optional[List[AccountMeta]] = None, 55 | program_id: Optional[PublicKey] = None, 56 | ): 57 | if program_id is None: 58 | program_id = PublicKey("Dex1111111111111111111111111111111111111111") 59 | 60 | if isinstance(market_product_group, (str, PublicKey)): 61 | market_product_group = to_account_meta( 62 | market_product_group, 63 | is_signer=False, 64 | is_writable=True, 65 | ) 66 | if isinstance(trader_risk_group, (str, PublicKey)): 67 | trader_risk_group = to_account_meta( 68 | trader_risk_group, 69 | is_signer=False, 70 | is_writable=True, 71 | ) 72 | 73 | return UpdateTraderFundingIx( 74 | program_id=program_id, 75 | market_product_group=market_product_group, 76 | trader_risk_group=trader_risk_group, 77 | remaining_accounts=remaining_accounts, 78 | ).to_instruction() 79 | 80 | # LOCK-END 81 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/__init__.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from .account_tag import AccountTag 3 | from .action_status import ActionStatus 4 | from .bitset import Bitset 5 | from .call_back_info import CallBackInfo 6 | from .cancel_order_params import CancelOrderParams 7 | from .clear_expired_orderbook_params import ClearExpiredOrderbookParams 8 | from .combo import Combo 9 | from .consume_orderbook_events_params import ConsumeOrderbookEventsParams 10 | from .deposit_funds_params import DepositFundsParams 11 | from .dex_error import DexError 12 | from .fractional import Fractional 13 | from .health_info import HealthInfo 14 | from .health_result import HealthResult 15 | from .health_status import HealthStatus 16 | from .initialize_combo_params import InitializeComboParams 17 | from .initialize_market_product_group_params import InitializeMarketProductGroupParams 18 | from .initialize_market_product_params import InitializeMarketProductParams 19 | from .leg import Leg 20 | from .liquidation_info import LiquidationInfo 21 | from .market_product_group import MarketProductGroup 22 | from .new_order_params import NewOrderParams 23 | from .open_orders import OpenOrders 24 | from .open_orders_metadata import OpenOrdersMetadata 25 | from .open_orders_node import OpenOrdersNode 26 | from .operation_type import OperationType 27 | from .order_info import OrderInfo 28 | from .order_type import OrderType 29 | from .outright import Outright 30 | from .params import Params 31 | from .price_ewma import PriceEwma 32 | from .product import Product 33 | from .product_array import ProductArray 34 | from .product_metadata import ProductMetadata 35 | from .product_status import ProductStatus 36 | from .risk_output_register import RiskOutputRegister 37 | from .social_loss import SocialLoss 38 | from .trader_fee_params import TraderFeeParams 39 | from .trader_fees import TraderFees 40 | from .trader_position import TraderPosition 41 | from .trader_risk_group import TraderRiskGroup 42 | from .update_product_funding_params import UpdateProductFundingParams 43 | from .util_error import UtilError 44 | from .withdraw_funds_params import WithdrawFundsParams 45 | 46 | # LOCK-END 47 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/account_tag.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from podite import ( 3 | AutoTagType, 4 | Enum, 5 | pod, 6 | ) 7 | 8 | # LOCK-END 9 | 10 | 11 | # LOCK-BEGIN[class(AccountTag)]: DON'T MODIFY 12 | @pod 13 | class AccountTag(Enum[AutoTagType]): 14 | UNINITIALIZED = None 15 | MARKET_PRODUCT_GROUP = None 16 | TRADER_RISK_GROUP = None 17 | TRADER_POSITION = None 18 | MARKET_PRODUCT_GROUP_WITH_COMBOS = None 19 | COMBO_GROUP = None 20 | COMBO = None 21 | RISK_PROFILE = None 22 | # LOCK-END 23 | 24 | @classmethod 25 | def _to_bytes_partial(cls, buffer, obj, **kwargs): 26 | # to modify packing, change this method 27 | return super()._to_bytes_partial(buffer, obj, **kwargs) 28 | 29 | @classmethod 30 | def _from_bytes_partial(cls, buffer, **kwargs): 31 | # to modify unpacking, change this method 32 | return super()._from_bytes_partial(buffer, **kwargs) 33 | 34 | @classmethod 35 | def to_bytes(cls, obj, **kwargs): 36 | return cls.pack(obj, converter="bytes", **kwargs) 37 | 38 | @classmethod 39 | def from_bytes(cls, raw, **kwargs): 40 | return cls.unpack(raw, converter="bytes", **kwargs) 41 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/action_status.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from podite import ( 3 | AutoTagType, 4 | Enum, 5 | pod, 6 | ) 7 | 8 | # LOCK-END 9 | 10 | 11 | # LOCK-BEGIN[class(ActionStatus)]: DON'T MODIFY 12 | @pod 13 | class ActionStatus(Enum[AutoTagType]): 14 | APPROVED = None 15 | NOT_APPROVED = None 16 | # LOCK-END 17 | 18 | @classmethod 19 | def _to_bytes_partial(cls, buffer, obj, **kwargs): 20 | # to modify packing, change this method 21 | return super()._to_bytes_partial(buffer, obj, **kwargs) 22 | 23 | @classmethod 24 | def _from_bytes_partial(cls, buffer, **kwargs): 25 | # to modify unpacking, change this method 26 | return super()._from_bytes_partial(buffer, **kwargs) 27 | 28 | @classmethod 29 | def to_bytes(cls, obj, **kwargs): 30 | return cls.pack(obj, converter="bytes", **kwargs) 31 | 32 | @classmethod 33 | def from_bytes(cls, raw, **kwargs): 34 | return cls.unpack(raw, converter="bytes", **kwargs) 35 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/bitset.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from podite import ( 3 | FixedLenArray, 4 | U128, 5 | pod, 6 | ) 7 | 8 | # LOCK-END 9 | 10 | 11 | # LOCK-BEGIN[class(Bitset)]: DON'T MODIFY 12 | @pod 13 | class Bitset: 14 | inner: FixedLenArray[U128, 2] 15 | # LOCK-END 16 | 17 | @classmethod 18 | def to_bytes(cls, obj, **kwargs): 19 | return cls.pack(obj, converter="bytes", **kwargs) 20 | 21 | @classmethod 22 | def from_bytes(cls, raw, **kwargs): 23 | return cls.unpack(raw, converter="bytes", **kwargs) 24 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/call_back_info.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from podite import ( 3 | U64, 4 | pod, 5 | ) 6 | from solana.publickey import PublicKey 7 | 8 | # LOCK-END 9 | 10 | 11 | # LOCK-BEGIN[class(CallBackInfo)]: DON'T MODIFY 12 | @pod 13 | class CallBackInfo: 14 | user_account: PublicKey 15 | open_orders_idx: U64 16 | # LOCK-END 17 | 18 | @classmethod 19 | def to_bytes(cls, obj, **kwargs): 20 | return cls.pack(obj, converter="bytes", **kwargs) 21 | 22 | @classmethod 23 | def from_bytes(cls, raw, **kwargs): 24 | return cls.unpack(raw, converter="bytes", **kwargs) 25 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/cancel_order_params.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from podite import ( 3 | U128, 4 | pod, 5 | ) 6 | 7 | # LOCK-END 8 | 9 | 10 | # LOCK-BEGIN[class(CancelOrderParams)]: DON'T MODIFY 11 | @pod 12 | class CancelOrderParams: 13 | order_id: U128 14 | # LOCK-END 15 | 16 | @classmethod 17 | def to_bytes(cls, obj, **kwargs): 18 | return cls.pack(obj, converter="bytes", **kwargs) 19 | 20 | @classmethod 21 | def from_bytes(cls, raw, **kwargs): 22 | return cls.unpack(raw, converter="bytes", **kwargs) 23 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/clear_expired_orderbook_params.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from podite import ( 3 | U8, 4 | pod, 5 | ) 6 | 7 | # LOCK-END 8 | 9 | 10 | # LOCK-BEGIN[class(ClearExpiredOrderbookParams)]: DON'T MODIFY 11 | @pod 12 | class ClearExpiredOrderbookParams: 13 | num_orders_to_cancel: U8 14 | # LOCK-END 15 | 16 | @classmethod 17 | def to_bytes(cls, obj, **kwargs): 18 | return cls.pack(obj, converter="bytes", **kwargs) 19 | 20 | @classmethod 21 | def from_bytes(cls, raw, **kwargs): 22 | return cls.unpack(raw, converter="bytes", **kwargs) 23 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/combo.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from dexterity.codegen.dex.types.leg import Leg 3 | from dexterity.codegen.dex.types.product_metadata import ProductMetadata 4 | from podite import ( 5 | FixedLenArray, 6 | pod, 7 | ) 8 | from solmate.dtypes import Usize 9 | 10 | # LOCK-END 11 | 12 | 13 | # LOCK-BEGIN[class(Combo)]: DON'T MODIFY 14 | @pod 15 | class Combo: 16 | metadata: ProductMetadata 17 | num_legs: Usize 18 | legs: FixedLenArray["Leg", 4] 19 | # LOCK-END 20 | 21 | @classmethod 22 | def to_bytes(cls, obj, **kwargs): 23 | return cls.pack(obj, converter="bytes", **kwargs) 24 | 25 | @classmethod 26 | def from_bytes(cls, raw, **kwargs): 27 | return cls.unpack(raw, converter="bytes", **kwargs) 28 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/consume_orderbook_events_params.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from podite import ( 3 | U64, 4 | pod, 5 | ) 6 | 7 | # LOCK-END 8 | 9 | 10 | # LOCK-BEGIN[class(ConsumeOrderbookEventsParams)]: DON'T MODIFY 11 | @pod 12 | class ConsumeOrderbookEventsParams: 13 | max_iterations: U64 14 | # LOCK-END 15 | 16 | @classmethod 17 | def to_bytes(cls, obj, **kwargs): 18 | return cls.pack(obj, converter="bytes", **kwargs) 19 | 20 | @classmethod 21 | def from_bytes(cls, raw, **kwargs): 22 | return cls.unpack(raw, converter="bytes", **kwargs) 23 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/deposit_funds_params.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from dexterity.codegen.dex.types.fractional import Fractional 3 | from podite import pod 4 | 5 | # LOCK-END 6 | 7 | 8 | # LOCK-BEGIN[class(DepositFundsParams)]: DON'T MODIFY 9 | @pod 10 | class DepositFundsParams: 11 | quantity: Fractional 12 | # LOCK-END 13 | 14 | @classmethod 15 | def to_bytes(cls, obj, **kwargs): 16 | return cls.pack(obj, converter="bytes", **kwargs) 17 | 18 | @classmethod 19 | def from_bytes(cls, raw, **kwargs): 20 | return cls.unpack(raw, converter="bytes", **kwargs) 21 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/dex_error.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from podite import ( 3 | AutoTagType, 4 | Enum, 5 | pod, 6 | ) 7 | 8 | # LOCK-END 9 | 10 | 11 | # LOCK-BEGIN[class(DexError)]: DON'T MODIFY 12 | @pod 13 | class DexError(Enum[AutoTagType]): 14 | CONTRACT_IS_EXPIRED = None 15 | CONTRACT_IS_NOT_EXPIRED = None 16 | INVALID_SYSTEM_PROGRAM_ACCOUNT = None 17 | INVALID_AOB_PROGRAM_ACCOUNT = None 18 | INVALID_STATE_ACCOUNT_OWNER = None 19 | INVALID_ORDER_INDEX = None 20 | USER_ACCOUNT_FULL = None 21 | TRANSACTION_ABORTED = None 22 | MISSING_USER_ACCOUNT = None 23 | ORDER_NOT_FOUND = None 24 | NO_OP = None 25 | OUTOF_FUNDS = None 26 | USER_ACCOUNT_STILL_ACTIVE = None 27 | MARKET_STILL_ACTIVE = None 28 | INVALID_MARKET_SIGNER_ACCOUNT = None 29 | INVALID_ORDERBOOK_ACCOUNT = None 30 | INVALID_MARKET_ADMIN_ACCOUNT = None 31 | INVALID_BASE_VAULT_ACCOUNT = None 32 | INVALID_QUOTE_VAULT_ACCOUNT = None 33 | FULL_MARKET_PRODUCT_GROUP = None 34 | MISSING_MARKET_PRODUCT = None 35 | INVALID_WITHDRAWAL_AMOUNT = None 36 | INVALID_TAKER_TRADER = None 37 | FUNDS_ERROR = None 38 | INACTIVE_PRODUCT_ERROR = None 39 | TOO_MANY_OPEN_ORDERS_ERROR = None 40 | NO_MORE_OPEN_ORDERS_ERROR = None 41 | NON_ZERO_PRICE_TICK_EXPONENT_ERROR = None 42 | DUPLICATE_PRODUCT_NAME_ERROR = None 43 | INVALID_RISK_RESPONSE_ERROR = None 44 | INVALID_ACCOUNT_HEALTH_ERROR = None 45 | ORDERBOOK_IS_EMPTY_ERROR = None 46 | COMBOS_NOT_REMOVED = None 47 | ACCOUNT_NOT_LIQUIDABLE = None 48 | FUNDING_PRECISION_ERROR = None 49 | PRODUCT_DECIMAL_PRECISION_ERROR = None 50 | PRODUCT_NOT_OUTRIGHT = None 51 | PRODUCT_NOT_COMBO = None 52 | INVALID_SOCIAL_LOSS_CALCULATION = None 53 | PRODUCT_INDEX_MISMATCH = None 54 | INVALID_ORDER_I_D = None 55 | INVALID_BYTES_FOR_ZERO_COPY_DESERIALIZATION = None 56 | # LOCK-END 57 | 58 | @classmethod 59 | def _to_bytes_partial(cls, buffer, obj, **kwargs): 60 | # to modify packing, change this method 61 | return super()._to_bytes_partial(buffer, obj, **kwargs) 62 | 63 | @classmethod 64 | def _from_bytes_partial(cls, buffer, **kwargs): 65 | # to modify unpacking, change this method 66 | return super()._from_bytes_partial(buffer, **kwargs) 67 | 68 | @classmethod 69 | def to_bytes(cls, obj, **kwargs): 70 | return cls.pack(obj, converter="bytes", **kwargs) 71 | 72 | @classmethod 73 | def from_bytes(cls, raw, **kwargs): 74 | return cls.unpack(raw, converter="bytes", **kwargs) 75 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/health_info.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from dexterity.codegen.dex.types.action_status import ActionStatus 3 | from dexterity.codegen.dex.types.health_status import HealthStatus 4 | from podite import pod 5 | 6 | # LOCK-END 7 | 8 | 9 | # LOCK-BEGIN[class(HealthInfo)]: DON'T MODIFY 10 | @pod 11 | class HealthInfo: 12 | health: "HealthStatus" 13 | action: "ActionStatus" 14 | # LOCK-END 15 | 16 | @classmethod 17 | def to_bytes(cls, obj, **kwargs): 18 | return cls.pack(obj, converter="bytes", **kwargs) 19 | 20 | @classmethod 21 | def from_bytes(cls, raw, **kwargs): 22 | return cls.unpack(raw, converter="bytes", **kwargs) 23 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/health_result.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from dexterity.codegen.dex.types.health_info import HealthInfo 3 | from dexterity.codegen.dex.types.liquidation_info import LiquidationInfo 4 | from podite import ( 5 | AutoTagType, 6 | Enum, 7 | Option, 8 | Variant, 9 | named_fields, 10 | pod, 11 | ) 12 | 13 | # LOCK-END 14 | 15 | 16 | # LOCK-BEGIN[class(HealthResult)]: DON'T MODIFY 17 | @pod 18 | class HealthResult(Enum[AutoTagType]): 19 | HEALTH = Variant(field=Option[named_fields(health_info=HealthInfo)]) 20 | LIQUIDATION = Variant(field=Option[named_fields(liquidation_info=LiquidationInfo)]) 21 | # LOCK-END 22 | 23 | @classmethod 24 | def to_bytes(cls, obj, **kwargs): 25 | return cls.pack(obj, converter="bytes", **kwargs) 26 | 27 | @classmethod 28 | def from_bytes(cls, raw, **kwargs): 29 | return cls.unpack(raw, converter="bytes", **kwargs) 30 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/health_status.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from podite import ( 3 | AutoTagType, 4 | Enum, 5 | pod, 6 | ) 7 | 8 | # LOCK-END 9 | 10 | 11 | # LOCK-BEGIN[class(HealthStatus)]: DON'T MODIFY 12 | @pod 13 | class HealthStatus(Enum[AutoTagType]): 14 | HEALTHY = None 15 | UNHEALTHY = None 16 | LIQUIDATABLE = None 17 | NOT_LIQUIDATABLE = None 18 | # LOCK-END 19 | 20 | @classmethod 21 | def _to_bytes_partial(cls, buffer, obj, **kwargs): 22 | # to modify packing, change this method 23 | return super()._to_bytes_partial(buffer, obj, **kwargs) 24 | 25 | @classmethod 26 | def _from_bytes_partial(cls, buffer, **kwargs): 27 | # to modify unpacking, change this method 28 | return super()._from_bytes_partial(buffer, **kwargs) 29 | 30 | @classmethod 31 | def to_bytes(cls, obj, **kwargs): 32 | return cls.pack(obj, converter="bytes", **kwargs) 33 | 34 | @classmethod 35 | def from_bytes(cls, raw, **kwargs): 36 | return cls.unpack(raw, converter="bytes", **kwargs) 37 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/initialize_combo_params.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from dexterity.codegen.dex.types.fractional import Fractional 3 | from podite import ( 4 | FixedLenArray, 5 | I8, 6 | U64, 7 | U8, 8 | Vec, 9 | pod, 10 | ) 11 | 12 | # LOCK-END 13 | 14 | 15 | # LOCK-BEGIN[class(InitializeComboParams)]: DON'T MODIFY 16 | @pod 17 | class InitializeComboParams: 18 | name: FixedLenArray[U8, 16] 19 | tick_size: Fractional 20 | price_offset: Fractional 21 | base_decimals: U64 22 | ratios: Vec[I8] 23 | # LOCK-END 24 | 25 | @classmethod 26 | def to_bytes(cls, obj, **kwargs): 27 | return cls.pack(obj, converter="bytes", **kwargs) 28 | 29 | @classmethod 30 | def from_bytes(cls, raw, **kwargs): 31 | return cls.unpack(raw, converter="bytes", **kwargs) 32 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/initialize_market_product_group_params.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from podite import ( 3 | FixedLenArray, 4 | I16, 5 | U64, 6 | U8, 7 | pod, 8 | ) 9 | 10 | # LOCK-END 11 | 12 | 13 | # LOCK-BEGIN[class(InitializeMarketProductGroupParams)]: DON'T MODIFY 14 | @pod 15 | class InitializeMarketProductGroupParams: 16 | name: FixedLenArray[U8, 16] 17 | validate_account_discriminant_len: U64 18 | find_fees_discriminant_len: U64 19 | validate_account_health_discriminant: FixedLenArray[U8, 8] 20 | validate_account_liquidation_discriminant: FixedLenArray[U8, 8] 21 | create_risk_state_account_discriminant: FixedLenArray[U8, 8] 22 | find_fees_discriminant: FixedLenArray[U8, 8] 23 | max_maker_fee_bps: I16 24 | min_maker_fee_bps: I16 25 | max_taker_fee_bps: I16 26 | min_taker_fee_bps: I16 27 | # LOCK-END 28 | 29 | @classmethod 30 | def to_bytes(cls, obj, **kwargs): 31 | return cls.pack(obj, converter="bytes", **kwargs) 32 | 33 | @classmethod 34 | def from_bytes(cls, raw, **kwargs): 35 | return cls.unpack(raw, converter="bytes", **kwargs) 36 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/initialize_market_product_params.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from dexterity.codegen.dex.types.fractional import Fractional 3 | from podite import ( 4 | FixedLenArray, 5 | U64, 6 | U8, 7 | pod, 8 | ) 9 | 10 | # LOCK-END 11 | 12 | 13 | # LOCK-BEGIN[class(InitializeMarketProductParams)]: DON'T MODIFY 14 | @pod 15 | class InitializeMarketProductParams: 16 | name: FixedLenArray[U8, 16] 17 | tick_size: Fractional 18 | base_decimals: U64 19 | price_offset: Fractional 20 | # LOCK-END 21 | 22 | @classmethod 23 | def to_bytes(cls, obj, **kwargs): 24 | return cls.pack(obj, converter="bytes", **kwargs) 25 | 26 | @classmethod 27 | def from_bytes(cls, raw, **kwargs): 28 | return cls.unpack(raw, converter="bytes", **kwargs) 29 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/leg.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from podite import ( 3 | I64, 4 | pod, 5 | ) 6 | from solana.publickey import PublicKey 7 | from solmate.dtypes import Usize 8 | 9 | # LOCK-END 10 | 11 | 12 | # LOCK-BEGIN[class(Leg)]: DON'T MODIFY 13 | @pod 14 | class Leg: 15 | product_index: Usize 16 | product_key: PublicKey 17 | ratio: I64 18 | # LOCK-END 19 | 20 | @classmethod 21 | def to_bytes(cls, obj, **kwargs): 22 | return cls.pack(obj, converter="bytes", **kwargs) 23 | 24 | @classmethod 25 | def from_bytes(cls, raw, **kwargs): 26 | return cls.unpack(raw, converter="bytes", **kwargs) 27 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/liquidation_info.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from dexterity.codegen.dex.types.action_status import ActionStatus 3 | from dexterity.codegen.dex.types.fractional import Fractional 4 | from dexterity.codegen.dex.types.health_status import HealthStatus 5 | from dexterity.codegen.dex.types.social_loss import SocialLoss 6 | from podite import ( 7 | FixedLenArray, 8 | pod, 9 | ) 10 | 11 | # LOCK-END 12 | 13 | 14 | # LOCK-BEGIN[class(LiquidationInfo)]: DON'T MODIFY 15 | @pod 16 | class LiquidationInfo: 17 | health: "HealthStatus" 18 | action: "ActionStatus" 19 | total_social_loss: "Fractional" 20 | liquidation_price: "Fractional" 21 | social_losses: FixedLenArray["SocialLoss", 16] 22 | # LOCK-END 23 | 24 | @classmethod 25 | def to_bytes(cls, obj, **kwargs): 26 | return cls.pack(obj, converter="bytes", **kwargs) 27 | 28 | @classmethod 29 | def from_bytes(cls, raw, **kwargs): 30 | return cls.unpack(raw, converter="bytes", **kwargs) 31 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/market_product_group.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from dexterity.codegen.dex.types.account_tag import AccountTag 3 | from dexterity.codegen.dex.types.bitset import Bitset 4 | from dexterity.codegen.dex.types.fractional import Fractional 5 | from dexterity.codegen.dex.types.product_array import ProductArray 6 | from podite import ( 7 | FixedLenArray, 8 | I16, 9 | U128, 10 | U16, 11 | U64, 12 | U8, 13 | pod, 14 | ) 15 | from solana.publickey import PublicKey 16 | 17 | # LOCK-END 18 | 19 | from typing import Iterable 20 | from dexterity.codegen.dex import types 21 | 22 | 23 | # LOCK-BEGIN[class(MarketProductGroup)]: DON'T MODIFY 24 | @pod 25 | class MarketProductGroup: 26 | tag: AccountTag 27 | name: FixedLenArray[U8, 16] 28 | authority: PublicKey 29 | successor: PublicKey 30 | vault_mint: PublicKey 31 | collected_fees: Fractional 32 | fee_collector: PublicKey 33 | decimals: U64 34 | risk_engine_program_id: PublicKey 35 | fee_model_program_id: PublicKey 36 | fee_model_configuration_acct: PublicKey 37 | risk_model_configuration_acct: PublicKey 38 | active_flags_products: Bitset 39 | ewma_windows: FixedLenArray[U64, 4] 40 | market_products: "ProductArray" 41 | vault_bump: U16 42 | risk_and_fee_bump: U16 43 | find_fees_discriminant_len: U16 44 | validate_account_discriminant_len: U16 45 | find_fees_discriminant: FixedLenArray[U8, 8] 46 | validate_account_health_discriminant: FixedLenArray[U8, 8] 47 | validate_account_liquidation_discriminant: FixedLenArray[U8, 8] 48 | create_risk_state_account_discriminant: FixedLenArray[U8, 8] 49 | max_maker_fee_bps: I16 50 | min_maker_fee_bps: I16 51 | max_taker_fee_bps: I16 52 | min_taker_fee_bps: I16 53 | fee_output_register: PublicKey 54 | risk_output_register: PublicKey 55 | sequence_number: U128 56 | # LOCK-END 57 | 58 | @classmethod 59 | def to_bytes(cls, obj, **kwargs): 60 | return cls.pack(obj, converter="bytes", **kwargs) 61 | 62 | @classmethod 63 | def from_bytes(cls, raw, **kwargs): 64 | return cls.unpack(raw, converter="bytes", **kwargs) 65 | 66 | def active_products(self) -> Iterable["types.Product"]: 67 | for p in self.market_products.array: 68 | if p.metadata().product_key != SENTINAL_KEY: 69 | yield p 70 | 71 | 72 | SENTINAL_KEY = PublicKey("11111111111111111111111111111111") -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/new_order_params.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from dexterity.codegen.dex.types.fractional import Fractional 3 | from dexterity.codegen.dex.types.order_type import OrderType 4 | from dexterity.utils.aob.state.base import ( 5 | SelfTradeBehavior, 6 | Side, 7 | ) 8 | from podite import ( 9 | U64, 10 | pod, 11 | ) 12 | 13 | # LOCK-END 14 | 15 | 16 | # LOCK-BEGIN[class(NewOrderParams)]: DON'T MODIFY 17 | @pod 18 | class NewOrderParams: 19 | side: Side 20 | max_base_qty: Fractional 21 | order_type: "OrderType" 22 | self_trade_behavior: SelfTradeBehavior 23 | match_limit: U64 24 | limit_price: Fractional 25 | # LOCK-END 26 | 27 | @classmethod 28 | def to_bytes(cls, obj, **kwargs): 29 | return cls.pack(obj, converter="bytes", **kwargs) 30 | 31 | @classmethod 32 | def from_bytes(cls, raw, **kwargs): 33 | return cls.unpack(raw, converter="bytes", **kwargs) 34 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/open_orders.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from dexterity.codegen.dex.types.open_orders_metadata import OpenOrdersMetadata 3 | from dexterity.codegen.dex.types.open_orders_node import OpenOrdersNode 4 | from podite import ( 5 | FixedLenArray, 6 | U64, 7 | pod, 8 | ) 9 | from solmate.dtypes import Usize 10 | 11 | # LOCK-END 12 | 13 | 14 | # LOCK-BEGIN[class(OpenOrders)]: DON'T MODIFY 15 | @pod 16 | class OpenOrders: 17 | free_list_head: Usize 18 | total_open_orders: U64 19 | products: FixedLenArray[OpenOrdersMetadata, 256] 20 | orders: FixedLenArray["OpenOrdersNode", 1024] 21 | # LOCK-END 22 | 23 | @classmethod 24 | def to_bytes(cls, obj, **kwargs): 25 | return cls.pack(obj, converter="bytes", **kwargs) 26 | 27 | @classmethod 28 | def from_bytes(cls, raw, **kwargs): 29 | return cls.unpack(raw, converter="bytes", **kwargs) 30 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/open_orders_metadata.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from dexterity.codegen.dex.types.fractional import Fractional 3 | from podite import ( 4 | U64, 5 | pod, 6 | ) 7 | from solmate.dtypes import Usize 8 | 9 | # LOCK-END 10 | 11 | 12 | # LOCK-BEGIN[class(OpenOrdersMetadata)]: DON'T MODIFY 13 | @pod 14 | class OpenOrdersMetadata: 15 | ask_qty_in_book: "Fractional" 16 | bid_qty_in_book: "Fractional" 17 | head_index: Usize 18 | num_open_orders: U64 19 | # LOCK-END 20 | 21 | @classmethod 22 | def to_bytes(cls, obj, **kwargs): 23 | return cls.pack(obj, converter="bytes", **kwargs) 24 | 25 | @classmethod 26 | def from_bytes(cls, raw, **kwargs): 27 | return cls.unpack(raw, converter="bytes", **kwargs) 28 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/open_orders_node.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from podite import ( 3 | U128, 4 | pod, 5 | ) 6 | from solmate.dtypes import Usize 7 | 8 | # LOCK-END 9 | 10 | 11 | # LOCK-BEGIN[class(OpenOrdersNode)]: DON'T MODIFY 12 | @pod 13 | class OpenOrdersNode: 14 | id: U128 15 | client_id: U128 16 | prev: Usize 17 | next: Usize 18 | # LOCK-END 19 | 20 | @classmethod 21 | def to_bytes(cls, obj, **kwargs): 22 | return cls.pack(obj, converter="bytes", **kwargs) 23 | 24 | @classmethod 25 | def from_bytes(cls, raw, **kwargs): 26 | return cls.unpack(raw, converter="bytes", **kwargs) 27 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/operation_type.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from podite import ( 3 | AutoTagType, 4 | Enum, 5 | pod, 6 | ) 7 | 8 | # LOCK-END 9 | 10 | 11 | # LOCK-BEGIN[class(OperationType)]: DON'T MODIFY 12 | @pod 13 | class OperationType(Enum[AutoTagType]): 14 | NEW_ORDER = None 15 | CANCEL_ORDER = None 16 | CHECK_HEALTH = None 17 | POSITION_TRANSFER = None 18 | CONSUME_EVENTS = None 19 | # LOCK-END 20 | 21 | @classmethod 22 | def _to_bytes_partial(cls, buffer, obj, **kwargs): 23 | # to modify packing, change this method 24 | return super()._to_bytes_partial(buffer, obj, **kwargs) 25 | 26 | @classmethod 27 | def _from_bytes_partial(cls, buffer, **kwargs): 28 | # to modify unpacking, change this method 29 | return super()._from_bytes_partial(buffer, **kwargs) 30 | 31 | @classmethod 32 | def to_bytes(cls, obj, **kwargs): 33 | return cls.pack(obj, converter="bytes", **kwargs) 34 | 35 | @classmethod 36 | def from_bytes(cls, raw, **kwargs): 37 | return cls.unpack(raw, converter="bytes", **kwargs) 38 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/order_info.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from dexterity.codegen.dex.types.fractional import Fractional 3 | from dexterity.codegen.dex.types.operation_type import OperationType 4 | from dexterity.utils.aob.state.base import Side 5 | from podite import pod 6 | from solmate.dtypes import Usize 7 | 8 | # LOCK-END 9 | 10 | 11 | # LOCK-BEGIN[class(OrderInfo)]: DON'T MODIFY 12 | @pod 13 | class OrderInfo: 14 | total_order_qty: "Fractional" 15 | matched_order_qty: "Fractional" 16 | order_side: Side 17 | is_combo: bool 18 | product_index: Usize 19 | operation_type: "OperationType" 20 | old_ask_qty_in_book: "Fractional" 21 | old_bid_qty_in_book: "Fractional" 22 | # LOCK-END 23 | 24 | @classmethod 25 | def to_bytes(cls, obj, **kwargs): 26 | return cls.pack(obj, converter="bytes", **kwargs) 27 | 28 | @classmethod 29 | def from_bytes(cls, raw, **kwargs): 30 | return cls.unpack(raw, converter="bytes", **kwargs) 31 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/order_type.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from podite import ( 3 | AutoTagType, 4 | Enum, 5 | pod, 6 | ) 7 | 8 | # LOCK-END 9 | 10 | 11 | # LOCK-BEGIN[class(OrderType)]: DON'T MODIFY 12 | @pod 13 | class OrderType(Enum[AutoTagType]): 14 | LIMIT = None 15 | IMMEDIATE_OR_CANCEL = None 16 | FILL_OR_KILL = None 17 | POST_ONLY = None 18 | # LOCK-END 19 | 20 | @classmethod 21 | def _to_bytes_partial(cls, buffer, obj, **kwargs): 22 | # to modify packing, change this method 23 | return super()._to_bytes_partial(buffer, obj, **kwargs) 24 | 25 | @classmethod 26 | def _from_bytes_partial(cls, buffer, **kwargs): 27 | # to modify unpacking, change this method 28 | return super()._from_bytes_partial(buffer, **kwargs) 29 | 30 | @classmethod 31 | def to_bytes(cls, obj, **kwargs): 32 | return cls.pack(obj, converter="bytes", **kwargs) 33 | 34 | @classmethod 35 | def from_bytes(cls, raw, **kwargs): 36 | return cls.unpack(raw, converter="bytes", **kwargs) 37 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/outright.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from dexterity.codegen.dex.types.fractional import Fractional 3 | from dexterity.codegen.dex.types.product_metadata import ProductMetadata 4 | from dexterity.codegen.dex.types.product_status import ProductStatus 5 | from podite import ( 6 | FixedLenArray, 7 | U64, 8 | pod, 9 | ) 10 | from solmate.dtypes import Usize 11 | 12 | # LOCK-END 13 | 14 | 15 | # LOCK-BEGIN[class(Outright)]: DON'T MODIFY 16 | @pod 17 | class Outright: 18 | metadata: "ProductMetadata" 19 | num_queue_events: Usize 20 | product_status: "ProductStatus" 21 | dust: "Fractional" 22 | cum_funding_per_share: "Fractional" 23 | cum_social_loss_per_share: "Fractional" 24 | open_long_interest: "Fractional" 25 | open_short_interest: "Fractional" 26 | padding: FixedLenArray[U64, 14] 27 | # LOCK-END 28 | 29 | @classmethod 30 | def to_bytes(cls, obj, **kwargs): 31 | return cls.pack(obj, converter="bytes", **kwargs) 32 | 33 | @classmethod 34 | def from_bytes(cls, raw, **kwargs): 35 | return cls.unpack(raw, converter="bytes", **kwargs) 36 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/params.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from dexterity.codegen.dex.types.fractional import Fractional 3 | from podite import pod 4 | 5 | # LOCK-END 6 | 7 | 8 | # LOCK-BEGIN[class(Params)]: DON'T MODIFY 9 | @pod 10 | class Params: 11 | quantity: "Fractional" 12 | # LOCK-END 13 | 14 | @classmethod 15 | def to_bytes(cls, obj, **kwargs): 16 | return cls.pack(obj, converter="bytes", **kwargs) 17 | 18 | @classmethod 19 | def from_bytes(cls, raw, **kwargs): 20 | return cls.unpack(raw, converter="bytes", **kwargs) 21 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/price_ewma.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from dexterity.codegen.dex.types.fractional import Fractional 3 | from podite import ( 4 | FixedLenArray, 5 | U64, 6 | pod, 7 | ) 8 | 9 | # LOCK-END 10 | 11 | 12 | # LOCK-BEGIN[class(PriceEwma)]: DON'T MODIFY 13 | @pod 14 | class PriceEwma: 15 | ewma_bid: FixedLenArray["Fractional", 4] 16 | ewma_ask: FixedLenArray["Fractional", 4] 17 | bid: "Fractional" 18 | ask: "Fractional" 19 | slot: U64 20 | prev_bid: "Fractional" 21 | prev_ask: "Fractional" 22 | # LOCK-END 23 | 24 | @classmethod 25 | def to_bytes(cls, obj, **kwargs): 26 | return cls.pack(obj, converter="bytes", **kwargs) 27 | 28 | @classmethod 29 | def from_bytes(cls, raw, **kwargs): 30 | return cls.unpack(raw, converter="bytes", **kwargs) 31 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/product.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from dexterity.codegen.dex.types.combo import Combo 3 | from dexterity.codegen.dex.types.outright import Outright 4 | from podite import ( 5 | AutoTagType, 6 | Enum, 7 | Option, 8 | Variant, 9 | named_fields, 10 | pod, 11 | ) 12 | 13 | # LOCK-END 14 | 15 | import dexterity.codegen.dex.types as types 16 | 17 | 18 | # LOCK-BEGIN[class(Product)]: DON'T MODIFY 19 | @pod 20 | class Product(Enum[AutoTagType]): 21 | OUTRIGHT = Variant(field=named_fields(outright=Outright)) 22 | COMBO = Variant(field=named_fields(combo=Combo)) 23 | # LOCK-END 24 | 25 | def metadata(self) -> "types.ProductMetadata": 26 | if getattr(self.field, "outright"): 27 | return self.field.outright.metadata 28 | elif getattr(self.field, "combo"): 29 | return self.field.combo.metadata 30 | else: 31 | raise ValueError(f"Uknown product type for {self}") 32 | 33 | @classmethod 34 | def _to_bytes_partial(cls, buffer, obj, **kwargs): 35 | # to modify packing, change this method 36 | return super()._to_bytes_partial(buffer, obj, **kwargs) 37 | 38 | @classmethod 39 | def _from_bytes_partial(cls, buffer, **kwargs): 40 | # to modify unpacking, change this method 41 | return super()._from_bytes_partial(buffer, **kwargs) 42 | 43 | @classmethod 44 | def to_bytes(cls, obj, **kwargs): 45 | return cls.pack(obj, converter="bytes", **kwargs) 46 | 47 | @classmethod 48 | def from_bytes(cls, raw, **kwargs): 49 | return cls.unpack(raw, converter="bytes", **kwargs) 50 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/product_array.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from dexterity.codegen.dex.types.product import Product 3 | from podite import ( 4 | FixedLenArray, 5 | pod, 6 | ) 7 | 8 | # LOCK-END 9 | 10 | 11 | # LOCK-BEGIN[class(ProductArray)]: DON'T MODIFY 12 | @pod 13 | class ProductArray: 14 | array: FixedLenArray[Product, 256] 15 | # LOCK-END 16 | 17 | @classmethod 18 | def to_bytes(cls, obj, **kwargs): 19 | return cls.pack(obj, converter="bytes", **kwargs) 20 | 21 | @classmethod 22 | def from_bytes(cls, raw, **kwargs): 23 | return cls.unpack(raw, converter="bytes", **kwargs) 24 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/product_metadata.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from dexterity.codegen.dex.types.fractional import Fractional 3 | from dexterity.codegen.dex.types.price_ewma import PriceEwma 4 | from podite import ( 5 | FixedLenArray, 6 | U64, 7 | U8, 8 | pod, 9 | ) 10 | from solana.publickey import PublicKey 11 | 12 | # LOCK-END 13 | 14 | 15 | # LOCK-BEGIN[class(ProductMetadata)]: DON'T MODIFY 16 | @pod 17 | class ProductMetadata: 18 | bump: U64 19 | product_key: PublicKey 20 | name: FixedLenArray[U8, 16] 21 | orderbook: PublicKey 22 | tick_size: "Fractional" 23 | base_decimals: U64 24 | price_offset: "Fractional" 25 | contract_volume: "Fractional" 26 | prices: PriceEwma 27 | # LOCK-END 28 | 29 | @classmethod 30 | def to_bytes(cls, obj, **kwargs): 31 | return cls.pack(obj, converter="bytes", **kwargs) 32 | 33 | @classmethod 34 | def from_bytes(cls, raw, **kwargs): 35 | return cls.unpack(raw, converter="bytes", **kwargs) 36 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/product_status.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from podite import ( 3 | AutoTagType, 4 | Enum, 5 | pod, 6 | ) 7 | 8 | # LOCK-END 9 | 10 | 11 | # LOCK-BEGIN[class(ProductStatus)]: DON'T MODIFY 12 | @pod 13 | class ProductStatus(Enum[AutoTagType]): 14 | UNINITIALIZED = None 15 | INITIALIZED = None 16 | EXPIRED = None 17 | # LOCK-END 18 | 19 | @classmethod 20 | def _to_bytes_partial(cls, buffer, obj, **kwargs): 21 | # to modify packing, change this method 22 | return super()._to_bytes_partial(buffer, obj, **kwargs) 23 | 24 | @classmethod 25 | def _from_bytes_partial(cls, buffer, **kwargs): 26 | # to modify unpacking, change this method 27 | return super()._from_bytes_partial(buffer, **kwargs) 28 | 29 | @classmethod 30 | def to_bytes(cls, obj, **kwargs): 31 | return cls.pack(obj, converter="bytes", **kwargs) 32 | 33 | @classmethod 34 | def from_bytes(cls, raw, **kwargs): 35 | return cls.unpack(raw, converter="bytes", **kwargs) 36 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/risk_output_register.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from dexterity.codegen.dex.types.health_result import HealthResult 3 | from podite import pod 4 | 5 | # LOCK-END 6 | 7 | 8 | # LOCK-BEGIN[class(RiskOutputRegister)]: DON'T MODIFY 9 | @pod 10 | class RiskOutputRegister: 11 | risk_engine_output: HealthResult 12 | # LOCK-END 13 | 14 | @classmethod 15 | def to_bytes(cls, obj, **kwargs): 16 | return cls.pack(obj, converter="bytes", **kwargs) 17 | 18 | @classmethod 19 | def from_bytes(cls, raw, **kwargs): 20 | return cls.unpack(raw, converter="bytes", **kwargs) 21 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/social_loss.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from dexterity.codegen.dex.types.fractional import Fractional 3 | from podite import pod 4 | from solmate.dtypes import Usize 5 | 6 | # LOCK-END 7 | 8 | 9 | # LOCK-BEGIN[class(SocialLoss)]: DON'T MODIFY 10 | @pod 11 | class SocialLoss: 12 | product_index: Usize 13 | amount: "Fractional" 14 | # LOCK-END 15 | 16 | @classmethod 17 | def to_bytes(cls, obj, **kwargs): 18 | return cls.pack(obj, converter="bytes", **kwargs) 19 | 20 | @classmethod 21 | def from_bytes(cls, raw, **kwargs): 22 | return cls.unpack(raw, converter="bytes", **kwargs) 23 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/trader_fee_params.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from dexterity.codegen.dex.types.fractional import Fractional 3 | from dexterity.utils.aob.state.base import Side 4 | from podite import pod 5 | from solana.publickey import PublicKey 6 | 7 | # LOCK-END 8 | 9 | 10 | # LOCK-BEGIN[class(TraderFeeParams)]: DON'T MODIFY 11 | @pod 12 | class TraderFeeParams: 13 | side: Side 14 | is_aggressor: bool 15 | matched_quote_qty: "Fractional" 16 | matched_base_qty: "Fractional" 17 | product: PublicKey 18 | # LOCK-END 19 | 20 | @classmethod 21 | def to_bytes(cls, obj, **kwargs): 22 | return cls.pack(obj, converter="bytes", **kwargs) 23 | 24 | @classmethod 25 | def from_bytes(cls, raw, **kwargs): 26 | return cls.unpack(raw, converter="bytes", **kwargs) 27 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/trader_fees.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from podite import ( 3 | I32, 4 | pod, 5 | ) 6 | from solmate.dtypes import UnixTimestamp 7 | 8 | # LOCK-END 9 | 10 | 11 | # LOCK-BEGIN[class(TraderFees)]: DON'T MODIFY 12 | @pod 13 | class TraderFees: 14 | valid_until: UnixTimestamp 15 | maker_fee_bps: I32 16 | taker_fee_bps: I32 17 | # LOCK-END 18 | 19 | @classmethod 20 | def to_bytes(cls, obj, **kwargs): 21 | return cls.pack(obj, converter="bytes", **kwargs) 22 | 23 | @classmethod 24 | def from_bytes(cls, raw, **kwargs): 25 | return cls.unpack(raw, converter="bytes", **kwargs) 26 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/trader_position.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from dexterity.codegen.dex.types.account_tag import AccountTag 3 | from dexterity.codegen.dex.types.fractional import Fractional 4 | from podite import pod 5 | from solana.publickey import PublicKey 6 | from solmate.dtypes import Usize 7 | 8 | # LOCK-END 9 | 10 | 11 | # LOCK-BEGIN[class(TraderPosition)]: DON'T MODIFY 12 | @pod 13 | class TraderPosition: 14 | tag: "AccountTag" 15 | product_key: PublicKey 16 | position: "Fractional" 17 | pending_position: "Fractional" 18 | product_index: Usize 19 | last_cum_funding_snapshot: "Fractional" 20 | last_social_loss_snapshot: "Fractional" 21 | # LOCK-END 22 | 23 | @classmethod 24 | def to_bytes(cls, obj, **kwargs): 25 | return cls.pack(obj, converter="bytes", **kwargs) 26 | 27 | @classmethod 28 | def from_bytes(cls, raw, **kwargs): 29 | return cls.unpack(raw, converter="bytes", **kwargs) 30 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/trader_risk_group.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from dexterity.codegen.dex.types.account_tag import AccountTag 3 | from dexterity.codegen.dex.types.fractional import Fractional 4 | from dexterity.codegen.dex.types.open_orders import OpenOrders 5 | from dexterity.codegen.dex.types.trader_position import TraderPosition 6 | from podite import ( 7 | FixedLenArray, 8 | I32, 9 | U128, 10 | U8, 11 | pod, 12 | ) 13 | from solana.publickey import PublicKey 14 | from solmate.dtypes import UnixTimestamp 15 | 16 | # LOCK-END 17 | 18 | 19 | # LOCK-BEGIN[class(TraderRiskGroup)]: DON'T MODIFY 20 | @pod 21 | class TraderRiskGroup: 22 | tag: AccountTag 23 | market_product_group: PublicKey 24 | owner: PublicKey 25 | active_products: FixedLenArray[U8, 128] 26 | total_deposited: Fractional 27 | total_withdrawn: Fractional 28 | cash_balance: Fractional 29 | pending_cash_balance: Fractional 30 | pending_fees: Fractional 31 | valid_until: UnixTimestamp 32 | maker_fee_bps: I32 33 | taker_fee_bps: I32 34 | trader_positions: FixedLenArray[TraderPosition, 16] 35 | risk_state_account: PublicKey 36 | fee_state_account: PublicKey 37 | client_order_id: U128 38 | open_orders: OpenOrders 39 | # LOCK-END 40 | 41 | @classmethod 42 | def to_bytes(cls, obj, **kwargs): 43 | return cls.pack(obj, converter="bytes", **kwargs) 44 | 45 | @classmethod 46 | def from_bytes(cls, raw, **kwargs): 47 | return cls.unpack(raw, converter="bytes", **kwargs) 48 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/update_product_funding_params.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from dexterity.codegen.dex.types.fractional import Fractional 3 | from podite import pod 4 | 5 | # LOCK-END 6 | 7 | 8 | # LOCK-BEGIN[class(UpdateProductFundingParams)]: DON'T MODIFY 9 | @pod 10 | class UpdateProductFundingParams: 11 | amount: Fractional 12 | expired: bool 13 | # LOCK-END 14 | 15 | @classmethod 16 | def to_bytes(cls, obj, **kwargs): 17 | return cls.pack(obj, converter="bytes", **kwargs) 18 | 19 | @classmethod 20 | def from_bytes(cls, raw, **kwargs): 21 | return cls.unpack(raw, converter="bytes", **kwargs) 22 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/util_error.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from podite import ( 3 | AutoTagType, 4 | Enum, 5 | pod, 6 | ) 7 | 8 | # LOCK-END 9 | 10 | 11 | # LOCK-BEGIN[class(UtilError)]: DON'T MODIFY 12 | @pod 13 | class UtilError(Enum[AutoTagType]): 14 | ACCOUNT_ALREADY_INITIALIZED = None 15 | ACCOUNT_UNINITIALIZED = None 16 | DUPLICATE_PRODUCT_KEY = None 17 | PUBLIC_KEY_MISMATCH = None 18 | ASSERTION_ERROR = None 19 | INVALID_MINT_AUTHORITY = None 20 | INCORRECT_OWNER = None 21 | PUBLIC_KEYS_SHOULD_BE_UNIQUE = None 22 | NOT_RENT_EXEMPT = None 23 | NUMERICAL_OVERFLOW = None 24 | ROUND_ERROR = None 25 | DIVISIONBY_ZERO = None 26 | INVALID_RETURN_VALUE = None 27 | SQRT_ROOT_ERROR = None 28 | ZERO_PRICE_ERROR = None 29 | ZERO_QUANTITY_ERROR = None 30 | SERIALIZE_ERROR = None 31 | DESERIALIZE_ERROR = None 32 | INVALID_BITSET_INDEX = None 33 | # LOCK-END 34 | 35 | @classmethod 36 | def _to_bytes_partial(cls, buffer, obj, **kwargs): 37 | # to modify packing, change this method 38 | return super()._to_bytes_partial(buffer, obj, **kwargs) 39 | 40 | @classmethod 41 | def _from_bytes_partial(cls, buffer, **kwargs): 42 | # to modify unpacking, change this method 43 | return super()._from_bytes_partial(buffer, **kwargs) 44 | 45 | @classmethod 46 | def to_bytes(cls, obj, **kwargs): 47 | return cls.pack(obj, converter="bytes", **kwargs) 48 | 49 | @classmethod 50 | def from_bytes(cls, raw, **kwargs): 51 | return cls.unpack(raw, converter="bytes", **kwargs) 52 | -------------------------------------------------------------------------------- /client/dexterity/codegen/dex/types/withdraw_funds_params.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from dexterity.codegen.dex.types.fractional import Fractional 3 | from podite import pod 4 | 5 | # LOCK-END 6 | 7 | 8 | # LOCK-BEGIN[class(WithdrawFundsParams)]: DON'T MODIFY 9 | @pod 10 | class WithdrawFundsParams: 11 | quantity: Fractional 12 | # LOCK-END 13 | 14 | @classmethod 15 | def to_bytes(cls, obj, **kwargs): 16 | return cls.pack(obj, converter="bytes", **kwargs) 17 | 18 | @classmethod 19 | def from_bytes(cls, raw, **kwargs): 20 | return cls.unpack(raw, converter="bytes", **kwargs) 21 | -------------------------------------------------------------------------------- /client/dexterity/codegen/instruments/__init__.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | import dexterity.codegen.instruments.accounts as accounts 3 | import dexterity.codegen.instruments.instructions as instructions 4 | import dexterity.codegen.instruments.types as types 5 | 6 | # LOCK-END 7 | 8 | -------------------------------------------------------------------------------- /client/dexterity/codegen/instruments/accounts.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from dexterity.codegen.instruments.types.derivative_metadata import DerivativeMetadata 3 | from podite import ( 4 | Enum, 5 | U64, 6 | pod, 7 | ) 8 | from solmate.anchor import AccountDiscriminant 9 | 10 | # LOCK-END 11 | 12 | 13 | # LOCK-BEGIN[accounts]: DON'T MODIFY 14 | @pod 15 | class Accounts(Enum[U64]): 16 | DERIVATIVE_METADATA = AccountDiscriminant(field=DerivativeMetadata) 17 | # LOCK-END 18 | 19 | @classmethod 20 | def to_bytes(cls, obj, **kwargs): 21 | return cls.pack(obj, converter="bytes", **kwargs) 22 | 23 | @classmethod 24 | def from_bytes(cls, raw, **kwargs): 25 | return cls.unpack(raw, converter="bytes", **kwargs) 26 | -------------------------------------------------------------------------------- /client/dexterity/codegen/instruments/addrs.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from solana.publickey import PublicKey 3 | 4 | # LOCK-END 5 | 6 | 7 | # LOCK-BEGIN[addresses]: DON'T MODIFY 8 | # LOCK-END 9 | -------------------------------------------------------------------------------- /client/dexterity/codegen/instruments/instructions/__init__.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from .close_derivative_account import ( 3 | CloseDerivativeAccountIx, 4 | close_derivative_account, 5 | ) 6 | from .initialize_derivative import ( 7 | InitializeDerivativeIx, 8 | initialize_derivative, 9 | ) 10 | from .instruction_tag import InstructionTag 11 | from .settle_derivative import ( 12 | SettleDerivativeIx, 13 | settle_derivative, 14 | ) 15 | 16 | # LOCK-END 17 | -------------------------------------------------------------------------------- /client/dexterity/codegen/instruments/instructions/close_derivative_account.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from .instruction_tag import InstructionTag 3 | from dataclasses import dataclass 4 | from io import BytesIO 5 | from podite import BYTES_CATALOG 6 | from solana.publickey import PublicKey 7 | from solana.transaction import ( 8 | AccountMeta, 9 | TransactionInstruction, 10 | ) 11 | from solmate.utils import to_account_meta 12 | from typing import ( 13 | List, 14 | Optional, 15 | Union, 16 | ) 17 | 18 | # LOCK-END 19 | 20 | 21 | # LOCK-BEGIN[ix_cls(close_derivative_account)]: DON'T MODIFY 22 | @dataclass 23 | class CloseDerivativeAccountIx: 24 | program_id: PublicKey 25 | 26 | # account metas 27 | derivative_metadata: AccountMeta 28 | close_authority: AccountMeta 29 | destination: AccountMeta 30 | remaining_accounts: Optional[List[AccountMeta]] 31 | 32 | def to_instruction(self): 33 | keys = [] 34 | keys.append(self.derivative_metadata) 35 | keys.append(self.close_authority) 36 | keys.append(self.destination) 37 | if self.remaining_accounts is not None: 38 | keys.extend(self.remaining_accounts) 39 | 40 | buffer = BytesIO() 41 | buffer.write(InstructionTag.to_bytes(InstructionTag.CLOSE_DERIVATIVE_ACCOUNT)) 42 | 43 | return TransactionInstruction( 44 | keys=keys, 45 | program_id=self.program_id, 46 | data=buffer.getvalue(), 47 | ) 48 | 49 | # LOCK-END 50 | 51 | 52 | # LOCK-BEGIN[ix_fn(close_derivative_account)]: DON'T MODIFY 53 | def close_derivative_account( 54 | derivative_metadata: Union[str, PublicKey, AccountMeta], 55 | close_authority: Union[str, PublicKey, AccountMeta], 56 | destination: Union[str, PublicKey, AccountMeta], 57 | remaining_accounts: Optional[List[AccountMeta]] = None, 58 | program_id: Optional[PublicKey] = None, 59 | ): 60 | if program_id is None: 61 | program_id = PublicKey("instruments11111111111111111111111111111111") 62 | 63 | if isinstance(derivative_metadata, (str, PublicKey)): 64 | derivative_metadata = to_account_meta( 65 | derivative_metadata, 66 | is_signer=False, 67 | is_writable=True, 68 | ) 69 | if isinstance(close_authority, (str, PublicKey)): 70 | close_authority = to_account_meta( 71 | close_authority, 72 | is_signer=True, 73 | is_writable=False, 74 | ) 75 | if isinstance(destination, (str, PublicKey)): 76 | destination = to_account_meta( 77 | destination, 78 | is_signer=False, 79 | is_writable=False, 80 | ) 81 | 82 | return CloseDerivativeAccountIx( 83 | program_id=program_id, 84 | derivative_metadata=derivative_metadata, 85 | close_authority=close_authority, 86 | destination=destination, 87 | remaining_accounts=remaining_accounts, 88 | ).to_instruction() 89 | 90 | # LOCK-END 91 | -------------------------------------------------------------------------------- /client/dexterity/codegen/instruments/instructions/instruction_tag.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from podite import ( 3 | Enum, 4 | U64, 5 | pod, 6 | ) 7 | from solmate.anchor import InstructionDiscriminant 8 | 9 | # LOCK-END 10 | 11 | 12 | # LOCK-BEGIN[instruction_tag]: DON'T MODIFY 13 | @pod 14 | class InstructionTag(Enum[U64]): 15 | INITIALIZE_DERIVATIVE = InstructionDiscriminant() 16 | SETTLE_DERIVATIVE = InstructionDiscriminant() 17 | CLOSE_DERIVATIVE_ACCOUNT = InstructionDiscriminant() 18 | # LOCK-END 19 | -------------------------------------------------------------------------------- /client/dexterity/codegen/instruments/instructions/settle_fixed_income.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from .instruction_tag import InstructionTag 3 | from dataclasses import dataclass 4 | from io import BytesIO 5 | from podite import BYTES_CATALOG 6 | from solana.publickey import PublicKey 7 | from solana.transaction import ( 8 | AccountMeta, 9 | TransactionInstruction, 10 | ) 11 | from solmate.utils import to_account_meta 12 | from typing import ( 13 | List, 14 | Optional, 15 | Union, 16 | ) 17 | 18 | # LOCK-END 19 | 20 | 21 | # LOCK-BEGIN[ix_cls(settle_fixed_income)]: DON'T MODIFY 22 | @dataclass 23 | class SettleFixedIncomeIx: 24 | program_id: PublicKey 25 | 26 | # account metas 27 | market_product_group: AccountMeta 28 | fixed_income_metadata: AccountMeta 29 | dex_program: AccountMeta 30 | remaining_accounts: Optional[List[AccountMeta]] 31 | 32 | def to_instruction(self): 33 | keys = [] 34 | keys.append(self.market_product_group) 35 | keys.append(self.fixed_income_metadata) 36 | keys.append(self.dex_program) 37 | if self.remaining_accounts is not None: 38 | keys.extend(self.remaining_accounts) 39 | 40 | buffer = BytesIO() 41 | buffer.write(InstructionTag.to_bytes(InstructionTag.SETTLE_FIXED_INCOME)) 42 | 43 | return TransactionInstruction( 44 | keys=keys, 45 | program_id=self.program_id, 46 | data=buffer.getvalue(), 47 | ) 48 | 49 | # LOCK-END 50 | 51 | 52 | # LOCK-BEGIN[ix_fn(settle_fixed_income)]: DON'T MODIFY 53 | def settle_fixed_income( 54 | market_product_group: Union[str, PublicKey, AccountMeta], 55 | fixed_income_metadata: Union[str, PublicKey, AccountMeta], 56 | dex_program: Union[str, PublicKey, AccountMeta], 57 | remaining_accounts: Optional[List[AccountMeta]] = None, 58 | program_id: Optional[PublicKey] = None, 59 | ): 60 | if program_id is None: 61 | program_id = PublicKey("EF5kuCdtoPa6Y9J4YMut4YMBvWa17JAebpJCo5LHig9a") 62 | 63 | if isinstance(market_product_group, (str, PublicKey)): 64 | market_product_group = to_account_meta( 65 | market_product_group, 66 | is_signer=False, 67 | is_writable=True, 68 | ) 69 | if isinstance(fixed_income_metadata, (str, PublicKey)): 70 | fixed_income_metadata = to_account_meta( 71 | fixed_income_metadata, 72 | is_signer=False, 73 | is_writable=True, 74 | ) 75 | if isinstance(dex_program, (str, PublicKey)): 76 | dex_program = to_account_meta( 77 | dex_program, 78 | is_signer=False, 79 | is_writable=False, 80 | ) 81 | 82 | return SettleFixedIncomeIx( 83 | program_id=program_id, 84 | market_product_group=market_product_group, 85 | fixed_income_metadata=fixed_income_metadata, 86 | dex_program=dex_program, 87 | remaining_accounts=remaining_accounts, 88 | ).to_instruction() 89 | 90 | # LOCK-END 91 | -------------------------------------------------------------------------------- /client/dexterity/codegen/instruments/types/__init__.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from .account_tag import AccountTag 3 | from .derivative_error import DerivativeError 4 | from .derivative_metadata import DerivativeMetadata 5 | from .expiration_status import ExpirationStatus 6 | from .initialize_derivative_params import InitializeDerivativeParams 7 | from .instrument_type import InstrumentType 8 | from .oracle_type import OracleType 9 | 10 | # LOCK-END 11 | -------------------------------------------------------------------------------- /client/dexterity/codegen/instruments/types/account_tag.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from podite import ( 3 | AutoTagType, 4 | Enum, 5 | pod, 6 | ) 7 | 8 | # LOCK-END 9 | 10 | 11 | # LOCK-BEGIN[class(AccountTag)]: DON'T MODIFY 12 | @pod 13 | class AccountTag(Enum[AutoTagType]): 14 | UNINITIALIZED = None 15 | DERIVATIVE_METADATA = None 16 | FIXED_INCOME_METADATA = None 17 | # LOCK-END 18 | 19 | @classmethod 20 | def _to_bytes_partial(cls, buffer, obj, **kwargs): 21 | # to modify packing, change this method 22 | return super()._to_bytes_partial(buffer, obj, **kwargs) 23 | 24 | @classmethod 25 | def _from_bytes_partial(cls, buffer, **kwargs): 26 | # to modify unpacking, change this method 27 | return super()._from_bytes_partial(buffer, **kwargs) 28 | 29 | @classmethod 30 | def to_bytes(cls, obj, **kwargs): 31 | return cls.pack(obj, converter="bytes", **kwargs) 32 | 33 | @classmethod 34 | def from_bytes(cls, raw, **kwargs): 35 | return cls.unpack(raw, converter="bytes", **kwargs) 36 | -------------------------------------------------------------------------------- /client/dexterity/codegen/instruments/types/derivative_error.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from podite import ( 3 | AutoTagType, 4 | Enum, 5 | pod, 6 | ) 7 | 8 | # LOCK-END 9 | 10 | 11 | # LOCK-BEGIN[class(DerivativeError)]: DON'T MODIFY 12 | @pod 13 | class DerivativeError(Enum[AutoTagType]): 14 | ACCOUNT_ALREADY_INITIALIZED = None 15 | INVALID_SETTLEMENT_TIME = None 16 | INVALID_CREATION_TIME = None 17 | UNINITIALIZED_ACCOUNT = None 18 | INVALID_SEQUENCE_NUMBER = None 19 | UNSETTLED_ACCOUNTS = None 20 | INVALID_ORACLE_CONFIG = None 21 | NUMERICAL_OVERFLOW = None 22 | CANNOT_BE_DELETED = None 23 | CONTRACT_IS_EXPIRED = None 24 | INVALID_DATE = None 25 | INVALID_ACCOUNT = None 26 | # LOCK-END 27 | 28 | @classmethod 29 | def _to_bytes_partial(cls, buffer, obj, **kwargs): 30 | # to modify packing, change this method 31 | return super()._to_bytes_partial(buffer, obj, **kwargs) 32 | 33 | @classmethod 34 | def _from_bytes_partial(cls, buffer, **kwargs): 35 | # to modify unpacking, change this method 36 | return super()._from_bytes_partial(buffer, **kwargs) 37 | 38 | @classmethod 39 | def to_bytes(cls, obj, **kwargs): 40 | return cls.pack(obj, converter="bytes", **kwargs) 41 | 42 | @classmethod 43 | def from_bytes(cls, raw, **kwargs): 44 | return cls.unpack(raw, converter="bytes", **kwargs) 45 | -------------------------------------------------------------------------------- /client/dexterity/codegen/instruments/types/derivative_metadata.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from dexterity.codegen.dex.types.fractional import Fractional 3 | from dexterity.codegen.instruments.types.account_tag import AccountTag 4 | from dexterity.codegen.instruments.types.expiration_status import ExpirationStatus 5 | from dexterity.codegen.instruments.types.instrument_type import InstrumentType 6 | from dexterity.codegen.instruments.types.oracle_type import OracleType 7 | from podite import ( 8 | U64, 9 | pod, 10 | ) 11 | from solana.publickey import PublicKey 12 | from solmate.dtypes import UnixTimestamp 13 | 14 | # LOCK-END 15 | 16 | 17 | # LOCK-BEGIN[class(DerivativeMetadata)]: DON'T MODIFY 18 | @pod 19 | class DerivativeMetadata: 20 | tag: AccountTag 21 | expired: ExpirationStatus 22 | oracle_type: OracleType 23 | instrument_type: InstrumentType 24 | bump: U64 25 | strike: Fractional 26 | initialization_time: UnixTimestamp 27 | full_funding_period: UnixTimestamp 28 | minimum_funding_period: UnixTimestamp 29 | price_oracle: PublicKey 30 | market_product_group: PublicKey 31 | close_authority: PublicKey 32 | clock: PublicKey 33 | last_funding_time: UnixTimestamp 34 | # LOCK-END 35 | 36 | @classmethod 37 | def to_bytes(cls, obj, **kwargs): 38 | return cls.pack(obj, converter="bytes", **kwargs) 39 | 40 | @classmethod 41 | def from_bytes(cls, raw, **kwargs): 42 | return cls.unpack(raw, converter="bytes", **kwargs) 43 | -------------------------------------------------------------------------------- /client/dexterity/codegen/instruments/types/expiration_status.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from podite import ( 3 | AutoTagType, 4 | Enum, 5 | pod, 6 | ) 7 | 8 | # LOCK-END 9 | 10 | 11 | # LOCK-BEGIN[class(ExpirationStatus)]: DON'T MODIFY 12 | @pod 13 | class ExpirationStatus(Enum[AutoTagType]): 14 | ACTIVE = None 15 | EXPIRED = None 16 | # LOCK-END 17 | 18 | @classmethod 19 | def _to_bytes_partial(cls, buffer, obj, **kwargs): 20 | # to modify packing, change this method 21 | return super()._to_bytes_partial(buffer, obj, **kwargs) 22 | 23 | @classmethod 24 | def _from_bytes_partial(cls, buffer, **kwargs): 25 | # to modify unpacking, change this method 26 | return super()._from_bytes_partial(buffer, **kwargs) 27 | 28 | @classmethod 29 | def to_bytes(cls, obj, **kwargs): 30 | return cls.pack(obj, converter="bytes", **kwargs) 31 | 32 | @classmethod 33 | def from_bytes(cls, raw, **kwargs): 34 | return cls.unpack(raw, converter="bytes", **kwargs) 35 | -------------------------------------------------------------------------------- /client/dexterity/codegen/instruments/types/fixed_income_metadata.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from dexterity.codegen.instruments.types.account_tag import AccountTag 3 | from dexterity.codegen.instruments.types.expiration_status import ExpirationStatus 4 | from podite import ( 5 | FixedLenArray, 6 | U64, 7 | pod, 8 | ) 9 | from solana.publickey import PublicKey 10 | from solmate.dtypes import UnixTimestamp 11 | 12 | # LOCK-END 13 | 14 | 15 | # LOCK-BEGIN[class(FixedIncomeMetadata)]: DON'T MODIFY 16 | @pod 17 | class FixedIncomeMetadata: 18 | tag: AccountTag 19 | bump: U64 20 | face_value: U64 21 | coupon_rate: U64 22 | initialization_time: UnixTimestamp 23 | coupon_dates: FixedLenArray[UnixTimestamp, 32] 24 | maturity_date: UnixTimestamp 25 | market_product_group: PublicKey 26 | close_authority: PublicKey 27 | last_funding_time: UnixTimestamp 28 | expired: ExpirationStatus 29 | # LOCK-END 30 | 31 | @classmethod 32 | def to_bytes(cls, obj, **kwargs): 33 | return cls.pack(obj, converter="bytes", **kwargs) 34 | 35 | @classmethod 36 | def from_bytes(cls, raw, **kwargs): 37 | return cls.unpack(raw, converter="bytes", **kwargs) 38 | -------------------------------------------------------------------------------- /client/dexterity/codegen/instruments/types/initialize_derivative_params.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from dexterity.codegen.dex.types.fractional import Fractional 3 | from dexterity.codegen.instruments.types.instrument_type import InstrumentType 4 | from dexterity.codegen.instruments.types.oracle_type import OracleType 5 | from podite import pod 6 | from solana.publickey import PublicKey 7 | from solmate.dtypes import UnixTimestamp 8 | 9 | # LOCK-END 10 | 11 | 12 | # LOCK-BEGIN[class(InitializeDerivativeParams)]: DON'T MODIFY 13 | @pod 14 | class InitializeDerivativeParams: 15 | instrument_type: "InstrumentType" 16 | strike: Fractional 17 | full_funding_period: UnixTimestamp 18 | minimum_funding_period: UnixTimestamp 19 | initialization_time: UnixTimestamp 20 | close_authority: PublicKey 21 | oracle_type: "OracleType" 22 | # LOCK-END 23 | 24 | @classmethod 25 | def to_bytes(cls, obj, **kwargs): 26 | return cls.pack(obj, converter="bytes", **kwargs) 27 | 28 | @classmethod 29 | def from_bytes(cls, raw, **kwargs): 30 | return cls.unpack(raw, converter="bytes", **kwargs) 31 | -------------------------------------------------------------------------------- /client/dexterity/codegen/instruments/types/initialize_fixed_income_params.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from podite import ( 3 | FixedLenArray, 4 | U64, 5 | pod, 6 | ) 7 | from solana.publickey import PublicKey 8 | from solmate.dtypes import UnixTimestamp 9 | 10 | # LOCK-END 11 | 12 | 13 | # LOCK-BEGIN[class(InitializeFixedIncomeParams)]: DON'T MODIFY 14 | @pod 15 | class InitializeFixedIncomeParams: 16 | face_value: U64 17 | coupon_rate: U64 18 | initialization_time: UnixTimestamp 19 | coupon_dates: FixedLenArray[UnixTimestamp, 32] 20 | maturity_date: UnixTimestamp 21 | close_authority: PublicKey 22 | # LOCK-END 23 | 24 | @classmethod 25 | def to_bytes(cls, obj, **kwargs): 26 | return cls.pack(obj, converter="bytes", **kwargs) 27 | 28 | @classmethod 29 | def from_bytes(cls, raw, **kwargs): 30 | return cls.unpack(raw, converter="bytes", **kwargs) 31 | -------------------------------------------------------------------------------- /client/dexterity/codegen/instruments/types/instrument_type.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from podite import ( 3 | AutoTagType, 4 | Enum, 5 | pod, 6 | ) 7 | 8 | # LOCK-END 9 | 10 | 11 | # LOCK-BEGIN[class(InstrumentType)]: DON'T MODIFY 12 | @pod 13 | class InstrumentType(Enum[AutoTagType]): 14 | UNINITIALIZED = None 15 | RECURRING_CALL = None 16 | RECURRING_PUT = None 17 | EXPIRING_CALL = None 18 | EXPIRING_PUT = None 19 | # LOCK-END 20 | 21 | @classmethod 22 | def _to_bytes_partial(cls, buffer, obj, **kwargs): 23 | # to modify packing, change this method 24 | return super()._to_bytes_partial(buffer, obj, **kwargs) 25 | 26 | @classmethod 27 | def _from_bytes_partial(cls, buffer, **kwargs): 28 | # to modify unpacking, change this method 29 | return super()._from_bytes_partial(buffer, **kwargs) 30 | 31 | @classmethod 32 | def to_bytes(cls, obj, **kwargs): 33 | return cls.pack(obj, converter="bytes", **kwargs) 34 | 35 | @classmethod 36 | def from_bytes(cls, raw, **kwargs): 37 | return cls.unpack(raw, converter="bytes", **kwargs) 38 | -------------------------------------------------------------------------------- /client/dexterity/codegen/instruments/types/oracle_type.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from podite import ( 3 | AutoTagType, 4 | Enum, 5 | pod, 6 | ) 7 | 8 | # LOCK-END 9 | 10 | 11 | # LOCK-BEGIN[class(OracleType)]: DON'T MODIFY 12 | @pod 13 | class OracleType(Enum[AutoTagType]): 14 | UNINITIALIZED = None 15 | PYTH = None 16 | DUMMY = None 17 | # LOCK-END 18 | 19 | @classmethod 20 | def _to_bytes_partial(cls, buffer, obj, **kwargs): 21 | # to modify packing, change this method 22 | return super()._to_bytes_partial(buffer, obj, **kwargs) 23 | 24 | @classmethod 25 | def _from_bytes_partial(cls, buffer, **kwargs): 26 | # to modify unpacking, change this method 27 | return super()._from_bytes_partial(buffer, **kwargs) 28 | 29 | @classmethod 30 | def to_bytes(cls, obj, **kwargs): 31 | return cls.pack(obj, converter="bytes", **kwargs) 32 | 33 | @classmethod 34 | def from_bytes(cls, raw, **kwargs): 35 | return cls.unpack(raw, converter="bytes", **kwargs) 36 | -------------------------------------------------------------------------------- /client/dexterity/codegen/noop_risk_engine/__init__.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | import dexterity.codegen.noop_risk_engine.instructions as instructions 3 | 4 | # LOCK-END 5 | 6 | 7 | -------------------------------------------------------------------------------- /client/dexterity/codegen/noop_risk_engine/addrs.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from solana.publickey import PublicKey 3 | 4 | # LOCK-END 5 | 6 | 7 | # LOCK-BEGIN[addresses]: DON'T MODIFY 8 | # LOCK-END 9 | -------------------------------------------------------------------------------- /client/dexterity/codegen/noop_risk_engine/instructions/__init__.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from .create_risk_state_account import ( 3 | CreateRiskStateAccountIx, 4 | create_risk_state_account, 5 | ) 6 | from .instruction_tag import InstructionTag 7 | from .validate_account_health import ( 8 | ValidateAccountHealthIx, 9 | validate_account_health, 10 | ) 11 | from .validate_account_liquidation import ( 12 | ValidateAccountLiquidationIx, 13 | validate_account_liquidation, 14 | ) 15 | 16 | # LOCK-END 17 | -------------------------------------------------------------------------------- /client/dexterity/codegen/noop_risk_engine/instructions/instruction_tag.py: -------------------------------------------------------------------------------- 1 | # LOCK-BEGIN[imports]: DON'T MODIFY 2 | from podite import ( 3 | Enum, 4 | U64, 5 | pod, 6 | ) 7 | from solmate.anchor import InstructionDiscriminant 8 | 9 | # LOCK-END 10 | 11 | 12 | # LOCK-BEGIN[instruction_tag]: DON'T MODIFY 13 | @pod 14 | class InstructionTag(Enum[U64]): 15 | VALIDATE_ACCOUNT_HEALTH = InstructionDiscriminant() 16 | VALIDATE_ACCOUNT_LIQUIDATION = InstructionDiscriminant() 17 | CREATE_RISK_STATE_ACCOUNT = InstructionDiscriminant() 18 | # LOCK-END 19 | -------------------------------------------------------------------------------- /client/dexterity/constant_fees/actions.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from solana.publickey import PublicKey 4 | from solana.transaction import Transaction 5 | 6 | import dexterity.constant_fees.instructions as ixs 7 | import dexterity.program_ids as pids 8 | from dexterity.dex.addrs import ( 9 | get_trader_fee_state_acct, 10 | get_trader_risk_group_addr, 11 | get_fee_model_configuration_addr, 12 | ) 13 | from dexterity.utils.solana import ( 14 | actionify, 15 | ) 16 | 17 | 18 | @actionify 19 | def update_fees( 20 | payer: PublicKey, 21 | market_product_group: PublicKey, 22 | maker_fee_bps: int, 23 | taker_fee_bps: int, 24 | fee_model_config_acct: Optional[PublicKey] = None, 25 | program_id: PublicKey = pids.CONSTANT_FEES_MODEL_PROGRAM_ID, 26 | ): 27 | if fee_model_config_acct is None: 28 | fee_model_config_acct = get_fee_model_configuration_addr( 29 | market_product_group, program_id 30 | ) 31 | 32 | return Transaction(fee_payer=payer).add( 33 | ixs.update_fees_ix( 34 | payer=payer, 35 | fee_model_config_acct=fee_model_config_acct, 36 | market_product_group=market_product_group, 37 | system_program=pids.SYSTEM_PROGRAM_ID, 38 | maker_fee_bps=maker_fee_bps, 39 | taker_fee_bps=taker_fee_bps, 40 | program_id=program_id, 41 | ) 42 | ) 43 | 44 | 45 | @actionify 46 | def initialize_trader_fee_acct( 47 | payer: PublicKey, 48 | market_product_group: PublicKey, 49 | program_id: PublicKey = pids.CONSTANT_FEES_MODEL_PROGRAM_ID, 50 | trader_risk_group: Optional[PublicKey] = None, 51 | system_program: Optional[PublicKey] = pids.SYSTEM_PROGRAM_ID, 52 | fee_model_config_acct: Optional[PublicKey] = None, 53 | ): 54 | if trader_risk_group is None: 55 | trader_risk_group = get_trader_risk_group_addr( 56 | payer, 57 | market_product_group, 58 | ) 59 | 60 | if fee_model_config_acct is None: 61 | fee_model_config_acct = get_fee_model_configuration_addr( 62 | market_product_group, 63 | program_id, 64 | ) 65 | 66 | trader_fee_acct = get_trader_fee_state_acct( 67 | payer, 68 | market_product_group, 69 | program_id, 70 | ) 71 | 72 | return Transaction(fee_payer=payer).add( 73 | ixs.initialize_trader_acct_ix( 74 | payer=payer, 75 | fee_model_config_acct=fee_model_config_acct, 76 | trader_fee_acct=trader_fee_acct, 77 | market_product_group=market_product_group, 78 | trader_risk_group=trader_risk_group, 79 | system_program=system_program, 80 | program_id=program_id, 81 | ) 82 | ) 83 | -------------------------------------------------------------------------------- /client/dexterity/constant_fees/addrs.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solana-labs/dexterity/56c8341fe64183d200767c646050260ef99a6f70/client/dexterity/constant_fees/addrs.py -------------------------------------------------------------------------------- /client/dexterity/constant_fees/instructions.py: -------------------------------------------------------------------------------- 1 | from podite import U8, I32, pod, Enum 2 | from solana.publickey import PublicKey 3 | from solana.transaction import AccountMeta, TransactionInstruction 4 | 5 | 6 | @pod 7 | class InstructionCode(Enum[U8]): 8 | FindFees = 0 9 | InitializeTraderAcct = 1 10 | UpdateFees = 2 11 | 12 | 13 | @pod 14 | class NoParams: 15 | instr: InstructionCode 16 | 17 | 18 | @pod 19 | class UpdateFeesParams: 20 | instr: InstructionCode 21 | maker_fee_bps: I32 22 | taker_fee_bps: I32 23 | 24 | 25 | def update_fees_ix( 26 | program_id: PublicKey, 27 | payer: PublicKey, 28 | fee_model_config_acct: PublicKey, 29 | market_product_group: PublicKey, 30 | system_program: PublicKey, 31 | maker_fee_bps: int, 32 | taker_fee_bps: int, 33 | ) -> TransactionInstruction: 34 | keys = [ 35 | AccountMeta(pubkey=payer, is_signer=True, is_writable=False), 36 | AccountMeta(pubkey=fee_model_config_acct, is_signer=False, is_writable=True), 37 | AccountMeta(pubkey=market_product_group, is_signer=False, is_writable=False), 38 | AccountMeta(pubkey=system_program, is_signer=False, is_writable=False), 39 | ] 40 | return TransactionInstruction( 41 | keys=keys, 42 | program_id=program_id, 43 | data=UpdateFeesParams.to_bytes(UpdateFeesParams( 44 | instr=InstructionCode.UpdateFees, 45 | maker_fee_bps=maker_fee_bps, 46 | taker_fee_bps=taker_fee_bps, 47 | )), 48 | ) 49 | 50 | 51 | def initialize_trader_acct_ix( 52 | program_id: PublicKey, 53 | payer: PublicKey, 54 | fee_model_config_acct: PublicKey, 55 | trader_fee_acct: PublicKey, 56 | market_product_group: PublicKey, 57 | trader_risk_group: PublicKey, 58 | system_program: PublicKey, 59 | ) -> TransactionInstruction: 60 | keys = [ 61 | AccountMeta(pubkey=payer, is_signer=True, is_writable=False), 62 | AccountMeta(pubkey=fee_model_config_acct, is_signer=False, is_writable=False), 63 | AccountMeta(pubkey=trader_fee_acct, is_signer=False, is_writable=True), 64 | AccountMeta(pubkey=market_product_group, is_signer=False, is_writable=False), 65 | AccountMeta(pubkey=trader_risk_group, is_signer=False, is_writable=False), 66 | AccountMeta(pubkey=system_program, is_signer=False, is_writable=False), 67 | ] 68 | return TransactionInstruction( 69 | program_id=program_id, 70 | keys=keys, 71 | data=NoParams.to_bytes(NoParams(instr=InstructionCode.InitializeTraderAcct)), 72 | ) 73 | -------------------------------------------------------------------------------- /client/dexterity/constant_fees/state.py: -------------------------------------------------------------------------------- 1 | from podite import ( 2 | pod, 3 | I32, 4 | U64, 5 | ) 6 | 7 | 8 | @pod 9 | class FeeConfig: 10 | maker_fee_bps: I32 11 | taker_fee_bps: I32 12 | 13 | @pod 14 | class TraderFeeState: 15 | bump: U64 16 | -------------------------------------------------------------------------------- /client/dexterity/dummy_oracle/instructions/__init__.py: -------------------------------------------------------------------------------- 1 | from .common import ( 2 | InstructionCode, 3 | ) 4 | 5 | from .initialize_clock import ( 6 | initialize_clock_ix, 7 | ) 8 | 9 | from .initialize_oracle import ( 10 | initialize_oracle_ix, 11 | ) 12 | 13 | from .update_clock import ( 14 | update_clock_ix, 15 | ) 16 | 17 | from .update_price import ( 18 | update_price_ix, 19 | ) 20 | 21 | __all__ = [ 22 | "InstructionCode", 23 | "initialize_clock_ix", 24 | "initialize_oracle_ix", 25 | "update_clock_ix", 26 | "update_price_ix", 27 | ] 28 | -------------------------------------------------------------------------------- /client/dexterity/dummy_oracle/instructions/common.py: -------------------------------------------------------------------------------- 1 | from enum import IntEnum 2 | 3 | from podite import U8, Enum, pod 4 | 5 | 6 | @pod 7 | class InstructionCode(Enum[U8]): 8 | INITIALIZE_CLOCK = None 9 | INITIALIZE_ORACLE = None 10 | UPDATE_CLOCK = None 11 | UPDATE_PRICE = None 12 | -------------------------------------------------------------------------------- /client/dexterity/dummy_oracle/instructions/initialize_clock.py: -------------------------------------------------------------------------------- 1 | from solana.publickey import PublicKey 2 | from solana.transaction import AccountMeta, TransactionInstruction 3 | from solana.system_program import SYS_PROGRAM_ID 4 | from podite import I64, U64, pod 5 | 6 | from .common import InstructionCode 7 | from dexterity.program_ids import ORACLE_PROGRAM_ID 8 | 9 | 10 | @pod 11 | class Params: 12 | instr: InstructionCode 13 | 14 | 15 | def initialize_clock_ix(clock: PublicKey, update_authority: PublicKey): 16 | keys = [ 17 | AccountMeta(pubkey=clock, is_signer=False, is_writable=True), 18 | AccountMeta(pubkey=update_authority, is_signer=True, is_writable=False), 19 | AccountMeta(pubkey=SYS_PROGRAM_ID, is_signer=False, is_writable=False), 20 | ] 21 | params = Params(instr=InstructionCode.INITIALIZE_CLOCK) 22 | return TransactionInstruction( 23 | keys=keys, program_id=ORACLE_PROGRAM_ID, data=params.to_bytes() 24 | ) 25 | -------------------------------------------------------------------------------- /client/dexterity/dummy_oracle/instructions/initialize_oracle.py: -------------------------------------------------------------------------------- 1 | from solana.publickey import PublicKey 2 | from solana.transaction import AccountMeta, TransactionInstruction 3 | from solana.system_program import SYS_PROGRAM_ID 4 | from podite import I64, U64, pod 5 | 6 | from .common import InstructionCode 7 | from dexterity.program_ids import ORACLE_PROGRAM_ID 8 | 9 | 10 | @pod 11 | class Params: 12 | instr: InstructionCode 13 | price: I64 14 | decimals: U64 15 | 16 | 17 | def initialize_oracle_ix( 18 | oracle_price: PublicKey, update_authority: PublicKey, price: int, decimals: int = 0 19 | ): 20 | keys = [ 21 | AccountMeta(pubkey=oracle_price, is_signer=False, is_writable=True), 22 | AccountMeta(pubkey=update_authority, is_signer=True, is_writable=True), 23 | AccountMeta(pubkey=SYS_PROGRAM_ID, is_signer=False, is_writable=False), 24 | ] 25 | params = Params( 26 | instr=InstructionCode.INITIALIZE_ORACLE, price=price, decimals=decimals 27 | ) 28 | return TransactionInstruction( 29 | keys=keys, program_id=ORACLE_PROGRAM_ID, data=params.to_bytes() 30 | ) 31 | -------------------------------------------------------------------------------- /client/dexterity/dummy_oracle/instructions/update_clock.py: -------------------------------------------------------------------------------- 1 | from solana.publickey import PublicKey 2 | from solana.transaction import AccountMeta, TransactionInstruction 3 | from podite import I64, U64, pod 4 | 5 | from .common import InstructionCode 6 | from dexterity.program_ids import ORACLE_PROGRAM_ID 7 | 8 | 9 | @pod 10 | class Params: 11 | instr: InstructionCode 12 | slot: U64 13 | epoch_start_timestamp: I64 14 | epoch: U64 15 | leader_schedule_epoch: U64 16 | unix_timestamp: I64 17 | 18 | 19 | def update_clock_ix( 20 | clock: PublicKey, 21 | slot: int, 22 | epoch_start_timestamp: int, 23 | epoch: int, 24 | leader_schedule_epoch: int, 25 | unix_timestamp: int, 26 | ): 27 | keys = [ 28 | AccountMeta(pubkey=clock, is_signer=False, is_writable=True), 29 | ] 30 | params = Params( 31 | instr=InstructionCode.UPDATE_CLOCK, 32 | slot=slot, 33 | epoch_start_timestamp=epoch_start_timestamp, 34 | epoch=epoch, 35 | leader_schedule_epoch=leader_schedule_epoch, 36 | unix_timestamp=unix_timestamp, 37 | ) 38 | return TransactionInstruction( 39 | keys=keys, program_id=ORACLE_PROGRAM_ID, data=params.to_bytes() 40 | ) 41 | -------------------------------------------------------------------------------- /client/dexterity/dummy_oracle/instructions/update_price.py: -------------------------------------------------------------------------------- 1 | from solana.publickey import PublicKey 2 | from solana.transaction import AccountMeta, TransactionInstruction 3 | from podite import I64, U64, pod 4 | from solana.system_program import SYS_PROGRAM_ID 5 | 6 | from .common import InstructionCode 7 | from dexterity.program_ids import ORACLE_PROGRAM_ID 8 | 9 | 10 | @pod 11 | class Params: 12 | instr: InstructionCode 13 | price: I64 14 | decimals: U64 15 | 16 | 17 | def update_price_ix( 18 | oracle_price: PublicKey, update_authority: PublicKey, price: int, decimals: int = 0 19 | ): 20 | keys = [ 21 | AccountMeta(pubkey=oracle_price, is_signer=False, is_writable=True), 22 | AccountMeta(pubkey=update_authority, is_signer=True, is_writable=False), 23 | AccountMeta(pubkey=SYS_PROGRAM_ID,is_signer=False,is_writable=False), 24 | ] 25 | params = Params( 26 | instr=InstructionCode.UPDATE_PRICE, 27 | price=price, 28 | decimals=decimals, 29 | ) 30 | return TransactionInstruction( 31 | keys=keys, program_id=ORACLE_PROGRAM_ID, data=params.to_bytes() 32 | ) 33 | -------------------------------------------------------------------------------- /client/dexterity/dummy_oracle/state/__init__.py: -------------------------------------------------------------------------------- 1 | from .common import AccountTag 2 | 3 | from .clock import ( 4 | Clock, 5 | ) 6 | from .oracle_price import ( 7 | OraclePrice, 8 | ) 9 | 10 | 11 | def account_parser(data): 12 | tag = AccountTag.from_bytes(data[:1], byteorder="little") 13 | if tag == AccountTag.UNINITIALIZED: 14 | return None 15 | elif tag == AccountTag.ORACLE_PRICE: 16 | return OraclePrice.from_bytes(data) 17 | raise ValueError() 18 | 19 | 20 | __all__ = [ 21 | "Clock", 22 | "AccountTag", 23 | "OraclePrice", 24 | "account_parser", 25 | ] 26 | -------------------------------------------------------------------------------- /client/dexterity/dummy_oracle/state/clock.py: -------------------------------------------------------------------------------- 1 | from podite import pod, U64, I64 2 | 3 | 4 | @pod 5 | class Clock: 6 | slot: U64 7 | epoch_start_timestamp: I64 8 | epoch: U64 9 | leader_schedule_epoch: U64 10 | unix_timestamp: I64 11 | -------------------------------------------------------------------------------- /client/dexterity/dummy_oracle/state/common.py: -------------------------------------------------------------------------------- 1 | from podite import U8, Enum, pod 2 | 3 | 4 | @pod 5 | class AccountTag(Enum[U8]): 6 | UNINITIALIZED = None 7 | ORACLE_PRICE = None 8 | -------------------------------------------------------------------------------- /client/dexterity/dummy_oracle/state/oracle_price.py: -------------------------------------------------------------------------------- 1 | from solana.publickey import PublicKey 2 | 3 | from dexterity.dummy_oracle.state.common import AccountTag 4 | from podite import pod, U64, I64 5 | 6 | 7 | @pod 8 | class OraclePrice: 9 | tag: AccountTag 10 | price: I64 11 | decimals: U64 12 | slot: U64 13 | update_authority: PublicKey 14 | -------------------------------------------------------------------------------- /client/dexterity/instruments/instructions/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | from .initialize_derivative import ( 3 | get_derivative_key 4 | ) 5 | 6 | from .initialize_fixed_income import get_fixed_income_key 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /client/dexterity/instruments/instructions/initialize_derivative.py: -------------------------------------------------------------------------------- 1 | import struct 2 | 3 | from solana.publickey import PublicKey 4 | 5 | from dexterity.codegen.dex.types import Fractional 6 | from dexterity.program_ids import INSTRUMENTS_PROGRAM_ID 7 | from dexterity.codegen.instruments.types import InstrumentType 8 | 9 | 10 | def get_derivative_key( 11 | price_oracle: PublicKey, 12 | market_product_group: PublicKey, 13 | instrument_type: InstrumentType, 14 | strike: float, 15 | full_funding_period: int, 16 | minimum_funding_period: int, 17 | initialization_time: int, 18 | **kwargs, 19 | ): 20 | strike = Fractional.to_decimal(strike) # type: Fractional 21 | derivative_metadata, bump_seed = PublicKey.find_program_address( 22 | seeds=[ 23 | b"derivative", 24 | bytes(price_oracle), 25 | bytes(market_product_group), 26 | struct.pack(" work... 46 | # set_pid_by_protocol_name("risk", ALPHA_RISK_ENGINE_PROGRAM_ID) 47 | # set_pid_by_protocol_name("dex", DEX_PROGRAM_ID) 48 | # set_pid_by_protocol_name("instruments", INSTRUMENTS_PROGRAM_ID) 49 | -------------------------------------------------------------------------------- /client/dexterity/risk/actions.py: -------------------------------------------------------------------------------- 1 | from ctypes import Union 2 | from solana.transaction import AccountMeta, TransactionInstruction 3 | from typing import Optional 4 | 5 | from solana.publickey import PublicKey 6 | from solana.transaction import Transaction 7 | import dexterity.program_ids as pids 8 | from podite import pod, U64 9 | from dexterity.utils.solana import ( 10 | actionify 11 | ) 12 | from dexterity.dex.actions import RISK_CONFIG_LAYOUT 13 | from dexterity.dex.addrs import get_risk_register_addr 14 | 15 | @pod 16 | class Params: 17 | instr: U64 18 | 19 | def _post_init_risk_config(resp): 20 | if resp is None: 21 | return None, None 22 | addr = resp.instructions[0]["accounts"][1] 23 | exists = False 24 | 25 | if resp.error: 26 | error_ix, error_info = resp.error["InstructionError"] 27 | if error_ix == 0 and error_info["Custom"] == 0: 28 | exists = True 29 | else: 30 | exists = True 31 | 32 | if exists: 33 | return addr, resp 34 | else: 35 | return None, resp 36 | 37 | 38 | @actionify(post_process=_post_init_risk_config) 39 | def initialize_risk_config_acct( 40 | admin: PublicKey, 41 | market_product_group: PublicKey, 42 | program_id: Optional[PublicKey] = pids.ALPHA_RISK_ENGINE_PROGRAM_ID, 43 | risk_model_config_acct: Optional[PublicKey] = None, 44 | layout_str: Optional[str] = RISK_CONFIG_LAYOUT, 45 | ): 46 | if program_id == pids.ALPHA_RISK_ENGINE_PROGRAM_ID: 47 | return None 48 | 49 | if risk_model_config_acct is None: 50 | risk_model_config_acct = get_risk_register_addr(admin, market_product_group, program_id, layout_str) 51 | 52 | keys = [ 53 | AccountMeta(pubkey=market_product_group, is_signer=False, is_writable=False), 54 | AccountMeta(pubkey=admin, is_signer=True, is_writable=False), 55 | AccountMeta(pubkey=risk_model_config_acct, is_signer=False, is_writable=True), 56 | ] 57 | 58 | params = Params( 59 | instr=4, 60 | ) 61 | 62 | return Transaction(fee_payer=admin).add( 63 | TransactionInstruction( 64 | keys=keys, 65 | program_id=program_id, 66 | data=Params.to_bytes(params), 67 | ), 68 | ) 69 | 70 | -------------------------------------------------------------------------------- /client/dexterity/scripts/build: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ROOT=$(git rev-parse --show-toplevel) 3 | cd $ROOT 4 | ./build.sh 5 | echo "Built protocols" 6 | cd $ROOT/client/dexterity 7 | echo "solana-test-validator \\" > $ROOT/client/dexterity/start_test_validator.sh 8 | DEPLOY=$ROOT/target/deploy 9 | ls $DEPLOY 10 | N=$(ls $DEPLOY | grep -v json | wc -l) 11 | echo $N 12 | echo $DEPLOY 13 | paste \ 14 | <(yes --bpf-program | head -n $N) \ 15 | <(ls $DEPLOY | grep json | xargs -I {} solana-keygen pubkey $DEPLOY/{}) \ 16 | <(ls $DEPLOY | awk -v dir="$DEPLOY" '{print dir"/"$0}'| grep -v json) \ 17 | <(yes "\\" | head -n $N) \ 18 | >> $ROOT/client/dexterity/start_test_validator.sh 19 | 20 | chmod +x $ROOT/client/dexterity/start_test_validator.sh -------------------------------------------------------------------------------- /client/dexterity/scripts/discriminant.py: -------------------------------------------------------------------------------- 1 | from hashlib import sha256 2 | import sys 3 | 4 | 5 | def main(): 6 | input = sys.argv[1] 7 | print(sighash(input).hex()) 8 | print(sighash_int(input)) 9 | 10 | 11 | def sighash(ix_name: str) -> bytes: 12 | """Not technically sighash, since we don't include the arguments. 13 | (Because Rust doesn't allow function overloading.) 14 | Args: 15 | ix_name: The instruction name. 16 | Returns: 17 | The sighash bytes. 18 | """ 19 | formatted_str = f"global:{ix_name}" 20 | return sha256(formatted_str.encode()).digest()[:8] 21 | 22 | 23 | def sighash_int(ix_name: str) -> int: 24 | return int.from_bytes(sighash(ix_name), byteorder="little") 25 | 26 | 27 | if __name__ == "__main__": 28 | main() 29 | -------------------------------------------------------------------------------- /client/dexterity/scripts/extract_program_ids.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | import re 4 | import subprocess 5 | 6 | 7 | def main(): 8 | programs = get_program_to_id() 9 | print("Programs:") 10 | for name, id in programs.items(): 11 | print(f"{name}: {id}") 12 | 13 | output = json.dumps({ 14 | "programs": programs 15 | }, indent=2) 16 | with open(f"{get_root()}/program_config.json", "w") as fp: 17 | fp.write(output) 18 | 19 | 20 | def get_program_to_id(): 21 | root = get_root() 22 | pids = dir_to_pids(f"{root}/target/deploy") 23 | # TODO: handle this more elegantly 24 | pids["agnostic_orderbook"] = os.environ.get("AAOB", "aaobKniTtDGvCZces7GH5UReLYP671bBkB96ahr9x3e") 25 | return pids 26 | 27 | 28 | def dir_to_pids(dir: str): 29 | program_to_id = {} 30 | for filename in os.listdir(dir): 31 | match = re.search(r"([a-z_]+)-keypair.json", filename) 32 | if match is None: 33 | continue 34 | program = match.groups()[0] 35 | program_to_id[program] = run(f"solana-keygen pubkey {dir}/{filename}") 36 | return program_to_id 37 | 38 | 39 | def run(cmd, debug=False): 40 | if debug: 41 | print(cmd) 42 | res = subprocess.check_output(cmd, shell=True).strip().decode("utf-8") 43 | if debug: 44 | print(res) 45 | return res 46 | 47 | 48 | def get_root() -> str: 49 | return run("git rev-parse --show-toplevel") 50 | 51 | 52 | if __name__ == "__main__": 53 | main() 54 | -------------------------------------------------------------------------------- /client/dexterity/scripts/get_trader_risk_groups_key.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | from base64 import b64decode as b64d 3 | from base58 import b58encode as b58e 4 | from solana.rpc.api import Client 5 | from solana.rpc.types import MemcmpOpts 6 | 7 | 8 | def main(): 9 | ap = argparse.ArgumentParser() 10 | ap.add_argument("dex_program_id") 11 | ap.add_argument("owner") 12 | ap.add_argument("--network", default="devnet") 13 | ap.add_argument("--market_product_group", default=None) 14 | args = ap.parse_args() 15 | 16 | urls = { 17 | "devnet": "https://api.devnet.solana.com", 18 | "dev": "https://api.devnet.solana.com", 19 | "localnet": "https://localhost:8899/", 20 | "local": "https://localhost:8899/", 21 | "mainnet": "https://api.mainnet-beta.solana.com/", 22 | "mainnet-beta": "https://api.mainnet-beta.solana.com/", 23 | } 24 | 25 | client = Client(urls[args.network]) 26 | 27 | print(f"owner: {args.owner}") 28 | mem_cmp = [MemcmpOpts(8 + 33, args.owner)] 29 | if args.market_product_group != None: 30 | mem_cmp.append(MemcmpOpts(8 + 1, args.market_product_group)) 31 | print(f"market product group: {args.market_product_group}") 32 | print("Searching...\n") 33 | resp = client.get_program_accounts( 34 | args.dex_program_id, 35 | "confirmed", 36 | encoding="base64", 37 | memcmp_opts=mem_cmp, 38 | ) 39 | 40 | mpgs = {} 41 | for account in resp["result"]: 42 | data = b64d(account["account"]["data"][0]) 43 | mpg = b58e(data[9:41]).decode('ascii') 44 | mpgs[mpg] = mpgs.get(mpg, []) + [account["pubkey"]] 45 | 46 | for k in mpgs: 47 | print(k) 48 | for trg in mpgs[k]: 49 | print(f"\t{trg}") 50 | 51 | 52 | if __name__ == '__main__': 53 | main() -------------------------------------------------------------------------------- /client/dexterity/scripts/keypair_to_b58.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import json 3 | from base58 import b58encode as b58e 4 | from solana.keypair import Keypair 5 | 6 | def main(): 7 | ap = argparse.ArgumentParser() 8 | ap.add_argument("f") 9 | args = ap.parse_args() 10 | 11 | with open(args.f, "r") as f: 12 | kp = json.load(f) 13 | print(b58e(bytes(kp)).decode('ascii')) 14 | print(Keypair(kp[:32]).public_key) 15 | 16 | if __name__ == '__name__': 17 | main() 18 | -------------------------------------------------------------------------------- /client/dexterity/scripts/start_test_validator.py: -------------------------------------------------------------------------------- 1 | from dexterity.scripts.extract_program_ids import get_program_to_id, get_root 2 | import os 3 | import subprocess 4 | 5 | 6 | def main(): 7 | programs = get_program_to_id() 8 | root = get_root() 9 | cmd = "solana-test-validator" 10 | args = "" 11 | for (name, pid) in programs.items(): 12 | path = f"{root}/target/deploy/{name}.so" 13 | args += f" --bpf-program {pid} {path}" 14 | print(f"Running {cmd} {args}") 15 | print(os.system(cmd + " " + args)) 16 | 17 | 18 | if __name__ == "__main__": 19 | main() 20 | -------------------------------------------------------------------------------- /client/dexterity/utils/__init__.py: -------------------------------------------------------------------------------- 1 | import podite 2 | from solmate.dtypes import Usize 3 | 4 | from .aob import create_market_aob_ix 5 | 6 | __all__ = ["create_market_aob_ix", "pod", "Usize"] 7 | -------------------------------------------------------------------------------- /client/dexterity/utils/aob/__init__.py: -------------------------------------------------------------------------------- 1 | from .instructions import * 2 | 3 | from .state import * 4 | -------------------------------------------------------------------------------- /client/dexterity/utils/aob/instructions.py: -------------------------------------------------------------------------------- 1 | import struct 2 | 3 | from solana.publickey import PublicKey 4 | from solana.transaction import AccountMeta, TransactionInstruction 5 | from dexterity.program_ids import AOB_PROGRAM_ID 6 | 7 | 8 | CREATE_MARKET_IX_CODE = 0 9 | 10 | 11 | def create_market_aob_ix( 12 | market: PublicKey, 13 | event_queue: PublicKey, 14 | bids: PublicKey, 15 | asks: PublicKey, 16 | caller_authority: PublicKey, 17 | callback_info_len: int, # u64 18 | callback_id_len: int, # u64 19 | min_base_order_size: int, # u64 20 | price_bitmask: int = (1 << 64) - 1, 21 | cranker_reward: int = 1000, 22 | ): 23 | params = [ 24 | CREATE_MARKET_IX_CODE, 25 | bytes(caller_authority), 26 | callback_info_len, 27 | callback_id_len, 28 | min_base_order_size, 29 | price_bitmask, 30 | cranker_reward, 31 | ] 32 | return TransactionInstruction( 33 | keys=[ 34 | AccountMeta(market, is_signer=False, is_writable=True), 35 | AccountMeta(event_queue, is_signer=False, is_writable=True), 36 | AccountMeta(bids, is_signer=False, is_writable=True), 37 | AccountMeta(asks, is_signer=False, is_writable=True), 38 | ], 39 | program_id=AOB_PROGRAM_ID, 40 | data=struct.pack(" Self { 25 | Self { 26 | client, 27 | authority, 28 | market_product_group, 29 | payer, 30 | } 31 | } 32 | 33 | pub async fn initialize_derivative( 34 | &self, 35 | price_oracle: Pubkey, 36 | clock: Pubkey, 37 | strike: impl Into, 38 | optional_args: initialize_derivative::InitializeDerivativeOptionalArgs, 39 | ) -> std::result::Result { 40 | let instrument_type = optional_args.instrument_type; 41 | let initialization_time = optional_args.initialization_time; 42 | let full_funding_period = optional_args.full_funding_period; 43 | let minimum_funding_period = optional_args.minimum_funding_period; 44 | let oracle_type = optional_args.oracle_type; 45 | let strike = strike.into(); 46 | 47 | let derivative_metadata = initialize_derivative::get_derivative_key( 48 | price_oracle, 49 | self.market_product_group, 50 | instrument_type, 51 | strike, 52 | full_funding_period as u64, 53 | minimum_funding_period, 54 | initialization_time, 55 | ); 56 | 57 | let ixs = initialize_derivative::initialize_derivative_ixs( 58 | self.authority.pubkey(), 59 | price_oracle, 60 | self.market_product_group, 61 | self.payer.pubkey(), 62 | clock, 63 | derivative_metadata, 64 | instrument_type, 65 | strike, 66 | full_funding_period, 67 | minimum_funding_period, 68 | initialization_time, 69 | oracle_type, 70 | ); 71 | self.client 72 | .sign_send_instructions(ixs, vec![&self.payer]) 73 | .await?; 74 | Ok(derivative_metadata) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /dexteritysdk/src/instrument/settle_derivative.rs: -------------------------------------------------------------------------------- 1 | use crate::{common::utils::*, sdk_client::SDKClient}; 2 | use anchor_lang::{InstructionData, ToAccountMetas}; 3 | use dex::utils::numeric::Fractional; 4 | use instruments::{ 5 | accounts, 6 | state::enums::{InstrumentType, OracleType}, 7 | }; 8 | use rand::Rng; 9 | use solana_program::{ 10 | clock::UnixTimestamp, 11 | instruction::Instruction, 12 | pubkey::Pubkey, 13 | sysvar::{clock::Clock, rent::Rent, Sysvar}, 14 | }; 15 | use solana_program_test::ProgramTestContext; 16 | use solana_sdk::signature::{Keypair, Signer}; 17 | 18 | pub fn settle_derivative_ixs( 19 | price_oracle: Pubkey, 20 | market_product_group: Pubkey, 21 | clock: Pubkey, 22 | derivative_metadata: Pubkey, 23 | ) -> Vec { 24 | let account_metas = instruments::accounts::SettleDerivative { 25 | market_product_group, 26 | derivative_metadata, 27 | price_oracle, 28 | dex_program: dex::id(), 29 | clock, 30 | } 31 | .to_account_metas(Some(true)); 32 | 33 | let mut data = instruments::instruction::SettleDerivative.data(); 34 | // Hack to get back test runtime dedupe 35 | let mut rng = rand::prelude::thread_rng(); 36 | let out = rng.gen_range(0..255); 37 | data.push(out as u8); 38 | let instruction = Instruction { 39 | program_id: instruments::ID, 40 | data: data, 41 | accounts: account_metas, 42 | }; 43 | 44 | vec![instruction] 45 | } 46 | 47 | pub async fn settle_derivative( 48 | client: &SDKClient, 49 | market_product_group: Pubkey, 50 | price_oracle: Pubkey, 51 | clock: Pubkey, 52 | derivative_metadata: Pubkey, 53 | ) -> std::result::Result { 54 | let ixs = settle_derivative_ixs( 55 | price_oracle, 56 | market_product_group, 57 | clock, 58 | derivative_metadata, 59 | ); 60 | client.sign_send_instructions(ixs, vec![]).await?; 61 | Ok(derivative_metadata) 62 | } 63 | -------------------------------------------------------------------------------- /dexteritysdk/src/oracle/create_clock.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | common::utils::{SDKError, SDKResult}, 3 | sdk_client::{ClientSubset, SDKClient}, 4 | state::clone_keypair, 5 | KeypairD, SDKContext, 6 | }; 7 | use solana_program::{ 8 | instruction::Instruction, message::Message, program_error::ProgramError, 9 | program_option::COption, program_pack::Pack, pubkey::Pubkey, sysvar::rent::Rent, 10 | }; 11 | use solana_sdk::{ 12 | account::Account, 13 | client::{Client, SyncClient}, 14 | signature::{Keypair, Signer}, 15 | system_instruction, 16 | transaction::Transaction, 17 | transport::TransportError, 18 | }; 19 | 20 | pub async fn create_clock_account( 21 | client: &SDKClient, 22 | dummy_oracle_program_id: Pubkey, 23 | authority: &KeypairD, 24 | system_program_id: Pubkey, 25 | ) -> std::result::Result { 26 | let seeds: &[&[u8]] = &[b"clock"]; 27 | let (clock_metadata_key, _) = Pubkey::find_program_address(&seeds, &dummy_oracle_program_id); 28 | let initialize_clock_ix = dummy_oracle::processor::initialize_clock_ix( 29 | dummy_oracle_program_id, 30 | clock_metadata_key, 31 | authority.pubkey(), 32 | system_program_id, 33 | dummy_oracle::processor::initialize_clock::Params {}, 34 | ); 35 | client 36 | .sign_send_instructions(vec![initialize_clock_ix], vec![authority]) 37 | .await?; 38 | Ok(clock_metadata_key) 39 | } 40 | -------------------------------------------------------------------------------- /dexteritysdk/src/oracle/create_oracle.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | common::utils::{SDKError, SDKResult}, 3 | sdk_client::{ClientSubset, SDKClient}, 4 | state::clone_keypair, 5 | KeypairD, SDKContext, 6 | }; 7 | use solana_program::{ 8 | instruction::Instruction, message::Message, program_error::ProgramError, 9 | program_option::COption, program_pack::Pack, pubkey::Pubkey, sysvar::rent::Rent, 10 | }; 11 | use solana_sdk::{ 12 | account::Account, 13 | client::{Client, SyncClient}, 14 | signature::{Keypair, Signer}, 15 | system_instruction, 16 | transaction::Transaction, 17 | transport::TransportError, 18 | }; 19 | 20 | pub struct CreateOracleOptionalArgs { 21 | price: i64, 22 | decimals: u64, 23 | } 24 | 25 | impl Default for CreateOracleOptionalArgs { 26 | fn default() -> Self { 27 | CreateOracleOptionalArgs { 28 | price: 100, 29 | decimals: 8, 30 | } 31 | } 32 | } 33 | 34 | pub async fn create_oracle_price_account( 35 | client: &SDKClient, 36 | dummy_oracle_program_id: Pubkey, 37 | authority: &KeypairD, 38 | system_program_id: Pubkey, 39 | optional_args: CreateOracleOptionalArgs, 40 | ) -> std::result::Result { 41 | let seeds: &[&[u8]] = &[b"oracle"]; 42 | let (oracle_metadata_key, _) = Pubkey::find_program_address(seeds, &dummy_oracle_program_id); 43 | let initialize_oracle_ix = dummy_oracle::processor::initialize_oracle_ix( 44 | dummy_oracle_program_id, 45 | oracle_metadata_key, 46 | authority.pubkey(), 47 | system_program_id, 48 | dummy_oracle::processor::initialize_oracle::Params { 49 | price: optional_args.price, 50 | decimals: optional_args.decimals, 51 | }, 52 | ); 53 | client 54 | .sign_send_instructions(vec![initialize_oracle_ix], vec![authority]) 55 | .await?; 56 | Ok(oracle_metadata_key) 57 | } 58 | -------------------------------------------------------------------------------- /dexteritysdk/src/oracle/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod create_clock; 2 | pub mod create_oracle; 3 | pub mod update_clock; 4 | pub mod update_oracle; 5 | -------------------------------------------------------------------------------- /dexteritysdk/src/oracle/update_clock.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | common::utils::{SDKError, SDKResult}, 3 | sdk_client::{ClientSubset, SDKClient}, 4 | state::clone_keypair, 5 | KeypairD, SDKContext, 6 | }; 7 | use solana_program::{ 8 | instruction::Instruction, message::Message, program_error::ProgramError, 9 | program_option::COption, program_pack::Pack, pubkey::Pubkey, sysvar::rent::Rent, 10 | }; 11 | use solana_sdk::{ 12 | account::Account, 13 | client::{Client, SyncClient}, 14 | signature::{Keypair, Signer}, 15 | system_instruction, 16 | transaction::Transaction, 17 | transport::TransportError, 18 | }; 19 | 20 | pub async fn update_clock_account( 21 | client: &SDKClient, 22 | dummy_oracle_program_id: Pubkey, 23 | authority: &KeypairD, 24 | system_program_id: Pubkey, 25 | slot: u64, 26 | epoch_start_timestamp: i64, 27 | epoch: u64, 28 | leader_schedule_epoch: u64, 29 | unix_timestamp: i64, 30 | ) -> std::result::Result { 31 | let seeds: Vec> = vec![b"clock".to_vec()]; 32 | let (clock_metadata_key, _) = Pubkey::find_program_address( 33 | seeds 34 | .iter() 35 | .map(|v| v.as_slice()) 36 | .collect::>() 37 | .as_ref(), 38 | &dummy_oracle_program_id, 39 | ); 40 | let initialize_clock_ix = dummy_oracle::processor::update_clock_ix( 41 | dummy_oracle_program_id, 42 | clock_metadata_key, 43 | authority.pubkey(), 44 | system_program_id, 45 | dummy_oracle::processor::update_clock::Params { 46 | slot: slot, 47 | epoch_start_timestamp: epoch_start_timestamp, 48 | epoch: epoch, 49 | leader_schedule_epoch: leader_schedule_epoch, 50 | unix_timestamp: unix_timestamp, 51 | }, 52 | ); 53 | client 54 | .sign_send_instructions(vec![initialize_clock_ix], vec![authority]) 55 | .await?; 56 | Ok(clock_metadata_key) 57 | } 58 | -------------------------------------------------------------------------------- /dexteritysdk/src/oracle/update_oracle.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | common::utils::{SDKError, SDKResult}, 3 | sdk_client::SDKClient, 4 | state::clone_keypair, 5 | KeypairD, SDKContext, 6 | }; 7 | use solana_program::{ 8 | instruction::Instruction, message::Message, program_error::ProgramError, 9 | program_option::COption, program_pack::Pack, pubkey::Pubkey, sysvar::rent::Rent, 10 | }; 11 | use solana_sdk::{ 12 | account::Account, 13 | client::{Client, SyncClient}, 14 | signature::{Keypair, Signer}, 15 | system_instruction, 16 | transaction::Transaction, 17 | transport::TransportError, 18 | }; 19 | 20 | pub async fn update_oracle_price_account( 21 | client: &SDKClient, 22 | dummy_oracle_program_id: Pubkey, 23 | authority: &KeypairD, 24 | system_program_id: Pubkey, 25 | price: i64, 26 | decimals: u64, 27 | ) -> std::result::Result { 28 | let seeds: Vec> = vec![b"oracle".to_vec()]; 29 | let (oracle_metadata_key, _) = Pubkey::find_program_address( 30 | seeds 31 | .iter() 32 | .map(|v| v.as_slice()) 33 | .collect::>() 34 | .as_ref(), 35 | &dummy_oracle_program_id, 36 | ); 37 | let initialize_oracle_ix = dummy_oracle::processor::update_price_ix( 38 | dummy_oracle_program_id, 39 | oracle_metadata_key, 40 | authority.pubkey(), 41 | system_program_id, 42 | dummy_oracle::processor::update_price::Params { 43 | price: price, 44 | decimals: decimals, 45 | }, 46 | ); 47 | client 48 | .sign_send_instructions(vec![initialize_oracle_ix], vec![authority]) 49 | .await?; 50 | Ok(oracle_metadata_key) 51 | } 52 | -------------------------------------------------------------------------------- /dexteritysdk/src/processor/cancel_order.rs: -------------------------------------------------------------------------------- 1 | use anchor_lang::{InstructionData, ToAccountMetas}; 2 | use solana_program::{ 3 | instruction::{AccountMeta, Instruction}, 4 | pubkey::Pubkey, 5 | system_program, 6 | }; 7 | use solana_program_test::ProgramTestContext; 8 | use solana_sdk::signature::{Keypair, Signer}; 9 | 10 | use dex::{accounts, instruction}; 11 | 12 | use crate::{common::utils::*, sdk_client::SDKClient}; 13 | 14 | pub fn cancel_order_ixs( 15 | aaob_program_id: Pubkey, 16 | user: Pubkey, 17 | trader_risk_group: Pubkey, 18 | market_product_group: Pubkey, 19 | product: Pubkey, 20 | market_signer: Pubkey, 21 | orderbook: Pubkey, 22 | event_queue: Pubkey, 23 | bids: Pubkey, 24 | asks: Pubkey, 25 | risk_engine_program: Pubkey, 26 | risk_engine_accounts: Vec, 27 | order_id: u128, 28 | risk_output_register: Pubkey, 29 | trader_risk_state_acct: Pubkey, 30 | risk_model_configuration_acct: Pubkey, 31 | ) -> Vec { 32 | let (risk_signer, _) = Pubkey::find_program_address(&[market_product_group.as_ref()], &dex::ID); 33 | let mut account_metas = accounts::CancelOrder { 34 | aaob_program: aaob_program_id, 35 | user, 36 | trader_risk_group, 37 | market_product_group, 38 | product, 39 | market_signer, 40 | orderbook, 41 | event_queue, 42 | bids, 43 | asks, 44 | system_program: system_program::id(), 45 | risk_engine_program, 46 | risk_output_register, 47 | trader_risk_state_acct, 48 | risk_model_configuration_acct: risk_model_configuration_acct, 49 | risk_signer, 50 | } 51 | .to_account_metas(None); 52 | for key in risk_engine_accounts.into_iter() { 53 | account_metas.push(AccountMeta::new_readonly(key, false)); 54 | } 55 | vec![Instruction { 56 | program_id: dex::ID, 57 | data: instruction::CancelOrder { 58 | params: dex::CancelOrderParams { order_id }, 59 | } 60 | .data(), 61 | accounts: account_metas, 62 | }] 63 | } 64 | -------------------------------------------------------------------------------- /dexteritysdk/src/processor/clear_expired_orderbook.rs: -------------------------------------------------------------------------------- 1 | use anchor_lang::{InstructionData, ToAccountMetas}; 2 | use solana_program::{ 3 | instruction::{AccountMeta, Instruction}, 4 | pubkey::Pubkey, 5 | system_program, 6 | }; 7 | use solana_program_test::ProgramTestContext; 8 | use solana_sdk::signature::{Keypair, Signer}; 9 | 10 | use dex::{accounts, instruction}; 11 | 12 | use crate::{common::utils::*, sdk_client::SDKClient}; 13 | 14 | pub fn clear_expired_orderbook_ixs( 15 | aaob_program_id: Pubkey, 16 | market_product_group: Pubkey, 17 | product: Pubkey, 18 | market_signer: Pubkey, 19 | orderbook: Pubkey, 20 | event_queue: Pubkey, 21 | bids: Pubkey, 22 | asks: Pubkey, 23 | n: Option, 24 | ) -> Vec { 25 | let num_orders_to_cancel = match n { 26 | Some(num) => num, 27 | None => 20, 28 | } as u8; 29 | let account_metas = accounts::ClearExpiredOrderbook { 30 | market_product_group, 31 | product, 32 | aaob_program: aaob_program_id, 33 | orderbook, 34 | market_signer, 35 | event_queue, 36 | bids, 37 | asks, 38 | } 39 | .to_account_metas(None); 40 | vec![Instruction { 41 | program_id: dex::ID, 42 | data: instruction::ClearExpiredOrderbook { 43 | params: dex::ClearExpiredOrderbookParams { 44 | num_orders_to_cancel, 45 | }, 46 | } 47 | .data(), 48 | accounts: account_metas, 49 | }] 50 | } 51 | -------------------------------------------------------------------------------- /dexteritysdk/src/processor/combo.rs: -------------------------------------------------------------------------------- 1 | use anchor_lang::{InstructionData, ToAccountMetas}; 2 | use dex::{accounts, state::constants::NAME_LEN, utils::numeric::Fractional}; 3 | use solana_program::{ 4 | instruction::{AccountMeta, Instruction}, 5 | pubkey::Pubkey, 6 | }; 7 | use solana_program_test::ProgramTestContext; 8 | use solana_sdk::signature::{Keypair, Signer}; 9 | 10 | use crate::{common::utils::*, sdk_client::SDKClient}; 11 | 12 | pub fn initialize_combo_ixs( 13 | authority: Pubkey, 14 | market_product_group: Pubkey, 15 | orderbook: Pubkey, 16 | name: [u8; NAME_LEN], 17 | products: &[Pubkey], 18 | tick_size: Fractional, 19 | price_offset: Fractional, 20 | base_decimals: u64, 21 | ratios: Vec, 22 | ) -> Vec { 23 | let params = dex::InitializeComboParams { 24 | name, 25 | tick_size, 26 | price_offset, 27 | base_decimals, 28 | ratios, 29 | }; 30 | let mut account_metas = accounts::InitializeCombo { 31 | authority, 32 | market_product_group, 33 | orderbook, 34 | } 35 | .to_account_metas(None); 36 | for key in products { 37 | account_metas.push(AccountMeta::new_readonly(*key, false)); 38 | } 39 | vec![Instruction { 40 | program_id: dex::ID, 41 | data: dex::instruction::InitializeCombo { params }.data(), 42 | accounts: account_metas, 43 | }] 44 | } 45 | -------------------------------------------------------------------------------- /dexteritysdk/src/processor/consume_orderbook_events.rs: -------------------------------------------------------------------------------- 1 | use anchor_lang::{InstructionData, ToAccountMetas}; 2 | use solana_program::{ 3 | instruction::{AccountMeta, Instruction}, 4 | pubkey::Pubkey, 5 | }; 6 | use solana_program_test::ProgramTestContext; 7 | use solana_sdk::signature::{Keypair, Signer}; 8 | 9 | use dex::{accounts, instruction}; 10 | 11 | use crate::{common::utils::*, sdk_client::SDKClient}; 12 | 13 | pub fn consume_orderbook_events_ixs( 14 | aaob_program: Pubkey, 15 | market_product_group: Pubkey, 16 | product: Pubkey, 17 | market_signer: Pubkey, 18 | orderbook: Pubkey, 19 | event_queue: Pubkey, 20 | reward_target: &Keypair, 21 | fee_model_program: Pubkey, 22 | fee_model_configuration_acct: Pubkey, 23 | risk_model_configuration_acct: Pubkey, 24 | fee_output_register: Pubkey, 25 | risk_engine_program: Pubkey, 26 | risk_output_register: Pubkey, 27 | user_accounts: &[Pubkey], 28 | max_iterations: u64, 29 | ) -> Vec { 30 | let (risk_and_fee_signer, _) = 31 | Pubkey::find_program_address(&[market_product_group.as_ref()], &dex::ID); 32 | let params = dex::ConsumeOrderbookEventsParams { max_iterations }; 33 | let mut account_metas = accounts::ConsumeOrderbookEvents { 34 | aaob_program, 35 | market_product_group, 36 | product, 37 | market_signer, 38 | orderbook, 39 | event_queue, 40 | reward_target: reward_target.pubkey(), 41 | fee_model_program, 42 | fee_model_configuration_acct, 43 | fee_output_register, 44 | risk_and_fee_signer: risk_and_fee_signer, 45 | } 46 | .to_account_metas(None); 47 | for key in user_accounts { 48 | account_metas.push(AccountMeta::new(*key, false)); 49 | } 50 | vec![Instruction { 51 | program_id: dex::ID, 52 | data: instruction::ConsumeOrderbookEvents { params }.data(), 53 | accounts: account_metas, 54 | }] 55 | } 56 | -------------------------------------------------------------------------------- /dexteritysdk/src/processor/deposit_funds.rs: -------------------------------------------------------------------------------- 1 | use crate::common::utils::*; 2 | 3 | use crate::{sdk_client::SDKClient, KeypairD}; 4 | use anchor_lang::{InstructionData, ToAccountMetas}; 5 | use dex::{accounts, instruction, utils::numeric::Fractional}; 6 | use solana_program::{instruction::Instruction, pubkey::Pubkey}; 7 | use solana_program_test::ProgramTestContext; 8 | use solana_sdk::signature::{Keypair, Signer}; 9 | 10 | pub fn deposit_funds_ixs( 11 | user: Pubkey, 12 | user_token_account: Pubkey, 13 | trader_risk_group: Pubkey, 14 | market_product_group: Pubkey, 15 | market_product_group_vault: Pubkey, 16 | quantity: Fractional, 17 | ) -> Vec { 18 | let params = dex::DepositFundsParams { quantity }; 19 | let account_metas = accounts::DepositFunds { 20 | token_program: spl_token::ID, 21 | user, 22 | user_token_account, 23 | trader_risk_group, 24 | market_product_group, 25 | market_product_group_vault, 26 | } 27 | .to_account_metas(None); 28 | vec![Instruction { 29 | program_id: dex::ID, 30 | data: instruction::DepositFunds { params }.data(), 31 | accounts: account_metas, 32 | }] 33 | } 34 | 35 | pub async fn deposit_funds( 36 | client: &SDKClient, 37 | dex_program_id: Pubkey, 38 | spl_token_program_id: Pubkey, 39 | user: &KeypairD, 40 | user_wallet: Pubkey, 41 | user_trader_risk_group: Pubkey, 42 | market_product_group: Pubkey, 43 | market_product_group_vault: Pubkey, 44 | quantity: Fractional, 45 | ) -> SDKResult { 46 | let ixs = deposit_funds_ixs( 47 | user.pubkey(), 48 | user_wallet, 49 | user_trader_risk_group, 50 | market_product_group, 51 | market_product_group_vault, 52 | quantity, 53 | ); 54 | client.sign_send_instructions(ixs, vec![user]).await 55 | } 56 | -------------------------------------------------------------------------------- /dexteritysdk/src/processor/fees.rs: -------------------------------------------------------------------------------- 1 | use anchor_lang::{InstructionData, ToAccountMetas}; 2 | use anyhow::anyhow; 3 | use solana_program::{instruction::Instruction, pubkey::Pubkey}; 4 | use solana_sdk::signer::Signer; 5 | 6 | use constant_fees::update_fees_ix; 7 | use dex::{accounts, instruction}; 8 | 9 | use crate::{admin::DexAdmin, common::utils::SDKResult, SDKContext, SDKError}; 10 | 11 | pub fn sweep_fees_ix( 12 | market_product_group: Pubkey, 13 | fee_collector: Pubkey, 14 | fee_collector_token_account: Pubkey, 15 | market_product_group_vault: Pubkey, 16 | ) -> Vec { 17 | let accts = accounts::SweepFees { 18 | market_product_group, 19 | fee_collector, 20 | fee_collector_token_account, 21 | market_product_group_vault, 22 | token_program: spl_token::ID, 23 | }; 24 | vec![Instruction { 25 | program_id: dex::ID, 26 | accounts: accts.to_account_metas(None), 27 | data: instruction::SweepFees {}.data(), 28 | }] 29 | } 30 | 31 | impl DexAdmin { 32 | pub async fn sweep_fees(&self) -> SDKResult { 33 | self.client 34 | .sign_send_instructions( 35 | sweep_fees_ix( 36 | self.market_product_group, 37 | self.fee_collector.pubkey(), 38 | self.fee_collector_wallet, 39 | self.vault, 40 | ), 41 | vec![], 42 | ) 43 | .await?; 44 | Ok(()) 45 | } 46 | 47 | pub async fn update_fees(&self, maker_fee_bps: i32, taker_fee_bps: i32) -> SDKResult { 48 | self.client 49 | .sign_send_instructions( 50 | vec![update_fees_ix( 51 | self.fee_model_program_id, 52 | self.payer.pubkey(), 53 | self.fee_model_config_acct, 54 | self.market_product_group, 55 | solana_program::system_program::id(), 56 | constant_fees::UpdateFeesParams { 57 | maker_fee_bps, 58 | taker_fee_bps, 59 | }, 60 | )], 61 | vec![&self.authority], 62 | ) 63 | .await 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /dexteritysdk/src/processor/market_product.rs: -------------------------------------------------------------------------------- 1 | use crate::{common::utils::*, sdk_client::SDKClient}; 2 | use anchor_lang::{InstructionData, ToAccountMetas}; 3 | use dex::{accounts, state::constants::NAME_LEN, utils::numeric::Fractional}; 4 | use solana_program::{instruction::Instruction, pubkey::Pubkey}; 5 | use solana_program_test::ProgramTestContext; 6 | use solana_sdk::signature::{Keypair, Signer}; 7 | 8 | pub fn initialize_market_product_ixs( 9 | authority: Pubkey, 10 | market_product_group: Pubkey, 11 | product: Pubkey, 12 | orderbook: Pubkey, 13 | name: [u8; NAME_LEN], 14 | tick_size: Fractional, 15 | base_decimals: u64, 16 | price_offset: Fractional, 17 | ) -> Vec { 18 | let params = dex::InitializeMarketProductParams { 19 | name, 20 | tick_size, 21 | base_decimals, 22 | price_offset, 23 | }; 24 | let account_metas = accounts::InitializeMarketProduct { 25 | authority, 26 | market_product_group, 27 | product, 28 | orderbook, 29 | } 30 | .to_account_metas(None); 31 | vec![Instruction { 32 | program_id: dex::ID, 33 | data: dex::instruction::InitializeMarketProduct { params }.data(), 34 | accounts: account_metas, 35 | }] 36 | } 37 | -------------------------------------------------------------------------------- /dexteritysdk/src/processor/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod cancel_order; 2 | pub mod clear_expired_orderbook; 3 | pub mod combo; 4 | pub mod consume_orderbook_events; 5 | pub mod deposit_funds; 6 | pub mod fees; 7 | pub mod market_product; 8 | pub mod market_product_group; 9 | pub mod new_order; 10 | pub mod orderbook; 11 | pub mod remove_market_product; 12 | pub mod trader_risk_group; 13 | pub mod transfer_full_position; 14 | pub mod update_product_funding; 15 | pub mod update_trader_funding; 16 | -------------------------------------------------------------------------------- /dexteritysdk/src/processor/remove_market_product.rs: -------------------------------------------------------------------------------- 1 | use anchor_lang::{InstructionData, ToAccountMetas}; 2 | use solana_program::{ 3 | instruction::{AccountMeta, Instruction}, 4 | pubkey::Pubkey, 5 | }; 6 | use solana_program_test::ProgramTestContext; 7 | use solana_sdk::signature::{Keypair, Signer}; 8 | 9 | use dex::{accounts, instruction}; 10 | 11 | use crate::{common::utils::*, sdk_client::SDKClient}; 12 | 13 | pub fn remove_market_product_ixs( 14 | authority: Pubkey, 15 | market_product_group: Pubkey, 16 | product: Pubkey, 17 | aaob_program_id: Pubkey, 18 | orderbook: Pubkey, 19 | market_signer: Pubkey, 20 | event_queue: Pubkey, 21 | bids: Pubkey, 22 | asks: Pubkey, 23 | ) -> Vec { 24 | let account_metas = accounts::RemoveMarketProduct { 25 | authority, 26 | market_product_group, 27 | product, 28 | aaob_program: aaob_program_id, 29 | orderbook, 30 | market_signer, 31 | event_queue, 32 | bids, 33 | asks, 34 | } 35 | .to_account_metas(None); 36 | vec![Instruction { 37 | program_id: dex::ID, 38 | data: instruction::RemoveMarketProduct.data(), 39 | accounts: account_metas, 40 | }] 41 | } 42 | -------------------------------------------------------------------------------- /dexteritysdk/src/processor/transfer_full_position.rs: -------------------------------------------------------------------------------- 1 | use crate::{common::utils::*, sdk_client::SDKClient}; 2 | use anchor_lang::{InstructionData, ToAccountMetas}; 3 | use dex::{accounts, instruction}; 4 | use solana_program::{instruction::Instruction, pubkey::Pubkey}; 5 | use solana_program_test::ProgramTestContext; 6 | use solana_sdk::signature::{Keypair, Signer}; 7 | 8 | pub fn transfer_full_position_ixs( 9 | user: Pubkey, 10 | liquidatee_risk_group: Pubkey, 11 | liquidator_risk_group: Pubkey, 12 | market_product_group: Pubkey, 13 | risk_engine_program: Pubkey, 14 | risk_output_register: Pubkey, 15 | liquidator_risk_state_account_info: Pubkey, 16 | liquidatee_risk_state_account_info: Pubkey, 17 | risk_model_configuration_acct: Pubkey, 18 | ) -> Vec { 19 | let (risk_signer, _) = Pubkey::find_program_address(&[market_product_group.as_ref()], &dex::ID); 20 | let account_metas = accounts::TransferFullPosition { 21 | liquidator: user, 22 | market_product_group, 23 | liquidatee_risk_group, 24 | liquidator_risk_group, 25 | risk_engine_program, 26 | risk_model_configuration_acct, 27 | risk_output_register, 28 | liquidator_risk_state_account_info, 29 | liquidatee_risk_state_account_info, 30 | risk_signer, 31 | } 32 | .to_account_metas(Some(true)); 33 | 34 | vec![Instruction { 35 | program_id: dex::ID, 36 | data: instruction::TransferFullPosition {}.data(), 37 | accounts: account_metas, 38 | }] 39 | } 40 | -------------------------------------------------------------------------------- /dexteritysdk/src/processor/update_product_funding.rs: -------------------------------------------------------------------------------- 1 | use crate::{common::utils::*, sdk_client::SDKClient, KeypairD}; 2 | use agnostic_orderbook::state::*; 3 | use anchor_lang::{InstructionData, ToAccountMetas}; 4 | use dex::{accounts, instruction, state::enums::OrderType, utils::numeric::Fractional}; 5 | use solana_program::{ 6 | instruction::{AccountMeta, Instruction}, 7 | pubkey::Pubkey, 8 | system_program, 9 | }; 10 | use solana_program_test::ProgramTestContext; 11 | use solana_sdk::signature::{Keypair, Signer}; 12 | 13 | pub fn update_product_funding_ixs( 14 | market_product_group: Pubkey, 15 | product: &Keypair, 16 | amount: Fractional, 17 | expired: bool, 18 | ) -> Vec { 19 | let params = dex::UpdateProductFundingParams { amount, expired }; 20 | let account_metas = accounts::UpdateProductFunding { 21 | market_product_group, 22 | product: product.pubkey(), 23 | } 24 | .to_account_metas(None); 25 | 26 | vec![Instruction { 27 | program_id: dex::ID, 28 | data: instruction::UpdateProductFunding { params }.data(), 29 | accounts: account_metas, 30 | }] 31 | } 32 | 33 | pub async fn update_product_funding( 34 | client: &SDKClient, 35 | market_product_group: Pubkey, 36 | product: &KeypairD, 37 | amount: Fractional, 38 | expired: bool, 39 | ) -> SDKResult { 40 | let ixs = update_product_funding_ixs(market_product_group, product, amount, expired); 41 | client.sign_send_instructions(ixs, vec![product]).await 42 | } 43 | -------------------------------------------------------------------------------- /dexteritysdk/src/processor/update_trader_funding.rs: -------------------------------------------------------------------------------- 1 | use crate::{common::utils::*, sdk_client::SDKClient, KeypairD}; 2 | use agnostic_orderbook::state::*; 3 | use anchor_lang::{InstructionData, ToAccountMetas}; 4 | use dex::{accounts, instruction, state::enums::OrderType, utils::numeric::Fractional}; 5 | use rand::Rng; 6 | use solana_program::{ 7 | instruction::{AccountMeta, Instruction}, 8 | pubkey::Pubkey, 9 | system_program, 10 | }; 11 | use solana_program_test::ProgramTestContext; 12 | use solana_sdk::signature::{Keypair, Signer}; 13 | 14 | pub fn update_trader_funding_ixs( 15 | trader_risk_group: Pubkey, 16 | market_product_group: Pubkey, 17 | ) -> Vec { 18 | let account_metas = accounts::UpdateTraderFunding { 19 | market_product_group, 20 | trader_risk_group, 21 | } 22 | .to_account_metas(None); 23 | 24 | let mut rng = rand::prelude::thread_rng(); 25 | let out = rng.gen_range(0..255); 26 | vec![Instruction { 27 | program_id: dex::ID, 28 | data: [instruction::UpdateTraderFunding {}.data(), vec![out]].concat(), 29 | accounts: account_metas, 30 | }] 31 | } 32 | 33 | pub async fn update_trader_funding( 34 | client: &SDKClient, 35 | user_trader_risk_group: Pubkey, 36 | market_product_group: Pubkey, 37 | ) -> SDKResult { 38 | let ixs = update_trader_funding_ixs(user_trader_risk_group, market_product_group); 39 | client.sign_send_instructions(ixs, vec![]).await 40 | } 41 | -------------------------------------------------------------------------------- /dexteritysdk/src/state.rs: -------------------------------------------------------------------------------- 1 | use std::{borrow::Borrow, cell::RefCell, marker::PhantomData, sync::Arc}; 2 | 3 | use agnostic_orderbook::state::SelfTradeBehavior; 4 | use anchor_lang::Key; 5 | use async_trait::async_trait; 6 | use solana_client::{rpc_client::RpcClient, thin_client::ThinClient}; 7 | use solana_program::{hash::Hash, instruction::Instruction, message::Message, pubkey::Pubkey}; 8 | use solana_program_test::BanksClient; 9 | use solana_sdk::{ 10 | client::{Client, SyncClient}, 11 | commitment_config::CommitmentLevel, 12 | signature::{Keypair, Signature, Signer}, 13 | signer::SignerError, 14 | signers::Signers, 15 | transaction::Transaction, 16 | transport::TransportError, 17 | }; 18 | 19 | use dex::{ 20 | state::{constants::*, enums::*, products::Leg}, 21 | utils::numeric::Fractional, 22 | }; 23 | 24 | use crate::{ 25 | common::utils::*, 26 | processor::{ 27 | cancel_order::*, combo::*, consume_orderbook_events::*, deposit_funds::*, new_order::*, 28 | orderbook::*, transfer_full_position::*, 29 | }, 30 | sdk_client::SDKClient, 31 | trader::SDKTrader, 32 | }; 33 | 34 | use crate::common::Side; 35 | use serde::{Deserialize, Serialize}; 36 | 37 | #[derive(Serialize, Deserialize)] 38 | pub struct Order { 39 | pub side: Side, 40 | pub size: Fractional, 41 | pub price: Fractional, 42 | } 43 | 44 | impl Order { 45 | pub fn new(side: Side, size: Fractional, price: Fractional) -> Self { 46 | Order { side, size, price } 47 | } 48 | } 49 | 50 | #[derive(Clone, Serialize, Deserialize)] 51 | pub struct SDKProduct { 52 | pub key: Pubkey, 53 | pub name: [u8; NAME_LEN], 54 | pub orderbook: Pubkey, 55 | pub bids: Pubkey, 56 | pub asks: Pubkey, 57 | pub market_signer: Pubkey, 58 | pub event_queue: Pubkey, 59 | } 60 | 61 | #[derive(Clone, Serialize, Deserialize)] 62 | pub struct SDKCombo { 63 | pub key: Pubkey, 64 | pub name: [u8; NAME_LEN], 65 | pub orderbook: Pubkey, 66 | pub bids: Pubkey, 67 | pub asks: Pubkey, 68 | pub market_signer: Pubkey, 69 | pub event_queue: Pubkey, 70 | } 71 | 72 | impl Key for SDKProduct { 73 | fn key(&self) -> Pubkey { 74 | self.key 75 | } 76 | } 77 | 78 | impl Key for SDKCombo { 79 | fn key(&self) -> Pubkey { 80 | self.key 81 | } 82 | } 83 | 84 | pub fn clone_keypair(keypair: &Keypair) -> Keypair { 85 | Keypair::from_bytes(&keypair.to_bytes()).unwrap() 86 | } 87 | 88 | impl SDKProduct { 89 | pub fn market_signer(product_key: Pubkey, dex_program_id: Pubkey) -> (Pubkey, u8) { 90 | Pubkey::find_program_address(&[product_key.as_ref()], &dex_program_id) 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /master_program_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "programs": { 3 | "constant_fees": "ConstantFees1111111111111111111111111111111", 4 | "dex": "Dex1111111111111111111111111111111111111111", 5 | "instruments": "instruments11111111111111111111111111111111", 6 | "alpha_risk_engine": "ARiskEngine11111111111111111111111111111111", 7 | "agnostic_orderbook": "AAoB111111111111111111111111111111111111111", 8 | "dummy_oracle": "Dummy11111111111111111111111111111111111111", 9 | "noop_risk_engine": "Noop111111111111111111111111111111111111111" 10 | } 11 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "@project-serum/anchor": "^0.19.0" 4 | }, 5 | "devDependencies": { 6 | "chai": "^4.3.4", 7 | "mocha": "^9.0.3", 8 | "ts-mocha": "^8.0.0", 9 | "@types/mocha": "^9.0.0", 10 | "typescript": "^4.3.5" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /programs/dex/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "dex" 4 | version = "0.1.0" 5 | resolver = "2" 6 | 7 | [features] 8 | no-entrypoint = [] 9 | cpi = ["no-entrypoint"] 10 | test-bpf = [] 11 | 12 | [dependencies] 13 | agnostic-orderbook = { version = "0.1.0", path = "../agnostic-orderbook/program", features = ["no-entrypoint"] } 14 | anchor-lang = "0.24.2" 15 | anchor-spl = "0.24.2" 16 | arrayref = "0.3.6" 17 | base64 = "0.13.0" 18 | bonfida-utils = "0.2" 19 | borsh = "0.9" 20 | bytemuck = { version = "1.7.2", features = ["derive"] } 21 | pyth-client = "0.3.0" 22 | spl-associated-token-account = { version = "1.0.3", features = ["no-entrypoint"] } 23 | spl-token = { version = "3.1.1", features = ["no-entrypoint"] } 24 | thiserror = "1.0" 25 | num-traits = "0.2.14" 26 | num-derive = "0.3" 27 | num = "0.4" 28 | itertools = "0.10.3" 29 | serde = "1.0.136" 30 | serde-big-array = { version = "0.3.2", features = ["const-generics"] } 31 | 32 | 33 | [dev-dependencies] 34 | solana-sdk = "1.9.4" 35 | anchor-client = "0.24.2" 36 | constant-fees = { path = "../fees/constant-fees", features = ["no-entrypoint"] } 37 | noop-risk-engine = { path = "../risk/noop-risk-engine", features = ["no-entrypoint"] } 38 | dexteritysdk = { path = "../../dexteritysdk" } 39 | alpha-risk-engine = { path = "../risk/alpha-risk-engine", features = ["no-entrypoint"] } 40 | instruments = { path = "../instruments", features = ["no-entrypoint"] } 41 | dummy-oracle = { path = "../dummy-oracle", features = ["no-entrypoint"] } 42 | arrayref = "0.3.6" 43 | hexdump = "0.1.0" 44 | rand = "0.8.4" 45 | tokio = { version = "1.6", features = ["macros"] } 46 | solana-program = "1.8.12" 47 | solana-program-test = "1.9.4" 48 | bincode = "1.3.3" 49 | 50 | [lib] 51 | crate-type = ["cdylib", "lib"] 52 | -------------------------------------------------------------------------------- /programs/dex/src/processor/change_authority.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | error::DomainOrProgramResult, utils::validation::assert_keys_equal, ChooseSuccessor, 3 | ClaimAuthority, 4 | }; 5 | use anchor_lang::prelude::*; 6 | 7 | pub fn choose_successor(ctx: Context) -> DomainOrProgramResult { 8 | let accts = ctx.accounts; 9 | let mut market_product_group = accts.market_product_group.load_mut()?; 10 | assert_keys_equal(market_product_group.authority, *accts.authority.key)?; 11 | market_product_group.successor = *accts.new_authority.key; 12 | market_product_group.sequence_number += 1; 13 | msg!("sequence: {}", market_product_group.sequence_number); 14 | accts.market_product_group.key().log(); 15 | Ok(()) 16 | } 17 | 18 | pub fn claim_authority(ctx: Context) -> DomainOrProgramResult { 19 | let accts = ctx.accounts; 20 | let mut market_product_group = accts.market_product_group.load_mut()?; 21 | assert_keys_equal(market_product_group.successor, *accts.new_authority.key)?; 22 | market_product_group.authority = *accts.new_authority.key; 23 | market_product_group.sequence_number += 1; 24 | msg!("sequence: {}", market_product_group.sequence_number); 25 | accts.market_product_group.key().log(); 26 | Ok(()) 27 | } 28 | -------------------------------------------------------------------------------- /programs/dex/src/processor/deposit_funds.rs: -------------------------------------------------------------------------------- 1 | use anchor_lang::{ 2 | prelude::*, 3 | solana_program::{ 4 | program::invoke_signed, program_error::ProgramError, program_pack::IsInitialized, 5 | pubkey::Pubkey, 6 | }, 7 | }; 8 | 9 | use crate::{ 10 | error::{DomainOrProgramResult, UtilError}, 11 | utils::validation::{assert, assert_keys_equal}, 12 | DepositFunds, DepositFundsParams, DomainOrProgramError, 13 | }; 14 | 15 | fn validate(accts: &DepositFunds) -> DomainOrProgramResult { 16 | let trader_risk_group = accts.trader_risk_group.load()?; 17 | assert_keys_equal(accts.token_program.key(), spl_token::ID)?; 18 | assert( 19 | trader_risk_group.is_initialized(), 20 | UtilError::AccountUninitialized, 21 | )?; 22 | assert_keys_equal(trader_risk_group.owner, accts.user.key())?; 23 | assert_keys_equal( 24 | trader_risk_group.market_product_group, 25 | accts.market_product_group.key(), 26 | )?; 27 | Ok(()) 28 | } 29 | 30 | pub fn process(ctx: Context, params: DepositFundsParams) -> DomainOrProgramResult { 31 | let accts = ctx.accounts; 32 | validate(accts)?; 33 | let DepositFundsParams { quantity } = params; 34 | let mut trader_risk_group = accts.trader_risk_group.load_mut()?; 35 | let market_product_group = accts.market_product_group.load()?; 36 | let vault_seeds = &[ 37 | b"market_vault", 38 | accts.market_product_group.as_ref().key.as_ref(), 39 | &[market_product_group.vault_bump as u8], 40 | ]; 41 | let vault_key = 42 | Pubkey::create_program_address(vault_seeds, ctx.program_id).map_err(ProgramError::from)?; 43 | 44 | assert_keys_equal(vault_key, accts.market_product_group_vault.key())?; 45 | 46 | let token_quantity = quantity.round(market_product_group.decimals as u32)?; 47 | 48 | // check_funds(token_quantity)?; 49 | 50 | let token_transfer_instruction = spl_token::instruction::transfer( 51 | accts.token_program.key, 52 | &accts.user_token_account.key(), 53 | &accts.market_product_group_vault.key(), 54 | accts.user.key, 55 | &[], 56 | token_quantity.m as u64, 57 | )?; 58 | 59 | invoke_signed( 60 | &token_transfer_instruction, 61 | &[ 62 | accts.token_program.to_account_info(), 63 | accts.user_token_account.to_account_info(), 64 | accts.market_product_group_vault.to_account_info(), 65 | accts.user.to_account_info(), 66 | ], 67 | &[vault_seeds], 68 | )?; 69 | trader_risk_group.total_deposited = trader_risk_group.total_deposited.checked_add(quantity)?; 70 | trader_risk_group.cash_balance = trader_risk_group.cash_balance.checked_add(quantity)?; 71 | 72 | Ok(()) 73 | } 74 | -------------------------------------------------------------------------------- /programs/dex/src/processor/initialize_trader_risk_group.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | error::{DomainOrProgramResult, UtilError}, 3 | state::{ 4 | constants::{HEALTH_BUFFER_LEN, MAX_OUTRIGHTS}, 5 | enums::AccountTag, 6 | }, 7 | utils::{cpi::create_risk_state_account, numeric::ZERO_FRAC, validation::assert_keys_equal}, 8 | InitializeTraderRiskGroup, 9 | }; 10 | use anchor_lang::{ 11 | prelude::*, 12 | solana_program::{msg, pubkey::Pubkey}, 13 | }; 14 | 15 | pub fn process<'a, 'b, 'c, 'info>( 16 | ctx: Context<'a, 'b, 'c, 'info, InitializeTraderRiskGroup<'info>>, 17 | ) -> DomainOrProgramResult { 18 | let accts = ctx.accounts; 19 | let mut trader_risk_group = accts.trader_risk_group.load_init()?; 20 | let market_product_group = accts.market_product_group.load()?; 21 | if trader_risk_group.tag != AccountTag::Uninitialized { 22 | msg!("TraderRiskGroup account is already initialized"); 23 | return Err(UtilError::AccountAlreadyInitialized.into()); 24 | } 25 | assert_keys_equal( 26 | *accts.trader_fee_state_acct.owner, 27 | market_product_group.fee_model_program_id, 28 | )?; 29 | // Risk account should not be initialized 30 | assert_keys_equal( 31 | *accts.trader_risk_state_acct.owner, 32 | accts.system_program.key(), 33 | )?; 34 | trader_risk_group.fee_state_account = accts.trader_fee_state_acct.key(); 35 | trader_risk_group.tag = AccountTag::TraderRiskGroup; 36 | trader_risk_group.owner = accts.owner.key(); 37 | trader_risk_group.market_product_group = accts.market_product_group.key(); 38 | trader_risk_group.cash_balance = ZERO_FRAC; 39 | trader_risk_group.pending_cash_balance = ZERO_FRAC; 40 | // Initialize fees as 0 41 | trader_risk_group.valid_until = 0; 42 | trader_risk_group.maker_fee_bps = 0; 43 | trader_risk_group.taker_fee_bps = 0; 44 | trader_risk_group.active_products = [u8::MAX; MAX_OUTRIGHTS]; 45 | trader_risk_group.risk_state_account = accts.trader_risk_state_acct.key(); 46 | trader_risk_group.client_order_id = 0; 47 | trader_risk_group.open_orders.initialize(); 48 | trader_risk_group.pending_fees = ZERO_FRAC; 49 | 50 | let risk_program_id = accts.risk_engine_program.key(); 51 | create_risk_state_account( 52 | &accts.risk_engine_program, 53 | &accts.owner, 54 | &accts.risk_signer, 55 | &accts.trader_risk_state_acct, 56 | &accts.market_product_group, 57 | &accts.system_program, 58 | &ctx.remaining_accounts, 59 | market_product_group 60 | .create_risk_state_account_discriminant 61 | .to_vec(), 62 | market_product_group.risk_and_fee_bump as u8, 63 | )?; 64 | 65 | // Risk state account should be initialized and assigned to the risk engine program 66 | assert_keys_equal(*accts.trader_risk_state_acct.owner, risk_program_id)?; 67 | 68 | Ok(()) 69 | } 70 | -------------------------------------------------------------------------------- /programs/dex/src/processor/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod cancel_order; 2 | pub mod change_authority; 3 | pub mod clear_expired_orderbook; 4 | pub mod consume_orderbook_events; 5 | pub mod deposit_funds; 6 | pub mod initialize_combo; 7 | pub mod initialize_market_product; 8 | pub mod initialize_market_product_group; 9 | pub mod initialize_trader_risk_group; 10 | pub mod new_order; 11 | pub mod remove_market_product; 12 | pub mod sweep_fees; 13 | pub mod transfer_full_position; 14 | pub mod update_product_funding; 15 | pub mod update_trader_funding; 16 | pub mod withdraw_funds; 17 | -------------------------------------------------------------------------------- /programs/dex/src/processor/sweep_fees.rs: -------------------------------------------------------------------------------- 1 | use anchor_lang::{ 2 | prelude::*, 3 | solana_program::{ 4 | log::sol_log_compute_units, program::invoke_signed, program_pack::IsInitialized, 5 | }, 6 | }; 7 | 8 | use crate::{ 9 | error::{DomainOrProgramResult, UtilError}, 10 | utils::{ 11 | numeric::Fractional, 12 | validation::{assert, assert_keys_equal, assert_valid_token_account_owner}, 13 | }, 14 | SweepFees, 15 | }; 16 | 17 | fn validate(ctx: &Context) -> DomainOrProgramResult { 18 | let market_product_group = ctx.accounts.market_product_group.load()?; 19 | assert( 20 | market_product_group.is_initialized(), 21 | UtilError::AccountUninitialized, 22 | )?; 23 | assert_keys_equal( 24 | market_product_group.fee_collector, 25 | ctx.accounts.fee_collector.key(), 26 | )?; 27 | assert_valid_token_account_owner( 28 | ctx.accounts.fee_collector_token_account.as_ref(), 29 | &ctx.accounts.fee_collector.key(), 30 | )?; 31 | Ok(()) 32 | } 33 | 34 | pub fn process(ctx: Context) -> DomainOrProgramResult { 35 | validate(&ctx)?; 36 | let accts = ctx.accounts; 37 | let mut market_product_group = accts.market_product_group.load_mut()?; 38 | 39 | let fees_to_sweep = market_product_group 40 | .collected_fees 41 | .round_unchecked(market_product_group.decimals as u32)?; 42 | market_product_group.collected_fees = market_product_group 43 | .collected_fees 44 | .checked_sub(fees_to_sweep)?; 45 | 46 | let vault_seeds = &[ 47 | b"market_vault", 48 | accts.market_product_group.as_ref().key.as_ref(), 49 | &[market_product_group.vault_bump as u8], 50 | ]; 51 | let vault_key = Pubkey::create_program_address(vault_seeds, ctx.program_id)?; 52 | assert_keys_equal(vault_key, accts.market_product_group_vault.key())?; 53 | 54 | let token_transfer_instruction = spl_token::instruction::transfer( 55 | &accts.token_program.key(), 56 | &accts.market_product_group_vault.key(), 57 | &accts.fee_collector_token_account.key(), 58 | &accts.market_product_group_vault.key(), 59 | &[], 60 | fees_to_sweep.m as u64, 61 | )?; 62 | invoke_signed( 63 | &token_transfer_instruction, 64 | &[ 65 | accts.token_program.to_account_info(), 66 | accts.market_product_group_vault.to_account_info(), 67 | accts.fee_collector_token_account.to_account_info(), 68 | ], 69 | &[vault_seeds], 70 | )?; 71 | market_product_group.sequence_number += 1; 72 | msg!("sequence: {}", market_product_group.sequence_number); 73 | accts.market_product_group.key().log(); 74 | Ok(()) 75 | } 76 | -------------------------------------------------------------------------------- /programs/dex/src/processor/update_product_funding.rs: -------------------------------------------------------------------------------- 1 | use anchor_lang::{ 2 | prelude::*, 3 | solana_program::{msg, program_pack::IsInitialized}, 4 | }; 5 | 6 | use crate::{ 7 | error::{DexError, DomainOrProgramResult, UtilError}, 8 | state::enums::ProductStatus, 9 | utils::validation::assert, 10 | UpdateProductFunding, UpdateProductFundingParams, 11 | }; 12 | 13 | pub fn process( 14 | ctx: Context, 15 | params: UpdateProductFundingParams, 16 | ) -> DomainOrProgramResult { 17 | let accts = ctx.accounts; 18 | let mut market_product_group = accts.market_product_group.load_mut()?; 19 | assert( 20 | market_product_group.is_initialized(), 21 | UtilError::AccountUninitialized, 22 | )?; 23 | 24 | let (idx, _) = market_product_group.find_product_index(&accts.product.key())?; 25 | let cash_decimals = market_product_group.decimals; 26 | let product = market_product_group.market_products[idx].try_to_outright_mut()?; 27 | product.apply_new_funding(params.amount, cash_decimals)?; 28 | 29 | if params.expired { 30 | product.product_status = ProductStatus::Expired; 31 | } 32 | market_product_group.sequence_number += 1; 33 | msg!("sequence: {}", market_product_group.sequence_number); 34 | accts.market_product_group.key().log(); 35 | Ok(()) 36 | } 37 | -------------------------------------------------------------------------------- /programs/dex/src/processor/update_trader_funding.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | error::{DomainOrProgramResult, UtilError}, 3 | utils::validation::{assert, assert_keys_equal}, 4 | UpdateTraderFunding, 5 | }; 6 | use anchor_lang::{prelude::*, solana_program::program_pack::IsInitialized}; 7 | 8 | pub fn process(ctx: Context) -> DomainOrProgramResult { 9 | let accts = ctx.accounts; 10 | let mut trader_risk_group = accts.trader_risk_group.load_mut()?; 11 | let mut market_product_group = accts.market_product_group.load_mut()?; 12 | 13 | // validate 14 | { 15 | assert_keys_equal( 16 | trader_risk_group.market_product_group, 17 | accts.market_product_group.key(), 18 | )?; 19 | assert( 20 | market_product_group.is_initialized(), 21 | UtilError::AccountUninitialized, 22 | )?; 23 | assert( 24 | trader_risk_group.is_initialized(), 25 | UtilError::AccountUninitialized, 26 | )?; 27 | } 28 | 29 | trader_risk_group.apply_all_funding(&mut market_product_group)?; 30 | market_product_group.sequence_number += 1; 31 | msg!("sequence: {}", market_product_group.sequence_number); 32 | accts.market_product_group.key().log(); 33 | Ok(()) 34 | } 35 | -------------------------------------------------------------------------------- /programs/dex/src/state/callback_info.rs: -------------------------------------------------------------------------------- 1 | use anchor_lang::{prelude::*, solana_program::pubkey::Pubkey}; 2 | use bytemuck::{Pod, Zeroable}; 3 | 4 | use crate::utils::loadable::Loadable; 5 | 6 | #[repr(C)] 7 | #[derive(Debug, Clone, Copy, Zeroable, Pod, AnchorSerialize, AnchorDeserialize)] 8 | /// Buffer attached to aaob events to tie owner to events 9 | pub struct CallBackInfo { 10 | pub user_account: Pubkey, 11 | pub open_orders_idx: u64, 12 | } 13 | 14 | impl CallBackInfo { 15 | pub fn to_vec(&self) -> Vec { 16 | [ 17 | self.user_account.to_bytes().to_vec(), 18 | self.open_orders_idx.to_le_bytes().to_vec(), 19 | ] 20 | .concat() 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /programs/dex/src/state/constants.rs: -------------------------------------------------------------------------------- 1 | use crate::utils::numeric::Fractional; 2 | 3 | use anchor_lang::prelude::*; 4 | 5 | #[constant] 6 | pub const NAME_LEN: usize = 16; 7 | 8 | #[constant] 9 | pub const MAX_OUTRIGHTS: usize = 128; 10 | 11 | #[constant] 12 | pub const MAX_PRODUCTS: usize = 256; 13 | 14 | #[constant] 15 | pub const HEALTH_BUFFER_LEN: usize = 32; 16 | 17 | #[constant] 18 | pub const MAX_TRADER_POSITIONS: usize = 16; 19 | 20 | #[constant] 21 | pub const MAX_OPEN_ORDERS_PER_POSITION: u64 = 256; 22 | 23 | #[constant] 24 | pub const MAX_OPEN_ORDERS: usize = 1024; 25 | 26 | #[constant] 27 | pub const ANCHOR_DISCRIMINANT_LEN: usize = 8; 28 | 29 | pub const NO_BID_PRICE: Fractional = Fractional { 30 | m: i64::MIN, 31 | exp: 0, 32 | }; 33 | 34 | pub const NO_ASK_PRICE: Fractional = Fractional { 35 | m: i64::MAX, 36 | exp: 0, 37 | }; 38 | 39 | #[constant] 40 | pub const SENTINEL: usize = 0; 41 | 42 | /// The length in bytes of the callback information in the associated asset agnostic orderbook 43 | #[constant] 44 | pub const CALLBACK_INFO_LEN: u64 = 40; 45 | /// The length in bytes of the callback identifer prefix in the associated asset agnostic orderbook 46 | #[constant] 47 | pub const CALLBACK_ID_LEN: u64 = 32; 48 | 49 | #[constant] 50 | pub const MAX_COMBOS: usize = 128; 51 | 52 | #[constant] 53 | pub const MAX_LEGS: usize = 4; 54 | 55 | // timing constants 56 | #[constant] 57 | pub const SLOTS_1_MIN: u64 = 150; 58 | 59 | #[constant] 60 | pub const SLOTS_5_MIN: u64 = 750; 61 | 62 | #[constant] 63 | pub const SLOTS_15_MIN: u64 = 2250; 64 | 65 | #[constant] 66 | pub const SLOTS_60_MIN: u64 = 9000; 67 | -------------------------------------------------------------------------------- /programs/dex/src/state/enums.rs: -------------------------------------------------------------------------------- 1 | use anchor_lang::prelude::*; 2 | use bytemuck::{Pod, Zeroable}; 3 | use serde::{Deserialize, Serialize}; 4 | 5 | use crate::utils::loadable::Loadable; 6 | 7 | #[derive( 8 | Copy, AnchorSerialize, AnchorDeserialize, Clone, Debug, PartialEq, Deserialize, Serialize, 9 | )] 10 | #[repr(u64)] 11 | pub enum AccountTag { 12 | Uninitialized, 13 | MarketProductGroup, 14 | TraderRiskGroup, 15 | TraderPosition, 16 | MarketProductGroupWithCombos, 17 | ComboGroup, 18 | Combo, 19 | RiskProfile, 20 | } 21 | 22 | impl Default for AccountTag { 23 | fn default() -> Self { 24 | AccountTag::Uninitialized 25 | } 26 | } 27 | 28 | unsafe impl Zeroable for AccountTag {} 29 | 30 | unsafe impl Pod for AccountTag {} 31 | 32 | impl AccountTag { 33 | pub fn to_bytes(&self) -> [u8; 8] { 34 | match self { 35 | AccountTag::Uninitialized => 0_u64.to_le_bytes(), 36 | AccountTag::MarketProductGroup => 1_u64.to_le_bytes(), 37 | AccountTag::TraderRiskGroup => 2_u64.to_le_bytes(), 38 | AccountTag::TraderPosition => 3_u64.to_le_bytes(), 39 | AccountTag::MarketProductGroupWithCombos => 4_u64.to_le_bytes(), 40 | AccountTag::ComboGroup => 5_u64.to_le_bytes(), 41 | AccountTag::Combo => 6_u64.to_le_bytes(), 42 | AccountTag::RiskProfile => 7_u64.to_le_bytes(), 43 | } 44 | } 45 | } 46 | 47 | #[derive( 48 | Eq, Copy, AnchorSerialize, AnchorDeserialize, Clone, Debug, PartialEq, Deserialize, Serialize, 49 | )] 50 | #[repr(u64)] 51 | pub enum ProductStatus { 52 | Uninitialized, 53 | Initialized, 54 | Expired, 55 | } 56 | 57 | impl Default for ProductStatus { 58 | fn default() -> Self { 59 | ProductStatus::Uninitialized 60 | } 61 | } 62 | 63 | unsafe impl Zeroable for ProductStatus {} 64 | 65 | unsafe impl Pod for ProductStatus {} 66 | 67 | #[derive(AnchorDeserialize, AnchorSerialize, Debug, PartialEq, Clone, Deserialize, Serialize)] // serde 68 | #[repr(u64)] 69 | pub enum OrderType { 70 | Limit, 71 | ImmediateOrCancel, 72 | FillOrKill, 73 | PostOnly, 74 | } 75 | -------------------------------------------------------------------------------- /programs/dex/src/state/fee_model.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | utils::{loadable::Loadable, numeric::bps}, 3 | Fractional, MarketProductGroup, 4 | }; 5 | use agnostic_orderbook::state::Side; 6 | use anchor_lang::{prelude::*, solana_program::clock::UnixTimestamp}; 7 | use bytemuck::{Pod, Zeroable}; 8 | 9 | #[repr(C)] 10 | #[zero_copy] 11 | #[derive(Debug, Zeroable, Pod)] 12 | pub struct TraderFees { 13 | pub valid_until: UnixTimestamp, 14 | pub maker_fee_bps: i32, 15 | pub taker_fee_bps: i32, 16 | } 17 | 18 | #[derive(Copy, Clone, Debug, AnchorDeserialize, AnchorSerialize)] 19 | pub struct TraderFeeParams { 20 | pub side: Side, 21 | pub is_aggressor: bool, 22 | pub matched_quote_qty: Fractional, 23 | pub matched_base_qty: Fractional, 24 | pub product: Pubkey, 25 | } 26 | 27 | // 10_000 bps == 100% 28 | const MAX_FEE_BPS: i32 = 10_000; 29 | const MIN_FEE_BPS: i32 = -10_000; 30 | 31 | fn clamp_fees(fee: i32) -> i32 { 32 | within_or_zero(fee, MAX_FEE_BPS, MIN_FEE_BPS) 33 | } 34 | 35 | fn within_or_zero(x: i32, max: impl Into, min: impl Into) -> i32 { 36 | if x > max.into() || x < min.into() { 37 | 0 38 | } else { 39 | x 40 | } 41 | } 42 | 43 | impl TraderFees { 44 | pub fn new(maker_fee_bps: i32, taker_fee_bps: i32, valid_until: UnixTimestamp) -> Self { 45 | Self { 46 | valid_until, 47 | maker_fee_bps, 48 | taker_fee_bps, 49 | } 50 | } 51 | 52 | pub fn maker_fee_bps(&self, market_product_group: Option<&MarketProductGroup>) -> Fractional { 53 | let fee = market_product_group 54 | .map(|mpg| { 55 | within_or_zero( 56 | self.maker_fee_bps, 57 | mpg.max_maker_fee_bps, 58 | mpg.min_maker_fee_bps, 59 | ) 60 | }) 61 | .unwrap_or(clamp_fees(self.maker_fee_bps)); 62 | 63 | bps(fee as i64) 64 | } 65 | 66 | pub fn taker_fee_bps(&self, market_product_group: Option<&MarketProductGroup>) -> Fractional { 67 | let fee = market_product_group 68 | .map(|mpg| { 69 | within_or_zero( 70 | self.taker_fee_bps, 71 | mpg.max_taker_fee_bps, 72 | mpg.min_taker_fee_bps, 73 | ) 74 | }) 75 | .unwrap_or(clamp_fees(self.taker_fee_bps)); 76 | 77 | bps(fee as i64) 78 | } 79 | 80 | pub fn set_taker_fee_bps(&mut self, taker_fee_bps: i32) { 81 | self.taker_fee_bps = clamp_fees(taker_fee_bps); 82 | } 83 | 84 | pub fn set_maker_fee_bps(&mut self, maker_fee_bps: i32) { 85 | self.maker_fee_bps = clamp_fees(maker_fee_bps); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /programs/dex/src/state/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod callback_info; 2 | pub mod constants; 3 | pub mod enums; 4 | pub mod fee_model; 5 | pub mod market_product_group; 6 | pub mod open_orders; 7 | pub mod products; 8 | pub mod risk_engine_register; 9 | pub mod trader_risk_group; 10 | -------------------------------------------------------------------------------- /programs/dex/src/utils/loadable.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | any::type_name, 3 | cell::{Ref, RefMut}, 4 | mem, 5 | mem::size_of, 6 | }; 7 | 8 | use anchor_lang::solana_program::{account_info::AccountInfo, msg}; 9 | use bytemuck::{Pod, PodCastError}; 10 | 11 | use crate::error::{DexError, DomainOrProgramError}; 12 | 13 | fn error_msg(data_len: usize) -> impl Fn(PodCastError) -> DomainOrProgramError { 14 | move |_: PodCastError| -> DomainOrProgramError { 15 | msg!( 16 | "Failed to load {}. Size is {}, expected {}", 17 | type_name::(), 18 | data_len, 19 | size_of::(), 20 | ); 21 | DomainOrProgramError::DexErr(DexError::InvalidBytesForZeroCopyDeserialization) 22 | } 23 | } 24 | 25 | pub trait Loadable: Pod { 26 | fn load<'a>( 27 | account: &'a AccountInfo, 28 | ) -> std::result::Result, DomainOrProgramError> { 29 | let size = mem::size_of::(); 30 | Ok(Ref::map(account.try_borrow_data()?, |data| { 31 | bytemuck::try_from_bytes(&data[..size]) 32 | .map_err(error_msg::(data.len())) 33 | .unwrap() 34 | })) 35 | } 36 | 37 | fn load_mut<'a>( 38 | account: &'a AccountInfo, 39 | ) -> std::result::Result, DomainOrProgramError> { 40 | let size = mem::size_of::(); 41 | Ok(RefMut::map(account.try_borrow_mut_data()?, |data| { 42 | let data_len = data.len(); 43 | bytemuck::try_from_bytes_mut(&mut data[..size]) 44 | .map_err(error_msg::(data_len)) 45 | .unwrap() 46 | })) 47 | } 48 | 49 | fn load_from_bytes(data: &[u8]) -> std::result::Result<&Self, DomainOrProgramError> { 50 | bytemuck::try_from_bytes(data).map_err(error_msg::(data.len())) 51 | } 52 | 53 | fn load_from_bytes_mut( 54 | data: &mut [u8], 55 | ) -> std::result::Result<&mut Self, DomainOrProgramError> { 56 | let data_len = data.len(); 57 | bytemuck::try_from_bytes_mut(data).map_err(error_msg::(data_len)) 58 | } 59 | 60 | #[deprecated] 61 | fn load_partial_mut<'a>( 62 | account: &'a AccountInfo, 63 | ) -> std::result::Result, DomainOrProgramError> { 64 | Loadable::load_mut(account) 65 | } 66 | } 67 | 68 | impl Loadable for T {} 69 | -------------------------------------------------------------------------------- /programs/dex/src/utils/logs.rs: -------------------------------------------------------------------------------- 1 | use agnostic_orderbook::state::OrderSummary; 2 | use anchor_lang::prelude::*; 3 | #[event] 4 | pub struct DexOrderSummary { 5 | pub posted_order_id: Option, 6 | pub total_base_qty: u64, 7 | pub total_quote_qty: u64, 8 | pub total_base_qty_posted: u64, 9 | } 10 | 11 | impl DexOrderSummary { 12 | pub fn new( 13 | posted_order_id: Option, 14 | total_base_qty: u64, 15 | total_quote_qty: u64, 16 | total_base_qty_posted: u64, 17 | ) -> Self { 18 | DexOrderSummary { 19 | posted_order_id, 20 | total_base_qty, 21 | total_quote_qty, 22 | total_base_qty_posted, 23 | } 24 | } 25 | pub fn from(order_summary: &OrderSummary) -> Self { 26 | DexOrderSummary::new( 27 | order_summary.posted_order_id, 28 | order_summary.total_base_qty, 29 | order_summary.total_quote_qty, 30 | order_summary.total_base_qty_posted, 31 | ) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /programs/dex/src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod bitset; 2 | pub mod cpi; 3 | pub mod loadable; 4 | pub mod logs; 5 | pub mod numeric; 6 | pub mod orderbook; 7 | pub mod param; 8 | pub mod validation; 9 | 10 | pub enum TwoIterators { 11 | A(X), 12 | B(Y), 13 | } 14 | 15 | impl Iterator for TwoIterators 16 | where 17 | X: Iterator, 18 | Y: Iterator, 19 | { 20 | type Item = (i64, usize); 21 | 22 | fn next(&mut self) -> Option { 23 | match self { 24 | TwoIterators::A(x) => x.next(), 25 | TwoIterators::B(y) => y.next(), 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /programs/dex/tests/test_liquidation_simple_risk_engine.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /programs/dex/tests/test_no_negative_order_size.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | use agnostic_orderbook::state::Side; 3 | use dex::utils::numeric::Fractional; 4 | 5 | mod setup; 6 | use crate::setup::bootstrap_tests; 7 | 8 | #[tokio::test] 9 | async fn test_no_negative_order_size() { 10 | let (ctx, traders) = 11 | &mut bootstrap_tests("noop_risk_engine", "constant_fees", "test", 1, 1).await; 12 | let product_0 = ctx.products[0].clone(); 13 | let trader_0 = traders[0].clone(); 14 | let res = trader_0 15 | .place_order( 16 | ctx, 17 | &product_0, 18 | Side::Bid, 19 | Fractional::new(-1000, 1), 20 | Fractional::from(100), 21 | ) 22 | .await; 23 | assert!(res.is_err()); 24 | } 25 | -------------------------------------------------------------------------------- /programs/dummy-oracle/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dummy-oracle" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [features] 7 | no-entrypoint = [] 8 | test-bpf = [] 9 | 10 | [dependencies] 11 | solana-program = "1.8.12" 12 | thiserror = "1.0" 13 | spl-token = {version = "3.1.1", features = ["no-entrypoint"]} 14 | spl-associated-token-account = {version = "1.0.3", features = ["no-entrypoint"]} 15 | arrayref = "0.3.6" 16 | borsh = "0.9" 17 | bincode = "1.3.3" 18 | 19 | [lib] 20 | crate-type = ["cdylib", "lib"] 21 | -------------------------------------------------------------------------------- /programs/dummy-oracle/src/entrypoint.rs: -------------------------------------------------------------------------------- 1 | #![cfg(all(target_arch = "bpf", not(feature = "no-entrypoint")))] 2 | 3 | use solana_program::{ 4 | account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, pubkey::Pubkey, 5 | }; 6 | 7 | use crate::processor::Processor; 8 | 9 | entrypoint!(process_instruction); 10 | fn process_instruction( 11 | program_id: &Pubkey, 12 | accounts: &[AccountInfo], 13 | instruction_data: &[u8], 14 | ) -> ProgramResult { 15 | Processor::process(program_id, accounts, instruction_data) 16 | } 17 | -------------------------------------------------------------------------------- /programs/dummy-oracle/src/error.rs: -------------------------------------------------------------------------------- 1 | use thiserror::Error; 2 | 3 | use solana_program::program_error::ProgramError; 4 | 5 | #[derive(Error, Debug, Copy, Clone)] 6 | pub enum UtilError { 7 | #[error("PublicKeyMismatch")] 8 | PublicKeyMismatch, 9 | #[error("AssertionError")] 10 | AssertionError, 11 | #[error("InvalidMintAuthority")] 12 | InvalidMintAuthority, 13 | #[error("AccountUninitialized")] 14 | AccountUninitialized, 15 | #[error("IncorrectOwner")] 16 | IncorrectOwner, 17 | #[error("PublicKeysShouldBeUnique")] 18 | PublicKeysShouldBeUnique, 19 | #[error("NotRentExempt")] 20 | NotRentExempt, 21 | #[error("NumericalOverflow")] 22 | NumericalOverflow, 23 | } 24 | 25 | impl From for ProgramError { 26 | fn from(e: UtilError) -> Self { 27 | ProgramError::Custom(e as u32) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /programs/dummy-oracle/src/instruction.rs: -------------------------------------------------------------------------------- 1 | pub use crate::processor::{initialize_clock, initialize_oracle, update_clock, update_price}; 2 | use borsh::{BorshDeserialize, BorshSerialize}; 3 | 4 | #[derive(BorshSerialize, BorshDeserialize, Clone)] 5 | pub enum DummyInstruction { 6 | InitializeClock(initialize_clock::Params), 7 | 8 | InitializeOracle(initialize_oracle::Params), 9 | 10 | UpdateClock(update_clock::Params), 11 | 12 | UpdatePrice(update_price::Params), 13 | } 14 | -------------------------------------------------------------------------------- /programs/dummy-oracle/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[doc(hidden)] 2 | pub mod entrypoint; 3 | pub mod error; 4 | pub mod instruction; 5 | pub mod processor; 6 | pub mod state; 7 | pub mod utils; 8 | -------------------------------------------------------------------------------- /programs/dummy-oracle/src/processor/initialize_clock.rs: -------------------------------------------------------------------------------- 1 | use crate::utils::{assert_keys_equal, assert_signer, get_rent}; 2 | use bincode; 3 | use borsh::{BorshDeserialize, BorshSerialize}; 4 | use solana_program::{ 5 | account_info::{next_account_info, AccountInfo}, 6 | entrypoint::ProgramResult, 7 | msg, 8 | program::invoke_signed, 9 | program_error::ProgramError, 10 | pubkey::Pubkey, 11 | system_instruction, system_program, 12 | sysvar::{clock::Clock, rent::Rent, Sysvar}, 13 | }; 14 | 15 | #[repr(C)] 16 | #[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug, Clone)] 17 | pub struct Params {} 18 | 19 | struct Context<'a, 'b: 'a> { 20 | clock: &'a AccountInfo<'b>, 21 | update_authority: &'a AccountInfo<'b>, 22 | system_program: &'a AccountInfo<'b>, 23 | rent: Rent, 24 | } 25 | 26 | impl<'a, 'b: 'a> Context<'a, 'b> { 27 | pub fn parse( 28 | _program_id: &Pubkey, 29 | accounts: &'a [AccountInfo<'b>], 30 | ) -> std::result::Result { 31 | let accounts_iter = &mut accounts.iter(); 32 | let a = Self { 33 | clock: next_account_info(accounts_iter)?, 34 | update_authority: next_account_info(accounts_iter)?, 35 | system_program: next_account_info(accounts_iter)?, 36 | rent: Rent::get()?, 37 | }; 38 | assert_keys_equal(*a.system_program.key, system_program::id())?; 39 | assert_signer(a.update_authority)?; 40 | Ok(a) 41 | } 42 | } 43 | 44 | pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], _params: Params) -> ProgramResult { 45 | let ctx = Context::parse(program_id, accounts)?; 46 | if ctx.clock.data_is_empty() { 47 | let seeds_without_bump: &[&[u8]] = &[b"clock"]; 48 | let (_key, bump_seed) = Pubkey::find_program_address(seeds_without_bump, program_id); 49 | let seeds = &[seeds_without_bump[0], &[bump_seed]]; 50 | invoke_signed( 51 | &system_instruction::create_account( 52 | ctx.update_authority.key, 53 | ctx.clock.key, 54 | get_rent(&ctx.rent, Clock::size_of() as u64, ctx.clock), 55 | Clock::size_of() as u64, 56 | program_id, 57 | ), 58 | &[ 59 | ctx.update_authority.clone(), 60 | ctx.clock.clone(), 61 | ctx.system_program.clone(), 62 | ], 63 | &[seeds], 64 | )?; 65 | } 66 | let mut clock: Clock = bincode::deserialize(&ctx.clock.data.borrow()).ok().unwrap(); 67 | 68 | clock.slot = 0; 69 | clock.epoch_start_timestamp = 0; 70 | clock.epoch = 0; 71 | clock.leader_schedule_epoch = 0; 72 | clock.unix_timestamp = 0; 73 | 74 | bincode::serialize_into(&mut *ctx.clock.data.borrow_mut(), &clock).ok(); 75 | Ok(()) 76 | } 77 | -------------------------------------------------------------------------------- /programs/dummy-oracle/src/processor/update_clock.rs: -------------------------------------------------------------------------------- 1 | use bincode; 2 | use borsh::{BorshDeserialize, BorshSerialize}; 3 | use solana_program::{ 4 | account_info::{next_account_info, AccountInfo}, 5 | entrypoint::ProgramResult, 6 | msg, 7 | program_error::ProgramError, 8 | pubkey::Pubkey, 9 | sysvar::clock::Clock, 10 | }; 11 | 12 | #[repr(C)] 13 | #[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug, Clone)] 14 | pub struct Params { 15 | pub slot: u64, 16 | pub epoch_start_timestamp: i64, 17 | pub epoch: u64, 18 | pub leader_schedule_epoch: u64, 19 | pub unix_timestamp: i64, 20 | } 21 | 22 | struct Context<'a, 'b: 'a> { 23 | clock: &'a AccountInfo<'b>, 24 | } 25 | 26 | impl<'a, 'b: 'a> Context<'a, 'b> { 27 | pub fn parse( 28 | _program_id: &Pubkey, 29 | accounts: &'a [AccountInfo<'b>], 30 | ) -> std::result::Result { 31 | let accounts_iter = &mut accounts.iter(); 32 | let a = Self { 33 | clock: next_account_info(accounts_iter)?, 34 | }; 35 | Ok(a) 36 | } 37 | } 38 | 39 | pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], params: Params) -> ProgramResult { 40 | let ctx = Context::parse(program_id, accounts)?; 41 | let mut clock: Clock = bincode::deserialize(&ctx.clock.data.borrow()).ok().unwrap(); 42 | clock.slot = params.slot; 43 | clock.epoch_start_timestamp = params.epoch_start_timestamp; 44 | clock.epoch = params.epoch; 45 | clock.leader_schedule_epoch = params.leader_schedule_epoch; 46 | clock.unix_timestamp = params.unix_timestamp; 47 | bincode::serialize_into(&mut *ctx.clock.data.borrow_mut(), &clock).ok(); 48 | Ok(()) 49 | } 50 | -------------------------------------------------------------------------------- /programs/dummy-oracle/src/processor/update_price.rs: -------------------------------------------------------------------------------- 1 | use crate::{state::OraclePrice, utils::assert_signer}; 2 | use borsh::{BorshDeserialize, BorshSerialize}; 3 | use solana_program::{ 4 | account_info::{next_account_info, AccountInfo}, 5 | entrypoint::ProgramResult, 6 | msg, 7 | program_error::ProgramError, 8 | pubkey::Pubkey, 9 | sysvar::{clock::Clock, Sysvar}, 10 | }; 11 | 12 | #[repr(C)] 13 | #[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug, Clone)] 14 | pub struct Params { 15 | pub price: i64, 16 | pub decimals: u64, 17 | } 18 | 19 | struct Context<'a, 'b: 'a> { 20 | oracle_price: &'a AccountInfo<'b>, 21 | update_authority: &'a AccountInfo<'b>, 22 | clock: Clock, 23 | } 24 | 25 | impl<'a, 'b: 'a> Context<'a, 'b> { 26 | pub fn parse( 27 | _program_id: &Pubkey, 28 | accounts: &'a [AccountInfo<'b>], 29 | ) -> std::result::Result { 30 | let accounts_iter = &mut accounts.iter(); 31 | let a = Self { 32 | oracle_price: next_account_info(accounts_iter)?, 33 | update_authority: next_account_info(accounts_iter)?, 34 | clock: Clock::get()?, 35 | }; 36 | assert_signer(a.update_authority)?; 37 | Ok(a) 38 | } 39 | } 40 | 41 | pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], params: Params) -> ProgramResult { 42 | let ctx = Context::parse(program_id, accounts)?; 43 | let mut oracle_price = OraclePrice::try_from_slice(&ctx.oracle_price.data.borrow_mut())?; 44 | if !oracle_price.is_initialized() { 45 | msg!("Oracle Price account is not initialized"); 46 | return Err(ProgramError::InvalidAccountData); 47 | } 48 | 49 | if *ctx.update_authority.key != oracle_price.update_authority { 50 | msg!("Update Authorities do not match"); 51 | return Err(ProgramError::InvalidAccountData); 52 | } 53 | 54 | oracle_price.price = params.price; 55 | oracle_price.decimals = params.decimals; 56 | oracle_price.slot = ctx.clock.slot; 57 | 58 | oracle_price.serialize(&mut *ctx.oracle_price.data.borrow_mut())?; 59 | Ok(()) 60 | } 61 | -------------------------------------------------------------------------------- /programs/dummy-oracle/src/state.rs: -------------------------------------------------------------------------------- 1 | use borsh::{BorshDeserialize, BorshSerialize}; 2 | 3 | use solana_program::pubkey::Pubkey; 4 | 5 | #[derive(BorshDeserialize, BorshSerialize, Copy, Clone, Debug, PartialEq)] 6 | #[repr(u8)] 7 | pub enum AccountTag { 8 | Uninitialized, 9 | OraclePrice, 10 | } 11 | 12 | #[repr(C)] 13 | #[derive(BorshSerialize, BorshDeserialize, Debug, Clone)] 14 | pub struct OraclePrice { 15 | pub tag: AccountTag, 16 | pub price: i64, 17 | pub decimals: u64, 18 | pub slot: u64, 19 | pub update_authority: Pubkey, 20 | } 21 | 22 | impl OraclePrice { 23 | pub const LEN: u64 = 1 // tag 24 | + 8 // price 25 | + 8 // decimals 26 | + 8 // slot 27 | + 32 // update_authority 28 | ; 29 | 30 | pub fn is_initialized(&self) -> bool { 31 | self.tag == AccountTag::OraclePrice 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /programs/fees/constant-fees/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "constant-fees" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [features] 7 | no-entrypoint = [] 8 | test-bpf = [] 9 | 10 | [dependencies] 11 | anchor-lang = "0.24.2" 12 | dex = { path = "../../dex", features = ["no-entrypoint"] } 13 | solana-program = "1.8.12" 14 | thiserror = "1.0" 15 | arrayref = "0.3.6" 16 | borsh = "0.9" 17 | bytemuck = { version = "1.7.2", features = ["derive"] } 18 | 19 | [lib] 20 | crate-type = ["cdylib", "lib"] 21 | -------------------------------------------------------------------------------- /programs/instruments/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "instruments" 3 | version = "0.1.0" 4 | description = "Created with Anchor" 5 | edition = "2018" 6 | 7 | [lib] 8 | crate-type = ["cdylib", "lib"] 9 | name = "instruments" 10 | 11 | [features] 12 | no-entrypoint = [] 13 | no-idl = [] 14 | no-log-ix-name = [] 15 | cpi = ["no-entrypoint"] 16 | default = [] 17 | 18 | [dependencies] 19 | anchor-lang = "0.24.2" 20 | solana-program = "1.8.12" 21 | thiserror = "1.0" 22 | spl-token = {version = "3.1.1", features = ["no-entrypoint"]} 23 | spl-associated-token-account = {version = "1.0.3", features = ["no-entrypoint"]} 24 | dex = { path = "../dex", features = ["no-entrypoint", "cpi"]} 25 | dummy-oracle = { path = "../dummy-oracle", features = ["no-entrypoint"]} 26 | bytemuck = {version = "1.7.2", features = ["derive"]} 27 | arrayref = "0.3.6" 28 | borsh = "0.9" 29 | pyth-client = {git = "https://github.com/pyth-network/pyth-client-rs", rev = "396b7e9"} 30 | num-traits = "0.2.14" 31 | num-derive = "0.3" 32 | bincode = "1.3.1" 33 | 34 | [dev-dependencies] 35 | hexdump = "0.1.0" 36 | solana-sdk = "1.8.0" 37 | rand = "0.8.4" 38 | arrayref = "0.3.6" 39 | solana-program-test = "1.8.0" 40 | tokio = {version="1.6", features = ["macros"]} 41 | 42 | -------------------------------------------------------------------------------- /programs/instruments/Xargo.toml: -------------------------------------------------------------------------------- 1 | [target.bpfel-unknown-unknown.dependencies.std] 2 | features = [] 3 | -------------------------------------------------------------------------------- /programs/instruments/src/error.rs: -------------------------------------------------------------------------------- 1 | use dex::error::DomainOrProgramError; 2 | use num_derive::FromPrimitive; 3 | use solana_program::{decode_error::DecodeError, program_error::ProgramError}; 4 | use thiserror::Error; 5 | 6 | #[derive(Error, Debug, Copy, Clone, FromPrimitive, PartialEq)] 7 | pub enum DerivativeError { 8 | #[error("AccountAlreadyInitialized")] 9 | AccountAlreadyInitialized, 10 | #[error("InvalidSettlementTime")] 11 | InvalidSettlementTime, 12 | #[error("InvalidCreationTime")] 13 | InvalidCreationTime, 14 | #[error("UninitializedAccount")] 15 | UninitializedAccount, 16 | #[error("InvalidSequenceNumber")] 17 | InvalidSequenceNumber, 18 | #[error("UnsettledAccounts")] 19 | UnsettledAccounts, 20 | #[error("InvalidOracleConfig")] 21 | InvalidOracleConfig, 22 | #[error("NumericalOverflow")] 23 | NumericalOverflow, 24 | #[error("CannotBeDeleted")] 25 | CannotBeDeleted, 26 | #[error("ContractIsExpired")] 27 | ContractIsExpired, 28 | #[error("InvalidDate")] 29 | InvalidDate, 30 | #[error("InvalidAccount")] 31 | InvalidAccount, 32 | } 33 | 34 | impl From for ProgramError { 35 | fn from(e: DerivativeError) -> Self { 36 | ProgramError::Custom(e as u32) 37 | } 38 | } 39 | 40 | impl DecodeError for DerivativeError { 41 | fn type_of() -> &'static str { 42 | "DerivativeError" 43 | } 44 | } 45 | 46 | impl From for DomainOrProgramError { 47 | fn from(e: DerivativeError) -> Self { 48 | DomainOrProgramError::Other { 49 | code: e as u32, 50 | msg: format!("{}", e), 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /programs/instruments/src/processor/close_derivative_account.rs: -------------------------------------------------------------------------------- 1 | use crate::{error::DerivativeError, state::enums::AccountTag, CloseDerivativeAccount}; 2 | use anchor_lang::prelude::*; 3 | use dex::{ 4 | error::UtilError, 5 | utils::validation::{assert, assert_keys_equal}, 6 | }; 7 | use solana_program::entrypoint::ProgramResult; 8 | 9 | pub fn process(ctx: Context) -> ProgramResult { 10 | let accts = ctx.accounts; 11 | let mut derivative_metadata = accts.derivative_metadata.load_mut()?; 12 | assert_keys_equal(*accts.derivative_metadata.as_ref().owner, *ctx.program_id)?; 13 | assert( 14 | derivative_metadata.is_initialized(), 15 | UtilError::AccountUninitialized, 16 | )?; 17 | assert_keys_equal( 18 | *accts.close_authority.key, 19 | derivative_metadata.close_authority, 20 | )?; 21 | assert_keys_equal( 22 | derivative_metadata.get_key(ctx.program_id)?, 23 | accts.derivative_metadata.key(), 24 | )?; 25 | assert( 26 | derivative_metadata.expired(), 27 | DerivativeError::CannotBeDeleted, 28 | )?; 29 | let dest_starting_lamports = accts.destination.lamports(); 30 | **accts.destination.lamports.borrow_mut() = dest_starting_lamports 31 | .checked_add(accts.derivative_metadata.as_ref().lamports()) 32 | .ok_or(DerivativeError::NumericalOverflow)?; 33 | **accts.derivative_metadata.as_ref().lamports.borrow_mut() = 0; 34 | derivative_metadata.tag = AccountTag::Uninitialized; 35 | Ok(()) 36 | } 37 | -------------------------------------------------------------------------------- /programs/instruments/src/processor/initialize_derivative.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | error::DerivativeError, 3 | state::enums::{AccountTag, ExpirationStatus, InstrumentType}, 4 | InitializeDerivative, InitializeDerivativeParams, 5 | }; 6 | use anchor_lang::prelude::*; 7 | use dex::utils::validation::assert; 8 | use solana_program::{ 9 | entrypoint::ProgramResult, program_error::ProgramError, sysvar::clock::Clock, 10 | }; 11 | 12 | pub fn process( 13 | context: Context, 14 | params: InitializeDerivativeParams, 15 | ) -> ProgramResult { 16 | let accts = context.accounts; 17 | let mut derivative_metadata = accts.derivative_metadata.load_init()?; 18 | assert( 19 | !derivative_metadata.is_initialized(), 20 | DerivativeError::AccountAlreadyInitialized, 21 | )?; 22 | let clock: Clock = bincode::deserialize(&accts.clock.data.borrow()) 23 | .map_err(|_| ProgramError::InvalidArgument)?; 24 | assert( 25 | params.initialization_time >= clock.unix_timestamp, 26 | DerivativeError::InvalidCreationTime, 27 | )?; 28 | derivative_metadata.tag = AccountTag::DerivativeMetadata; 29 | 30 | match params.instrument_type { 31 | InstrumentType::ExpiringCall | InstrumentType::ExpiringPut => { 32 | assert( 33 | params.full_funding_period == params.minimum_funding_period, 34 | DerivativeError::InvalidSettlementTime, 35 | )?; 36 | } 37 | _ => {} 38 | } 39 | 40 | // Immutable fields 41 | derivative_metadata.bump = context.bumps["derivative_metadata"] as u64; 42 | derivative_metadata.instrument_type = params.instrument_type; 43 | derivative_metadata.strike = params.strike; 44 | derivative_metadata.initialization_time = params.initialization_time; 45 | derivative_metadata.full_funding_period = params.full_funding_period; 46 | derivative_metadata.minimum_funding_period = params.minimum_funding_period; 47 | derivative_metadata.close_authority = params.close_authority; 48 | derivative_metadata.market_product_group = *accts.market_product_group.key; 49 | derivative_metadata.price_oracle = *accts.price_oracle.key; 50 | derivative_metadata.clock = *accts.clock.key; 51 | derivative_metadata.oracle_type = params.oracle_type; 52 | // Mutable fields 53 | derivative_metadata.expired = ExpirationStatus::Active; 54 | derivative_metadata.last_funding_time = params.initialization_time; 55 | Ok(()) 56 | } 57 | -------------------------------------------------------------------------------- /programs/instruments/src/processor/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod close_derivative_account; 2 | pub mod initialize_derivative; 3 | pub mod settle_derivative; 4 | -------------------------------------------------------------------------------- /programs/instruments/src/state/constants.rs: -------------------------------------------------------------------------------- 1 | pub const MAX_DATES: usize = 32; 2 | -------------------------------------------------------------------------------- /programs/instruments/src/state/derivative_metadata.rs: -------------------------------------------------------------------------------- 1 | use crate::state::enums::{AccountTag, ExpirationStatus, InstrumentType, OracleType}; 2 | use anchor_lang::prelude::*; 3 | use dex::utils::numeric::Fractional; 4 | use solana_program::{clock::UnixTimestamp, program_error::ProgramError, pubkey::Pubkey}; 5 | 6 | #[account(zero_copy)] 7 | pub struct DerivativeMetadata { 8 | pub tag: AccountTag, 9 | pub expired: ExpirationStatus, 10 | pub oracle_type: OracleType, 11 | pub instrument_type: InstrumentType, 12 | pub bump: u64, 13 | pub strike: Fractional, 14 | pub initialization_time: UnixTimestamp, 15 | pub full_funding_period: UnixTimestamp, 16 | pub minimum_funding_period: UnixTimestamp, 17 | pub price_oracle: Pubkey, 18 | pub market_product_group: Pubkey, 19 | pub close_authority: Pubkey, 20 | pub clock: Pubkey, 21 | pub last_funding_time: UnixTimestamp, 22 | } 23 | 24 | impl DerivativeMetadata { 25 | pub fn get_key(&self, program_id: &Pubkey) -> std::result::Result { 26 | let seeds = &[ 27 | b"derivative", 28 | self.price_oracle.as_ref(), 29 | self.market_product_group.as_ref(), 30 | &(self.instrument_type as u64).to_le_bytes(), 31 | &self.strike.m.to_le_bytes(), 32 | &self.strike.exp.to_le_bytes(), 33 | &self.initialization_time.to_le_bytes(), 34 | &self.full_funding_period.to_le_bytes(), 35 | &self.minimum_funding_period.to_le_bytes(), 36 | &[self.bump as u8], 37 | ]; 38 | Ok(Pubkey::create_program_address(seeds, program_id)?) 39 | } 40 | 41 | pub fn is_initialized(&self) -> bool { 42 | self.tag == AccountTag::DerivativeMetadata && self.expired == ExpirationStatus::Active 43 | } 44 | 45 | pub fn expired(&self) -> bool { 46 | self.expired == ExpirationStatus::Expired 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /programs/instruments/src/state/enums.rs: -------------------------------------------------------------------------------- 1 | use borsh::{BorshDeserialize, BorshSerialize}; 2 | use bytemuck::{Pod, Zeroable}; 3 | use dex::error::UtilError; 4 | 5 | #[derive(Copy, Clone, Debug, PartialEq)] 6 | #[repr(u64)] 7 | pub enum AccountTag { 8 | Uninitialized, 9 | DerivativeMetadata, 10 | FixedIncomeMetadata, 11 | } 12 | impl Default for AccountTag { 13 | fn default() -> Self { 14 | AccountTag::Uninitialized 15 | } 16 | } 17 | unsafe impl Zeroable for AccountTag {} 18 | unsafe impl Pod for AccountTag {} 19 | 20 | #[derive(BorshSerialize, BorshDeserialize, Copy, Debug, Clone, PartialEq)] 21 | #[repr(u64)] 22 | pub enum InstrumentType { 23 | Uninitialized, 24 | RecurringCall, 25 | RecurringPut, 26 | ExpiringCall, 27 | ExpiringPut, 28 | } 29 | impl Default for InstrumentType { 30 | fn default() -> Self { 31 | InstrumentType::Uninitialized 32 | } 33 | } 34 | unsafe impl Zeroable for InstrumentType {} 35 | unsafe impl Pod for InstrumentType {} 36 | 37 | impl InstrumentType { 38 | pub fn is_recurring(&self) -> std::result::Result { 39 | match self { 40 | InstrumentType::RecurringCall | InstrumentType::RecurringPut => Ok(true), 41 | InstrumentType::ExpiringCall | InstrumentType::ExpiringPut => Ok(false), 42 | InstrumentType::Uninitialized => Err(UtilError::AccountUninitialized), 43 | } 44 | } 45 | } 46 | 47 | #[derive(BorshSerialize, BorshDeserialize, Copy, Debug, Clone, PartialEq)] 48 | #[repr(u64)] 49 | pub enum OracleType { 50 | Uninitialized, 51 | Pyth, 52 | Dummy, 53 | } 54 | impl Default for OracleType { 55 | fn default() -> Self { 56 | OracleType::Uninitialized 57 | } 58 | } 59 | unsafe impl Zeroable for OracleType {} 60 | unsafe impl Pod for OracleType {} 61 | 62 | #[derive(Copy, Clone, Debug, PartialEq)] 63 | #[repr(u64)] 64 | pub enum ExpirationStatus { 65 | Active, 66 | Expired, 67 | } 68 | impl Default for ExpirationStatus { 69 | fn default() -> Self { 70 | ExpirationStatus::Active 71 | } 72 | } 73 | unsafe impl Zeroable for ExpirationStatus {} 74 | unsafe impl Pod for ExpirationStatus {} 75 | -------------------------------------------------------------------------------- /programs/instruments/src/state/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod constants; 2 | pub mod derivative_metadata; 3 | pub mod enums; 4 | -------------------------------------------------------------------------------- /programs/risk/alpha-risk-engine/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "alpha-risk-engine" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [features] 7 | no-entrypoint = [] 8 | test-bpf = [] 9 | 10 | [dependencies] 11 | agnostic-orderbook = { version = "0.1.0", path = "../../agnostic-orderbook/program", features = ["no-entrypoint"] } 12 | anchor-lang = "0.24.2" 13 | dex = { path = "../../dex", version = "0.1.0", features = ["no-entrypoint"]} 14 | solana-program = "1.8.12" 15 | thiserror = "1.0" 16 | arrayref = "0.3.6" 17 | borsh = "0.9" 18 | 19 | [lib] 20 | crate-type = ["cdylib", "lib"] 21 | -------------------------------------------------------------------------------- /programs/risk/noop-risk-engine/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "noop-risk-engine" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [features] 7 | no-entrypoint = [] 8 | cpi = ["no-entrypoint"] 9 | test-bpf = [] 10 | 11 | [dependencies] 12 | dex = {path = "../../dex", features = ["no-entrypoint"]} 13 | anchor-lang = "0.24.2" 14 | anchor-spl = "0.24.2" 15 | solana-program = "1.8.12" 16 | thiserror = "1.0" 17 | arrayref = "0.3.6" 18 | borsh = "0.9" 19 | 20 | [dev-dependencies] 21 | anchor-client = "0.24.2" 22 | 23 | 24 | [lib] 25 | crate-type = ["cdylib", "lib"] 26 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | START_DIR=$(pwd) 3 | ROOT=$(git rev-parse --show-toplevel) 4 | cd $ROOT/programs/dex 5 | 6 | RUST_LOG= cargo test-bpf 7 | cd $START_DIR -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "types": ["mocha", "chai"], 4 | "typeRoots": ["./node_modules/@types"], 5 | "lib": ["es2015"], 6 | "module": "commonjs", 7 | "target": "es6", 8 | "esModuleInterop": true 9 | } 10 | } 11 | --------------------------------------------------------------------------------