├── .eslintrc.js ├── .gitignore ├── .husky └── pre-commit ├── .pre-commit-config.yaml ├── .prettierignore ├── .prettierrc.js ├── Anchor.toml ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── admin ├── README.md ├── add_prices_to_ladder.ts ├── client.ts ├── create_market.ts ├── create_order.ts ├── get_all.ts ├── market_operator.ts ├── market_types.ts ├── orders.ts ├── price_ladders.ts ├── print_market.ts ├── product.ts ├── update_market_status.ts └── util.ts ├── audit └── sec3 │ ├── 0.10.0.pdf │ ├── 0.10.1.pdf │ ├── 0.11.0.pdf │ ├── 0.12.0.pdf │ ├── 0.12.1.pdf │ ├── 0.13.0.pdf │ ├── 0.14.0.pdf │ ├── 0.14.1.pdf │ ├── 0.14.2.pdf │ ├── 0.15.0.pdf │ ├── 0.15.1.pdf │ ├── 0.15.2.pdf │ ├── 0.15.3.pdf │ ├── 0.15.4.pdf │ ├── 0.15.5.pdf │ ├── 0.5.0.pdf │ ├── 0.6.0.pdf │ ├── 0.7.0.pdf │ ├── 0.8.0.pdf │ └── 0.9.0.pdf ├── babel.config.js ├── ci ├── build_manager │ ├── build_and_test.sh │ ├── download_artifact.sh │ ├── generate_build_name.sh │ ├── save_build_artifacts.sh │ └── upload_build_artifacts.sh ├── deploy_manager │ ├── deploy_program.sh │ ├── devnet_history │ │ ├── archive │ │ │ └── monaco_protocol.json │ │ ├── dev.json │ │ └── stable.json │ ├── get_last_deploy.sh │ ├── get_program_data.sh │ ├── initial_deploy.sh │ ├── initial_idl.sh │ ├── mainnet_history │ │ └── monaco_protocol.json │ ├── program_data.json │ ├── testnet_history │ │ └── monaco_protocol.json │ ├── update_history.sh │ └── update_idl.sh ├── security_manager │ ├── authority_check.sh │ ├── verify_program.sh │ ├── verify_program_checksum_check.sh │ └── verify_program_get_assets.sh ├── version_manager │ ├── bump_client_version.sh │ ├── check_deploy_status.sh │ ├── get_latest_version.sh │ ├── get_toml_version.sh │ ├── update_version_info.sh │ └── version_history │ │ ├── market.json │ │ └── matchmaker.json └── wallet_manager │ ├── decrypt_wallet.sh │ ├── decrypt_wallet_cleanup.sh │ ├── encrypt_wallet.sh │ ├── set_keypair.sh │ ├── update_wallet_balance.sh │ └── wallet.json.gpg ├── clippy.toml ├── jest.config.js ├── migrations └── deploy.ts ├── npm-admin-client ├── README.md ├── docs │ ├── endpoints │ │ ├── market_create.md │ │ ├── market_helpers.md │ │ ├── market_management.md │ │ ├── market_outcome.md │ │ ├── market_outcome_prices.md │ │ ├── market_type_create.md │ │ ├── market_validate.md │ │ ├── operators.md │ │ ├── price_ladder.md │ │ └── utils.md │ └── types │ │ ├── client.md │ │ ├── default_price_ladder.md │ │ ├── market_outcomes.md │ │ ├── market_type.md │ │ ├── markets.md │ │ └── operator.md ├── generate_docs.sh ├── package-lock.json ├── package.json ├── src │ ├── index.ts │ ├── market_create.ts │ ├── market_create_instruction.ts │ ├── market_helpers.ts │ ├── market_management.ts │ ├── market_management_instructions.ts │ ├── market_outcome.ts │ ├── market_outcome_instruction.ts │ ├── market_outcome_prices.ts │ ├── market_type_create.ts │ ├── market_validate.ts │ ├── operators.ts │ ├── price_ladder.ts │ └── utils.ts ├── tsconfig.json └── types │ ├── account.ts │ ├── client.ts │ ├── default_price_ladder.ts │ ├── index.ts │ ├── market_outcomes.ts │ ├── market_type.ts │ ├── markets.ts │ ├── operator.ts │ └── transactions.ts ├── npm-client ├── README.md ├── docs │ ├── endpoints │ │ ├── cancel_order.md │ │ ├── cancel_order_instruction.md │ │ ├── create_order.md │ │ ├── create_order_instruction.md │ │ ├── market_matching_pool_query.md │ │ ├── market_matching_pools.md │ │ ├── market_outcome_query.md │ │ ├── market_outcomes.md │ │ ├── market_position.md │ │ ├── market_position_query.md │ │ ├── market_prices.md │ │ ├── market_query.md │ │ ├── markets.md │ │ ├── order.md │ │ ├── order_query.md │ │ ├── product.md │ │ ├── product_query.md │ │ ├── queries │ │ │ └── account_query.md │ │ ├── trade.md │ │ ├── trade_query.md │ │ ├── utils.md │ │ └── wallet_tokens.md │ └── types │ │ ├── account_query.md │ │ ├── client.md │ │ ├── default_price_ladder.md │ │ ├── errors.md │ │ ├── get_account.md │ │ ├── market.md │ │ ├── market_position.md │ │ ├── matching_pool.md │ │ ├── order.md │ │ ├── product.md │ │ ├── trade.md │ │ ├── transactions.md │ │ └── wallet_tokens.md ├── generate_docs.sh ├── package-lock.json ├── package.json ├── src │ ├── cancel_order.ts │ ├── cancel_order_instruction.ts │ ├── create_order.ts │ ├── create_order_instruction.ts │ ├── index.ts │ ├── market_commission_payment_queues.ts │ ├── market_liquidities.ts │ ├── market_matching_pool_query.ts │ ├── market_matching_pools.ts │ ├── market_matching_queues.ts │ ├── market_order_request_queues.ts │ ├── market_outcome_query.ts │ ├── market_outcomes.ts │ ├── market_position.ts │ ├── market_position_query.ts │ ├── market_prices.ts │ ├── market_query.ts │ ├── markets.ts │ ├── order.ts │ ├── order_query.ts │ ├── product.ts │ ├── product_query.ts │ ├── queries │ │ ├── account_query.ts │ │ └── filtering.ts │ ├── trade.ts │ ├── trade_query.ts │ ├── utils.ts │ └── wallet_tokens.ts ├── tsconfig.json └── types │ ├── account_query.ts │ ├── client.ts │ ├── default_price_ladder.ts │ ├── errors.ts │ ├── get_account.ts │ ├── index.ts │ ├── market.ts │ ├── market_commission_payment_queue.ts │ ├── market_liquidities.ts │ ├── market_matching_queue.ts │ ├── market_order_request_queue.ts │ ├── market_position.ts │ ├── order.ts │ ├── product.ts │ ├── trade.ts │ ├── transactions.ts │ └── wallet_tokens.ts ├── package.json ├── programs └── monaco_protocol │ ├── Cargo.toml │ ├── Xargo.toml │ └── src │ ├── context.rs │ ├── error.rs │ ├── events │ ├── mod.rs │ └── trade.rs │ ├── instructions │ ├── clock.rs │ ├── close.rs │ ├── market │ │ ├── create_market.rs │ │ ├── market_authority.rs │ │ ├── market_token_accounts.rs │ │ ├── mod.rs │ │ ├── move_to_inplay.rs │ │ ├── update_market_event_start_time.rs │ │ ├── update_market_locktime.rs │ │ ├── update_market_status.rs │ │ └── update_market_title.rs │ ├── market_liquidities │ │ ├── mod.rs │ │ └── update_market_liquidities_with_cross_liquidity.rs │ ├── market_position │ │ ├── create_market_position.rs │ │ ├── mod.rs │ │ ├── settle_market_position.rs │ │ ├── update_on_order_cancellation.rs │ │ ├── update_on_order_match.rs │ │ ├── update_on_order_request_creation.rs │ │ ├── update_product_commission_contributions.rs │ │ └── void_market_position.rs │ ├── market_type │ │ ├── create_market_type.rs │ │ └── mod.rs │ ├── matching │ │ ├── create_trade.rs │ │ ├── matching_one_to_one.rs │ │ ├── matching_pool.rs │ │ ├── mod.rs │ │ ├── on_order_creation.rs │ │ └── on_order_match.rs │ ├── math.rs │ ├── mod.rs │ ├── operator.rs │ ├── order │ │ ├── cancel_order.rs │ │ ├── cancel_order_post_market_lock.rs │ │ ├── cancel_preplay_order_post_event_start.rs │ │ ├── create_order.rs │ │ ├── match_order.rs │ │ ├── mod.rs │ │ ├── settle_order.rs │ │ └── void_order.rs │ ├── order_request │ │ ├── create_order_request.rs │ │ ├── dequeue_order_request.rs │ │ ├── mod.rs │ │ └── process_order_request.rs │ ├── payment.rs │ ├── price_ladder │ │ ├── add_prices_to_price_ladder.rs │ │ ├── create_price_ladder.rs │ │ ├── increase_price_ladder_size.rs │ │ └── mod.rs │ └── transfer.rs │ ├── lib.rs │ └── state │ ├── market_account.rs │ ├── market_liquidities.rs │ ├── market_matching_pool_account.rs │ ├── market_matching_queue_account.rs │ ├── market_order_request_queue.rs │ ├── market_outcome_account.rs │ ├── market_position_account.rs │ ├── market_type.rs │ ├── mod.rs │ ├── operator_account.rs │ ├── order_account.rs │ ├── payments_queue.rs │ ├── price_ladder.rs │ ├── trade_account.rs │ └── type_size.rs ├── tests ├── anchor │ └── protocol_product │ │ ├── protocol_product.json │ │ ├── protocol_product.so │ │ └── protocol_product.ts ├── end-to-end │ └── inplay_market.ts ├── market │ ├── create_market.ts │ ├── force_void_market.ts │ ├── initialize_market_outcome.ts │ ├── recreate_market.ts │ ├── update_market_event_start_time.ts │ ├── update_market_locktime.ts │ ├── update_market_status.ts │ └── update_market_title.ts ├── market_type │ └── create_market_type.ts ├── npm-admin-client │ ├── market_create.ts │ ├── market_management.ts │ ├── market_outcome.ts │ ├── market_outcome_prices.ts │ ├── market_recreate.ts │ ├── market_validate.ts │ └── operators.ts ├── npm-client │ ├── batch_sign_and_send_instructions.ts │ ├── cancel_order.ts │ ├── create_order.ts │ ├── market_commission_payment_queue.ts │ ├── market_liquidities.ts │ ├── market_matching_pool.ts │ ├── market_matching_pool_query.ts │ ├── market_matching_queue.ts │ ├── market_order_request_queue.ts │ ├── market_outcome.ts │ ├── market_position.ts │ ├── market_position_query.ts │ ├── market_prices.ts │ ├── market_query.ts │ ├── multiple_order_query.ts │ ├── order_query.ts │ ├── orders.ts │ ├── product.ts │ ├── product_query.ts │ ├── stake.ts │ ├── trade_query.ts │ └── wallet_tokens.ts ├── order │ ├── cancelation_payment_10.ts │ ├── cancelation_payment_11.ts │ ├── cancelation_payment_12.ts │ ├── creation_payment_1.ts │ ├── creation_payment_2.ts │ ├── creation_payment_3.ts │ ├── matching_orders_01.ts │ ├── matching_orders_02.ts │ ├── matching_orders_03.ts │ ├── matching_refunds_1.ts │ ├── settlement_payment_1.ts │ ├── settlement_payment_10.ts │ ├── settlement_payment_11.ts │ ├── settlement_payment_2.ts │ ├── settlement_payment_3.ts │ ├── settlement_payment_4.ts │ ├── settlement_payment_5.ts │ ├── void_payment_01.ts │ ├── wholesale_payment_01.ts │ ├── wholesale_payment_02.ts │ ├── wholesale_payment_03.ts │ ├── wholesale_payment_04.ts │ └── wholesale_payment_05.ts ├── orderRequest │ ├── createOrderRequest.ts │ ├── dequeueOrderRequest.ts │ └── processOrderRequest.ts ├── priceLadder │ └── priceLadder.ts ├── protocol │ ├── cancel_order.ts │ ├── cancel_order_post_market_lock.ts │ ├── cancel_preplay_order_post_event_start.ts │ ├── close_market_matching_pool.ts │ ├── close_market_outcome.ts │ ├── close_market_position.ts │ ├── close_market_settlement.ts │ ├── close_market_voided.ts │ ├── close_order.ts │ ├── close_trade.ts │ ├── crank.ts │ ├── crank_matching.ts │ ├── crank_settlement.ts │ ├── create_order.ts │ ├── create_order_request.ts │ ├── matching_v1_vs_v2.ts │ ├── move_market_matching_pool_to_inplay.ts │ ├── process_order_match.ts │ ├── product_commission_matching.ts │ ├── product_commission_settlement.ts │ ├── settle_bet_order.ts │ ├── settle_market.ts │ ├── update_market_liquidities_with_cross_liquidity.ts │ └── void_order.ts ├── setup.ts └── util │ ├── pdas.ts │ ├── test_util.ts │ └── wrappers.ts ├── tsconfig.json └── yarn.lock /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | node: true, 4 | es2021: true, 5 | }, 6 | parser: "@typescript-eslint/parser", 7 | parserOptions: { 8 | ecmaVersion: "latest", 9 | sourceType: "module", 10 | }, 11 | extends: [ 12 | "eslint:recommended", 13 | "plugin:@typescript-eslint/recommended", 14 | "plugin:@typescript-eslint/eslint-recommended", 15 | "prettier", 16 | ], 17 | rules: { 18 | "prettier/prettier": "error", 19 | "jest/no-focused-tests": "error", 20 | "@typescript-eslint/no-unused-vars": [ 21 | "error", 22 | { 23 | varsIgnorePattern: "^_", 24 | argsIgnorePattern: "^_", 25 | }, 26 | ], 27 | }, 28 | plugins: ["@typescript-eslint", "prettier", "jest"], 29 | }; 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .anchor 3 | .DS_Store 4 | target 5 | bin 6 | **/*.rs.bk 7 | node_modules 8 | tmp 9 | test_log 10 | build_log 11 | 12 | test-ledger/ 13 | wallet.json 14 | 15 | lib-cov 16 | *.seed 17 | *.log 18 | *.csv 19 | *.dat 20 | *.out 21 | *.pid 22 | *.gz 23 | *.swp 24 | 25 | pids 26 | logs 27 | results 28 | tmp 29 | 30 | # Build 31 | public/css/main.css 32 | 33 | # Coverage reports 34 | coverage 35 | 36 | # API keys and secrets 37 | .env 38 | 39 | # Dependency directory 40 | node_modules 41 | bower_components 42 | 43 | # Editors 44 | .idea 45 | *.iml 46 | .project 47 | .classpath 48 | 49 | # OS metadata 50 | .DS_Store 51 | Thumbs.db 52 | 53 | # Ignore built ts files 54 | crank/dist/**/* 55 | 56 | crank/**/*.js 57 | admin/**/*.js 58 | migrations/**/*.js 59 | 60 | # npm package 61 | npm-client/**/*.js 62 | npm-client/**/*.d.ts 63 | 64 | # npm package 65 | npm-admin-client/**/*.js 66 | npm-admin-client/**/*.d.ts 67 | 68 | .eslintcache 69 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx lint-staged 5 | pre-commit run 6 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v2.3.0 4 | hooks: 5 | - id: check-yaml 6 | - id: end-of-file-fixer 7 | - id: trailing-whitespace 8 | - repo: https://github.com/doublify/pre-commit-rust 9 | rev: v1.0 10 | hooks: 11 | - id: fmt 12 | - id: cargo-check 13 | - repo: https://github.com/doublify/pre-commit-rust 14 | rev: v1.0 15 | hooks: 16 | - id: clippy 17 | args: ["--", "-D", "warnings", "-A", "clippy::result_large_err"] 18 | - repo: local 19 | hooks: 20 | - id: generate-admin-client-docs 21 | name: generate-admin-client-docs 22 | entry: npm-admin-client/generate_docs.sh 23 | language: script 24 | files: ^npm-admin-client/ 25 | pass_filenames: true 26 | - id: generate-client-docs 27 | name: generate-client-docs 28 | entry: npm-client/generate_docs.sh 29 | language: script 30 | files: ^npm-client/ 31 | pass_filenames: true 32 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # ignore all 2 | /* 3 | 4 | # except 5 | !/npm-client 6 | !/npm-admin-client 7 | !/admin 8 | !/tests 9 | !/migrations 10 | 11 | # ignore 12 | /**/package-lock.json 13 | /*.md 14 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | semi: true, 3 | trailingComma: "all", 4 | singleQuote: false, 5 | tabWidth: 2, 6 | }; 7 | -------------------------------------------------------------------------------- /Anchor.toml: -------------------------------------------------------------------------------- 1 | [programs.localnet] 2 | monaco_protocol = "monacoUXKtUi6vKsQwaLyxmXKSievfNWEcYXTgkbCih" 3 | 4 | [registry] 5 | url = "https://anchor.projectserum.com" 6 | 7 | [provider] 8 | cluster = "localnet" 9 | wallet = "~/.config/solana/id.json" 10 | 11 | [scripts] 12 | test = "yarn runJestTests" 13 | 14 | [[test.genesis]] 15 | address = "mppFrYmM6A4Ud3AxRbGXsGisX1HUsbDfp1nrg9FQJEE" 16 | program = "tests/anchor/protocol_product/protocol_product.so" 17 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "programs/*" 4 | ] 5 | 6 | [profile.dev] 7 | overflow-checks = true 8 | 9 | [profile.release] 10 | overflow-checks = true 11 | -------------------------------------------------------------------------------- /admin/README.md: -------------------------------------------------------------------------------- 1 | # Admin Scripts 2 | 3 | Admin function can be performed via `yarn run admin_function` you can check these admin scripts in [package.json](/package.json). To perform any functions, the first thing required is to export: 4 | 5 | ``` 6 | export ANCHOR_WALLET=path/to/wallet.json 7 | export ANCHOR_PROVIDER_URL=[https://](https://api..solana.com) 8 | ``` 9 | 10 | Replace solana env with the [solana cluster](https://docs.solana.com/clusters) you want to work against. 11 | 12 | If you want to perform market or cranking actions, you will need to authorise your wallet using (ensure your wallet has some SOL too): 13 | 14 | ``` 15 | yarn run authoriseOperator 16 | ``` 17 | 18 | You are then set up to perform all admin functions. You can inspect the admin scripts to discover the args required, though they should error and provide information if you try to run them without the correct args. 19 | -------------------------------------------------------------------------------- /admin/add_prices_to_ladder.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey, SystemProgram } from "@solana/web3.js"; 2 | import { Program } from "@coral-xyz/anchor"; 3 | import { 4 | findMarketOutcomePda, 5 | getAnchorProvider, 6 | getProtocolProgram, 7 | } from "./util"; 8 | import { 9 | findAuthorisedOperatorsAccountPda, 10 | Operator, 11 | } from "../npm-admin-client/src"; 12 | 13 | export async function addPricesToLadder() { 14 | const protocolProgram = await getProtocolProgram(); 15 | if (process.argv.length != 5) { 16 | console.log( 17 | "Usage: yarn run addPricesToLadder [,...]", 18 | ); 19 | process.exit(1); 20 | } 21 | 22 | const marketPda = new PublicKey(process.argv[3]); 23 | const pricesToAdd = JSON.parse(process.argv[4]); 24 | 25 | const market = await protocolProgram.account.market.fetch(marketPda); 26 | const authorisedOperators = await findAuthorisedOperatorsAccountPda( 27 | protocolProgram as Program, 28 | Operator.MARKET, 29 | ); 30 | 31 | Array.from(new Array(market.marketOutcomesCount), (_, i) => i).forEach( 32 | async (marketOutcomeIndex) => { 33 | const marketOutcomePda = await findMarketOutcomePda( 34 | marketPda, 35 | marketOutcomeIndex, 36 | protocolProgram, 37 | ); 38 | await protocolProgram.methods 39 | .addPricesToMarketOutcome(marketOutcomeIndex, pricesToAdd) 40 | .accounts({ 41 | systemProgram: SystemProgram.programId, 42 | outcome: marketOutcomePda, 43 | market: marketPda, 44 | marketOperator: getAnchorProvider().wallet.publicKey, 45 | authorisedOperators: authorisedOperators.data.pda, 46 | }) 47 | .rpc(); 48 | }, 49 | ); 50 | } 51 | -------------------------------------------------------------------------------- /admin/create_market.ts: -------------------------------------------------------------------------------- 1 | import { Keypair, PublicKey } from "@solana/web3.js"; 2 | import { Program } from "@coral-xyz/anchor"; 3 | import { 4 | createMarketWithOutcomesAndPriceLadder as npmCreateMarket, 5 | MarketOrderBehaviourValue, 6 | } from "../npm-admin-client/src/"; 7 | import { getProtocolProgram } from "./util"; 8 | import { Markets, MarketStatusFilter } from "../npm-client"; 9 | 10 | /** 11 | * Example create market script - parameters used for market creation might be need to replaced/created before use 12 | */ 13 | export async function create_market() { 14 | const protocolProgram = await getProtocolProgram(); 15 | const marketTokenString = 16 | process.argv.length > 3 17 | ? process.argv[3] 18 | : "2QqxXa2aNCx3DLQCHgiC4P7Xfbe3B4bULM5eKpyAirGY"; 19 | const priceLadderString = 20 | process.argv.length > 4 21 | ? process.argv[4] 22 | : "94VCY4rWi3nvyNPHnsRV65n3JZxiPSvXbxfvJydYw9uA"; 23 | 24 | const marketTokenPk = new PublicKey(marketTokenString); 25 | const priceLadderPk = new PublicKey(priceLadderString); 26 | 27 | const eventAccountKeyPair = Keypair.generate(); 28 | 29 | const createMarketResponse = await npmCreateMarket( 30 | protocolProgram as Program, 31 | "Aduana Stars-Bechem United", 32 | "TEST", 33 | marketTokenPk, 34 | 1924254038, 35 | eventAccountKeyPair.publicKey, 36 | ["Aduana Stars", "Draw", "Bechem United"], 37 | priceLadderPk, 38 | { 39 | eventStartOrderBehaviour: MarketOrderBehaviourValue.cancelUnmatched, 40 | marketLockOrderBehaviour: MarketOrderBehaviourValue.cancelUnmatched, 41 | batchSize: 20, 42 | }, 43 | ); 44 | 45 | if (createMarketResponse.success) { 46 | console.log(JSON.stringify(createMarketResponse.data.marketPk)); 47 | console.log(JSON.stringify(createMarketResponse.data.market, null, 2)); 48 | } else { 49 | console.log("Market Creation Failure"); 50 | console.log(JSON.stringify(createMarketResponse.errors, null, 2)); 51 | } 52 | } 53 | 54 | export async function getMarketsByStatus() { 55 | const program = await getProtocolProgram(); 56 | const query = Markets.marketQuery(program); 57 | const result = { totals: {}, pks: {} }; 58 | let total = 0; 59 | for (const status in MarketStatusFilter) { 60 | if (!isNaN(parseInt(status))) continue; 61 | const marketPksWithStatus = ( 62 | await query 63 | .filterByStatus( 64 | MarketStatusFilter[status as keyof typeof MarketStatusFilter], 65 | ) 66 | .fetchPublicKeys() 67 | ).data.publicKeys; 68 | result.totals[status] = marketPksWithStatus.length; 69 | result.pks[status] = marketPksWithStatus; 70 | total += result.totals[status]; 71 | } 72 | result.totals["total"] = total; 73 | console.log(JSON.stringify(result, null, 2)); 74 | } 75 | -------------------------------------------------------------------------------- /admin/create_order.ts: -------------------------------------------------------------------------------- 1 | import { createOrderUiStake } from "../npm-client/src/create_order"; 2 | import { PublicKey } from "@solana/web3.js"; 3 | import { getProtocolProgram } from "./util"; 4 | import { findMarketOutcomePda } from "../npm-admin-client"; 5 | import { MarketOutcomeAccount } from "../npm-client"; 6 | 7 | // yarn run create_order 8 | // or tsc; ANCHOR_WALLET=~/.config/solana/id.json yarn ts-node client.ts create_order 9 | 10 | export async function create_order() { 11 | if (process.argv.length != 8) { 12 | console.log( 13 | "Usage: yarn run create_order ", 14 | ); 15 | process.exit(1); 16 | } 17 | 18 | const marketPk = new PublicKey(process.argv[3]); 19 | const marketOutcomeIndex = parseInt(process.argv[4], 10); 20 | const forOutcome = process.argv[5] == "true"; 21 | const price = parseFloat(process.argv[6]); 22 | const stake = parseFloat(process.argv[7]); 23 | 24 | const protocolProgram = await getProtocolProgram(); 25 | 26 | const outcome = (await protocolProgram.account.marketOutcome.fetch( 27 | ( 28 | await findMarketOutcomePda(protocolProgram, marketPk, marketOutcomeIndex) 29 | ).data.pda, 30 | )) as MarketOutcomeAccount; 31 | 32 | const result = await createOrderUiStake( 33 | protocolProgram, 34 | marketPk, 35 | marketOutcomeIndex, 36 | forOutcome, 37 | price, 38 | stake, 39 | outcome.prices, 40 | ); 41 | console.log(JSON.stringify(result, null, 2)); 42 | } 43 | -------------------------------------------------------------------------------- /admin/get_all.ts: -------------------------------------------------------------------------------- 1 | import { BorshAccountsCoder } from "@coral-xyz/anchor"; 2 | import bs58 from "bs58"; 3 | import { getAnchorProvider, getProtocolProgram } from "./util"; 4 | 5 | export async function getAllMarkets() { 6 | await _getAllByDiscriminator("market"); 7 | } 8 | 9 | export async function getAllOrders() { 10 | await _getAllByDiscriminator("order"); 11 | } 12 | 13 | export async function getAll() { 14 | if (process.argv.length != 4) { 15 | console.log("Usage: yarn run getAll "); 16 | process.exit(1); 17 | } 18 | 19 | await _getAllByDiscriminator(process.argv[3]); 20 | } 21 | 22 | async function _getAllByDiscriminator(accountDiscriminator: string) { 23 | const program = await getProtocolProgram(); 24 | getAnchorProvider() 25 | .connection.getProgramAccounts(program.programId, { 26 | dataSlice: { offset: 0, length: 0 }, // fetch without any data. 27 | filters: [ 28 | { 29 | memcmp: { 30 | offset: 0, 31 | bytes: bs58.encode( 32 | BorshAccountsCoder.accountDiscriminator(accountDiscriminator), 33 | ), 34 | }, 35 | }, 36 | ], 37 | }) 38 | .then( 39 | (accounts) => { 40 | const accountPKs = accounts.map((account) => account.pubkey.toBase58()); 41 | console.log(JSON.stringify(accountPKs)); 42 | }, 43 | (reason) => console.log(reason), 44 | ); 45 | } 46 | -------------------------------------------------------------------------------- /admin/market_operator.ts: -------------------------------------------------------------------------------- 1 | import { 2 | authoriseAdminOperator as clientAuthoriseAdminOperator, 3 | authoriseCrankOperator, 4 | authoriseMarketOperator, 5 | findAuthorisedOperatorsAccountPda, 6 | Operator, 7 | } from "../npm-admin-client/src"; 8 | import { getProtocolProgram } from "./util"; 9 | import { PublicKey } from "@solana/web3.js"; 10 | 11 | export async function authoriseOperator() { 12 | if (process.argv.length != 5) { 13 | console.log( 14 | "Usage: yarn run authorise_operator ", 15 | ); 16 | process.exit(1); 17 | } 18 | 19 | const operatorType = process.argv[3].toUpperCase(); 20 | if (operatorType != "CRANK" && operatorType != "MARKET") { 21 | console.log("Operator type must be one of CRANK or MARKET."); 22 | process.exit(1); 23 | } 24 | const operator = process.argv[4]; 25 | const protocolProgram = await getProtocolProgram(); 26 | const operatorPk = new PublicKey(operator); 27 | 28 | if (operatorType == "CRANK") { 29 | authoriseCrankOperator(protocolProgram, operatorPk); 30 | } else { 31 | authoriseMarketOperator(protocolProgram, operatorPk); 32 | } 33 | } 34 | 35 | export async function authoriseAdminOperator() { 36 | if (process.argv.length != 4) { 37 | console.log("Usage: yarn run authorise_admin_operator "); 38 | process.exit(1); 39 | } 40 | 41 | const operator = process.argv[3]; 42 | const operatorPk = new PublicKey(operator); 43 | const protocolProgram = await getProtocolProgram(); 44 | await clientAuthoriseAdminOperator(protocolProgram, operatorPk); 45 | } 46 | 47 | export async function printAuthorisedOperatorAccounts() { 48 | const program = await getProtocolProgram(); 49 | const [admin, market, crank] = ( 50 | await Promise.all([ 51 | findAuthorisedOperatorsAccountPda(program, Operator.ADMIN), 52 | findAuthorisedOperatorsAccountPda(program, Operator.MARKET), 53 | findAuthorisedOperatorsAccountPda(program, Operator.CRANK), 54 | ]) 55 | ).map((response) => response.data.pda); 56 | console.log(`Admin authorised operators account: ${admin}`); 57 | console.log(`Market authorised operators account: ${market}`); 58 | console.log(`Crank authorised operators account: ${crank}`); 59 | } 60 | -------------------------------------------------------------------------------- /admin/market_types.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey } from "@solana/web3.js"; 2 | import { Program } from "@coral-xyz/anchor"; 3 | import { 4 | findMarketTypePda, 5 | getOrCreateMarketType, 6 | } from "../npm-admin-client/src/"; 7 | import { getProtocolProgram } from "./util"; 8 | 9 | export async function createMarketType() { 10 | if (process.argv.length != 4) { 11 | console.log("Usage: yarn run createMarketType "); 12 | process.exit(1); 13 | } 14 | 15 | const protocolProgram = await getProtocolProgram(); 16 | const response = await getOrCreateMarketType( 17 | protocolProgram as Program, 18 | process.argv[3], 19 | ); 20 | console.log(JSON.stringify(response, null, 2)); 21 | } 22 | 23 | export async function printAllMarketTypes() { 24 | const protocolProgram = await getProtocolProgram(); 25 | const marketTypes = await protocolProgram.account.marketType.all(); 26 | console.log(JSON.stringify(marketTypes, null, 2)); 27 | } 28 | 29 | export async function printMarketTypeByName() { 30 | if (process.argv.length != 4) { 31 | console.log("Usage: yarn run printMarketTypeByName "); 32 | process.exit(1); 33 | } 34 | const protocolProgram = await getProtocolProgram(); 35 | const publicKey = findMarketTypePda(protocolProgram, process.argv[3]).data 36 | .pda; 37 | const marketType = await protocolProgram.account.marketType.fetch(publicKey); 38 | console.log(JSON.stringify(marketType, null, 2)); 39 | } 40 | 41 | export async function printMarketType() { 42 | if (process.argv.length != 4) { 43 | console.log("Usage: yarn run printMarketType
"); 44 | process.exit(1); 45 | } 46 | const protocolProgram = await getProtocolProgram(); 47 | const publicKey = new PublicKey(process.argv[3]); 48 | const marketType = await protocolProgram.account.marketType.fetch(publicKey); 49 | console.log(JSON.stringify(marketType, null, 2)); 50 | } 51 | -------------------------------------------------------------------------------- /admin/orders.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey } from "@solana/web3.js"; 2 | import { getProtocolProgram } from "./util"; 3 | 4 | export function print_order() { 5 | if (process.argv.length != 4) { 6 | console.log("Usage: yarn run printOrder
"); 7 | process.exit(1); 8 | } 9 | 10 | const orderPK = new PublicKey(process.argv[3]); 11 | get_order(orderPK).then( 12 | (order) => console.log(JSON.stringify(order)), 13 | (reason) => console.log(reason), 14 | ); 15 | } 16 | 17 | async function get_order(orderPK: PublicKey) { 18 | const program = await getProtocolProgram(); 19 | return await program.account.order.fetch(orderPK); 20 | } 21 | -------------------------------------------------------------------------------- /admin/price_ladders.ts: -------------------------------------------------------------------------------- 1 | import { 2 | createPriceLadderWithPrices, 3 | findPriceLadderPda, 4 | } from "../npm-admin-client/src/"; 5 | import { getProtocolProgram } from "./util"; 6 | 7 | export async function createPriceLadder() { 8 | if (process.argv.length != 5) { 9 | console.log( 10 | "Usage: yarn run createPriceLadder ", 11 | ); 12 | process.exit(1); 13 | } 14 | 15 | const distinctSeed = process.argv[3]; 16 | const prices = JSON.parse(process.argv[4]); 17 | 18 | const protocolProgram = await getProtocolProgram(); 19 | const priceLadderPk = findPriceLadderPda(protocolProgram, distinctSeed).data 20 | .pda; 21 | 22 | const response = await createPriceLadderWithPrices( 23 | protocolProgram, 24 | priceLadderPk, 25 | distinctSeed, 26 | prices, 27 | ); 28 | if (!response.success) { 29 | throw response.errors[0]; 30 | } 31 | console.log(priceLadderPk); 32 | } 33 | -------------------------------------------------------------------------------- /admin/print_market.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey } from "@solana/web3.js"; 2 | import { 3 | findEscrowPda, 4 | findMarketCommissionPaymentQueuePda, 5 | findMarketLiquiditiesPda, 6 | findMarketMatchingQueuePda, 7 | findMarketOrderRequestQueuePda, 8 | getMarket, 9 | } from "../npm-client"; 10 | import { getProtocolProgram } from "./util"; 11 | import { findMarketFundingPda } from "../npm-admin-client"; 12 | 13 | export async function printMarket() { 14 | const program = await getProtocolProgram(); 15 | 16 | if (process.argv.length != 4) { 17 | console.log("Usage: yarn run printMarket
"); 18 | process.exit(1); 19 | } 20 | 21 | const marketPk = new PublicKey(process.argv[3]); 22 | 23 | const market = await getMarket(program, marketPk); 24 | const marketEscrowPk = await findEscrowPda(program, marketPk); 25 | const marketFundingPk = await findMarketFundingPda(program, marketPk); 26 | const marketLiquiditiesPk = await findMarketLiquiditiesPda(program, marketPk); 27 | const marketOrderRequestQueuePk = await findMarketOrderRequestQueuePda( 28 | program, 29 | marketPk, 30 | ); 31 | const marketMatchingQueuePk = await findMarketMatchingQueuePda( 32 | program, 33 | marketPk, 34 | ); 35 | const marketCommissionPaymentQueuePk = 36 | await findMarketCommissionPaymentQueuePda(program, marketPk); 37 | 38 | console.log(`Market: ${marketPk} : ${JSON.stringify(market, null, 2)}`); 39 | console.log(`- escrow: ${marketEscrowPk.data.pda.toBase58()}`); 40 | console.log(`- funding: ${marketFundingPk.data.pda.toBase58()}`); 41 | console.log( 42 | `- marketLiquidities: ${marketLiquiditiesPk.data.pda.toBase58()}`, 43 | ); 44 | console.log( 45 | `- marketOrderRequestQueue: ${marketOrderRequestQueuePk.data.pda.toBase58()}`, 46 | ); 47 | console.log( 48 | `- marketMatchingQueue: ${marketMatchingQueuePk.data.pda.toBase58()}`, 49 | ); 50 | console.log( 51 | `- marketCommissionPaymentQueue: ${marketCommissionPaymentQueuePk.data.pda.toBase58()}`, 52 | ); 53 | } 54 | -------------------------------------------------------------------------------- /admin/product.ts: -------------------------------------------------------------------------------- 1 | import { createProduct } from "../npm-client/src/product"; 2 | import { PublicKey } from "@solana/web3.js"; 3 | import { Program } from "@coral-xyz/anchor"; 4 | import * as anchor from "@coral-xyz/anchor"; 5 | 6 | export async function create_product() { 7 | if (process.argv.length != 6) { 8 | console.log( 9 | "Usage: yarn run create_product ", 10 | ); 11 | process.exit(1); 12 | } 13 | 14 | const title = process.argv[3]; 15 | const commissionRate = parseFloat(process.argv[4]); 16 | const commissionEscrow = new PublicKey(process.argv[5]); 17 | 18 | const program = await getProtocolProductProgram(); 19 | const result = await createProduct( 20 | program as Program, 21 | title, 22 | commissionRate, 23 | commissionEscrow, 24 | ); 25 | console.log(JSON.stringify(result, null, 2)); 26 | } 27 | 28 | function getProtocolProductProgram() { 29 | return Program.at( 30 | "mppFrYmM6A4Ud3AxRbGXsGisX1HUsbDfp1nrg9FQJEE", 31 | anchor.getProvider(), 32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /audit/sec3/0.10.0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MonacoProtocol/protocol/a98aaf9f545709b65f6060b949572d65edc2f761/audit/sec3/0.10.0.pdf -------------------------------------------------------------------------------- /audit/sec3/0.10.1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MonacoProtocol/protocol/a98aaf9f545709b65f6060b949572d65edc2f761/audit/sec3/0.10.1.pdf -------------------------------------------------------------------------------- /audit/sec3/0.11.0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MonacoProtocol/protocol/a98aaf9f545709b65f6060b949572d65edc2f761/audit/sec3/0.11.0.pdf -------------------------------------------------------------------------------- /audit/sec3/0.12.0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MonacoProtocol/protocol/a98aaf9f545709b65f6060b949572d65edc2f761/audit/sec3/0.12.0.pdf -------------------------------------------------------------------------------- /audit/sec3/0.12.1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MonacoProtocol/protocol/a98aaf9f545709b65f6060b949572d65edc2f761/audit/sec3/0.12.1.pdf -------------------------------------------------------------------------------- /audit/sec3/0.13.0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MonacoProtocol/protocol/a98aaf9f545709b65f6060b949572d65edc2f761/audit/sec3/0.13.0.pdf -------------------------------------------------------------------------------- /audit/sec3/0.14.0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MonacoProtocol/protocol/a98aaf9f545709b65f6060b949572d65edc2f761/audit/sec3/0.14.0.pdf -------------------------------------------------------------------------------- /audit/sec3/0.14.1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MonacoProtocol/protocol/a98aaf9f545709b65f6060b949572d65edc2f761/audit/sec3/0.14.1.pdf -------------------------------------------------------------------------------- /audit/sec3/0.14.2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MonacoProtocol/protocol/a98aaf9f545709b65f6060b949572d65edc2f761/audit/sec3/0.14.2.pdf -------------------------------------------------------------------------------- /audit/sec3/0.15.0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MonacoProtocol/protocol/a98aaf9f545709b65f6060b949572d65edc2f761/audit/sec3/0.15.0.pdf -------------------------------------------------------------------------------- /audit/sec3/0.15.1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MonacoProtocol/protocol/a98aaf9f545709b65f6060b949572d65edc2f761/audit/sec3/0.15.1.pdf -------------------------------------------------------------------------------- /audit/sec3/0.15.2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MonacoProtocol/protocol/a98aaf9f545709b65f6060b949572d65edc2f761/audit/sec3/0.15.2.pdf -------------------------------------------------------------------------------- /audit/sec3/0.15.3.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MonacoProtocol/protocol/a98aaf9f545709b65f6060b949572d65edc2f761/audit/sec3/0.15.3.pdf -------------------------------------------------------------------------------- /audit/sec3/0.15.4.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MonacoProtocol/protocol/a98aaf9f545709b65f6060b949572d65edc2f761/audit/sec3/0.15.4.pdf -------------------------------------------------------------------------------- /audit/sec3/0.15.5.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MonacoProtocol/protocol/a98aaf9f545709b65f6060b949572d65edc2f761/audit/sec3/0.15.5.pdf -------------------------------------------------------------------------------- /audit/sec3/0.5.0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MonacoProtocol/protocol/a98aaf9f545709b65f6060b949572d65edc2f761/audit/sec3/0.5.0.pdf -------------------------------------------------------------------------------- /audit/sec3/0.6.0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MonacoProtocol/protocol/a98aaf9f545709b65f6060b949572d65edc2f761/audit/sec3/0.6.0.pdf -------------------------------------------------------------------------------- /audit/sec3/0.7.0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MonacoProtocol/protocol/a98aaf9f545709b65f6060b949572d65edc2f761/audit/sec3/0.7.0.pdf -------------------------------------------------------------------------------- /audit/sec3/0.8.0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MonacoProtocol/protocol/a98aaf9f545709b65f6060b949572d65edc2f761/audit/sec3/0.8.0.pdf -------------------------------------------------------------------------------- /audit/sec3/0.9.0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MonacoProtocol/protocol/a98aaf9f545709b65f6060b949572d65edc2f761/audit/sec3/0.9.0.pdf -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | ["@babel/preset-env", { targets: { node: "current" } }], 4 | "@babel/preset-typescript", 5 | ], 6 | }; 7 | -------------------------------------------------------------------------------- /ci/build_manager/build_and_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # build and test program outputting build and logs 4 | 5 | # usage ./ci/build_manager/build_and_test.sh -t BUILD_TYPE < stable | dev > 6 | # ./ci/build_manager/build_and_test.sh -t dev 7 | 8 | set -euxo pipefail 9 | 10 | PROGRAM="monaco_protocol" 11 | 12 | while getopts t: flag 13 | do 14 | case "${flag}" in 15 | t) TYPE=${OPTARG};; 16 | esac 17 | done 18 | 19 | rm -f {build_log,test_log} 20 | touch test_log build_log 21 | 22 | cargo test 2>&1 | tee test_log 23 | anchor test 2>&1 | tee -a test_log 24 | anchor build -p ${PROGRAM} -- --features ${TYPE} 2>&1 | tee build_log 25 | -------------------------------------------------------------------------------- /ci/build_manager/download_artifact.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # download a program artifact from AWS for given program and artifact type 4 | # artifact type can be either build or idl (defaults to build) 5 | # optional -o dir to output result, defaults to download 6 | 7 | # usage ./ci/deploy_manager/download_artifact.sh -b BUILD -a ARTIFACT < build | idl > -o OUTPUT_DIR 8 | # ./ci/build_manager/download_artifact.sh -b 0.1.0.dev.bbb9c3df -a idl -o target/idl 9 | 10 | TYPE="dev" 11 | PROGRAM="monaco_protocol" 12 | BUCKET="betdex-core-programs" 13 | ARTIFACT="build" 14 | ARTIFACT_PATH="deploy" 15 | FILE_TYPE="so" 16 | OUTPUT_DIR="download" 17 | 18 | while getopts b:a:o: flag 19 | do 20 | case "${flag}" in 21 | b) BUILD=${OPTARG};; 22 | a) ARTIFACT=${OPTARG};; 23 | o) OUTPUT_DIR=${OPTARG};; 24 | esac 25 | done 26 | 27 | if [[ "$BUILD" == *"stable"* ]]; then 28 | TYPE="stable" 29 | fi 30 | 31 | if [ $ARTIFACT == "idl" ] 32 | then 33 | ARTIFACT_PATH="$ARTIFACT" 34 | FILE_TYPE="json" 35 | fi 36 | 37 | FILE="${BUILD}.${FILE_TYPE}" 38 | 39 | echo "Getting ${TYPE} ${ARTIFACT} for ${BUILD}.${FILE_TYPE}" 40 | 41 | mkdir -p ${OUTPUT_DIR} -v 42 | 43 | aws s3api get-object --bucket ${BUCKET} --key ${PROGRAM}/${TYPE}/${ARTIFACT_PATH}/${FILE} ${OUTPUT_DIR}/${FILE} 44 | 45 | echo "File saved to ${OUTPUT_DIR}/${FILE}" 46 | -------------------------------------------------------------------------------- /ci/build_manager/generate_build_name.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # generate a build name based of build type and checksum 4 | 5 | # usage ./ci/build_manager/generate_build_name.sh -v VERSION -t BUILD_TYPE < stable | dev > 6 | # ./ci/build_manager/generate_build_name.sh -v 0.1.0 -t dev 7 | 8 | set -euxo pipefail 9 | 10 | PROGRAM="monaco_protocol" 11 | 12 | while getopts v:b:t: flag 13 | do 14 | case "${flag}" in 15 | v) VERSION=${OPTARG};; 16 | t) TYPE=${OPTARG};; 17 | esac 18 | done 19 | 20 | sha256sum target/deploy/${PROGRAM}.so > target/deploy/checksum 21 | CHECKSUM=`cat target/deploy/checksum | cut -d' ' -f1` 22 | CHECKSUM_SHORT=`cut -c -8 <<< $CHECKSUM` 23 | BUILD_NAME="${VERSION}.${TYPE}.${CHECKSUM_SHORT}" 24 | 25 | echo $BUILD_NAME 26 | -------------------------------------------------------------------------------- /ci/build_manager/save_build_artifacts.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # save build artifacts by checksum and bundle into folder based on semantic version and built type 4 | 5 | # usage ./save_build_artifacts.sh -v VERSION -t BUILD_TYPE < stable | dev > 6 | # ./ci/build_manager/save_build_artifacts.sh -v 0.1.0 -t stable 7 | 8 | set -euxo pipefail 9 | 10 | VERSION="version" 11 | PROGRAM="monaco_protocol" 12 | TYPE="dev" 13 | 14 | while getopts v:t: flag 15 | do 16 | case "${flag}" in 17 | v) VERSION=${OPTARG};; 18 | t) TYPE=${OPTARG};; 19 | esac 20 | done 21 | 22 | BUILD_DIR="${TYPE}/" 23 | 24 | FILE_NAME=`bash ./ci/build_manager/generate_build_name.sh -v ${VERSION} -t ${TYPE}` 25 | 26 | mv -v target/deploy/${PROGRAM}.so target/deploy/${FILE_NAME}.so 27 | mv -v target/deploy/checksum target/deploy/${FILE_NAME}_checksum 28 | mv -v target/idl/${PROGRAM}.json target/idl/${FILE_NAME}.json 29 | mv -v build_log ${FILE_NAME}_build_log 30 | mv -v test_log ${FILE_NAME}_test_log 31 | 32 | mkdir -v -p ${BUILD_DIR}/logs 33 | 34 | mv -v -f ${FILE_NAME}_build_log ${FILE_NAME}_test_log ${BUILD_DIR}/logs/ 35 | mv -v -f target/deploy ${BUILD_DIR} 36 | mv -v -f target/idl ${BUILD_DIR} 37 | -------------------------------------------------------------------------------- /ci/build_manager/upload_build_artifacts.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # upload build artifacts 4 | 5 | # usage ./save_build_artifacts.sh -t BUILD_TYPE -a AWS_BUCKET 6 | # ./ci/build_manager/upload_build_artifacts.sh -t dev -b betdex-core-programs 7 | 8 | set -euxo pipefail 9 | 10 | PROGRAM="monaco_protocol" 11 | BUCKET="betdex-core-programs" 12 | 13 | while getopts t:b: flag 14 | do 15 | case "${flag}" in 16 | t) TYPE=${OPTARG};; 17 | b) BUCKET=${OPTARG};; 18 | esac 19 | done 20 | 21 | aws s3 sync --acl private ${TYPE}/ s3://${BUCKET}/${PROGRAM}/${TYPE}/ 22 | 23 | rm -f -R ${TYPE} 24 | -------------------------------------------------------------------------------- /ci/deploy_manager/deploy_program.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # deploy program by environment - will fail if the program does not have a program ID registered in ci/deploy_manager/program_data.json 4 | 5 | # usage ./ci/deploy_manager/deploy_program.sh -e ENVIRONMENT < stable | dev > -f FILE_PATH 6 | # ./ci/deploy_manager/deploy_program.sh -e devnet -t dev -f target/deploy/0.1.0.dev.bbb9c3df.so 7 | 8 | set -euxo pipefail 9 | 10 | TYPE="dev" 11 | PROGRAM="monaco_protocol" 12 | FILE_PATH="target/deploy/$PROGRAM.so" 13 | 14 | while getopts e:f: flag 15 | do 16 | case "${flag}" in 17 | e) ENVIRONMENT=${OPTARG};; 18 | f) FILE_PATH=${OPTARG};; 19 | esac 20 | done 21 | 22 | WALLET_MANAGER="./ci/wallet_manager" 23 | DEPLOY_MANAGER="./ci/deploy_manager" 24 | 25 | if [[ "$FILE_PATH" == *"stable"* ]]; then 26 | TYPE="stable" 27 | fi 28 | 29 | PROGRAM_ID=`$DEPLOY_MANAGER/get_program_data.sh -e $ENVIRONMENT -t $TYPE | jq -r .program_id` 30 | 31 | if [ $PROGRAM_ID == null ] 32 | then 33 | echo "No Program ID found \nAborting Deploy" 34 | exit 1 35 | else 36 | echo "Program ID: $PROGRAM_ID" 37 | fi 38 | 39 | echo "Upgrading $TYPE $PROGRAM to $PROGRAM_ID on $ENVIRONMENT from location $FILE_PATH" 40 | anchor upgrade --provider.cluster $ENVIRONMENT --provider.wallet $WALLET_MANAGER/wallet.json --program-id $PROGRAM_ID $FILE_PATH 41 | -------------------------------------------------------------------------------- /ci/deploy_manager/get_last_deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # get the last deploy for a program by program name and environment 4 | 5 | # usage ./get_last_deploy.sh -e ENVIRONMENT -t DEPLOY_TYPE 6 | # ./ci/deploy_manager/get_last_deploy.sh -e devnet -t stable 7 | 8 | while getopts t:e: flag 9 | do 10 | case "${flag}" in 11 | t) DEPLOY_TYPE=${OPTARG};; 12 | e) ENVIRONMENT=${OPTARG};; 13 | esac 14 | done 15 | 16 | HISTORY_FILE="./ci/deploy_manager/${ENVIRONMENT}_history/${DEPLOY_TYPE}.json" 17 | 18 | jq '.deploys | max_by(.deployment_id)' $HISTORY_FILE 19 | -------------------------------------------------------------------------------- /ci/deploy_manager/get_program_data.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # get program data for a program by environment 4 | 5 | # usage ./ci/deploy_manager/get_program_data.sh -e ENVIRONMENT < devnet | testnet > -t BUILD_TYPE < stable | dev > 6 | 7 | set -euxo pipefail 8 | 9 | PROGRAM="monaco_protocol" 10 | TYPE="dev" 11 | 12 | while getopts t:e: flag 13 | do 14 | case "${flag}" in 15 | t) TYPE=${OPTARG};; 16 | e) ENVIRONMENT=${OPTARG};; 17 | esac 18 | done 19 | 20 | HISTORY_FILE="./ci/deploy_manager/program_data.json" 21 | 22 | jq --arg program ${PROGRAM} --arg env ${ENVIRONMENT} --arg type ${TYPE} '. | .[$program] | .[$env] | .[$type]' $HISTORY_FILE 23 | -------------------------------------------------------------------------------- /ci/deploy_manager/initial_deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # iniitial deploy of program by environment - the output program ID should then be added to ci/deploy_manager/program_data.json 4 | 5 | # usage ./initial_deploy.sh -p PROGRAM -e ENVIRONMENT 6 | 7 | while getopts p:e: flag 8 | do 9 | case "${flag}" in 10 | p) PROGRAM=${OPTARG};; 11 | e) ENVIRONMENT=${OPTARG};; 12 | esac 13 | done 14 | 15 | WALLET_MANAGER="./ci/wallet_manager" 16 | 17 | echo "Initial Deploy of $PROGRAM on $ENVIRONMENT" 18 | anchor deploy --provider.cluster $ENVIRONMENT --provider.wallet $WALLET_MANAGER/wallet.json -p $PROGRAM 19 | -------------------------------------------------------------------------------- /ci/deploy_manager/initial_idl.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Initialises IDL for given program on the chosen environment 4 | # https://book.anchor-lang.com/chapter_4/cli.html#idl-init 5 | # Will fail if the program does not have a program ID registered in ci/deploy_manager/program_data.json 6 | 7 | # usage ./ci/deploy_manager/initial_idl.sh -p PROGRAM -e ENVIRONMENT 8 | 9 | while getopts p:e: flag 10 | do 11 | case "${flag}" in 12 | p) PROGRAM=${OPTARG};; 13 | e) ENVIRONMENT=${OPTARG};; 14 | esac 15 | done 16 | 17 | WALLET_MANAGER="./ci/wallet_manager" 18 | DEPLOY_MANAGER="./ci/deploy_manager" 19 | PROGRAM_ID=`$DEPLOY_MANAGER/get_program_data.sh -p $PROGRAM -e $ENVIRONMENT | jq -r .program_id` 20 | 21 | if [ $PROGRAM_ID == null ] 22 | then 23 | echo "No Program ID found \nAborting Update" 24 | exit 1 25 | else 26 | echo "Program ID: $PROGRAM_ID" 27 | fi 28 | 29 | echo "Upgrading IDL for $PROGRAM on $ENVIRONMENT" 30 | anchor idl init --provider.cluster $ENVIRONMENT --provider.wallet $WALLET_MANAGER/wallet.json -f target/idl/$PROGRAM.json $PROGRAM_ID 31 | -------------------------------------------------------------------------------- /ci/deploy_manager/mainnet_history/monaco_protocol.json: -------------------------------------------------------------------------------- 1 | { 2 | "deploys": [ 3 | { 4 | "deployment_id": 1, 5 | "new_version": { 6 | "version": null, 7 | "checksum": null 8 | }, 9 | "previous_version": { 10 | "version": null, 11 | "checksum": null 12 | }, 13 | "time": null, 14 | "actioned_by": null, 15 | "notes": null 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /ci/deploy_manager/program_data.json: -------------------------------------------------------------------------------- 1 | { 2 | "monaco_protocol": { 3 | "devnet": { 4 | "stable": { 5 | "program_id": "5Q2hKsxShaPxFqgVtQH3ErTkiBf8NGb99nmpaGw7FCrr", 6 | "idl_account": "Bw1JY5jbKTfyQBvFHCs3HjS6y4bjd8vhDbYvcGx4tKKE" 7 | }, 8 | "dev": { 9 | "program_id": "yxvZ2jHThHQPTN6mGC8Z4i7iVBtQb3eBGeURQuLSrG9", 10 | "idl_account": "FwLPLLyhQoPKJZYSdNxaP8KBQV1MCLC7FBuXe15gJZqJ" 11 | } 12 | }, 13 | "testnet": { 14 | "stable": { 15 | "program_id": "5Q2hKsxShaPxFqgVtQH3ErTkiBf8NGb99nmpaGw7FCrr", 16 | "idl_account": "Bw1JY5jbKTfyQBvFHCs3HjS6y4bjd8vhDbYvcGx4tKKE" 17 | } 18 | }, 19 | "mainnet": { 20 | "stable": { 21 | "program_id": null, 22 | "idl_account": null 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ci/deploy_manager/update_history.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # bash script to log deployment history taking in arguement flags and checking the deploy history file for previous deploy information 4 | # usage ./ci/deploy_manager/update_deploy_history.sh -a ACTIONEER -e ENVIRONMENT -b BUILD -n "additional notes" 5 | 6 | NOTES="Standard deploy" 7 | DEPLOY_TYPE="dev" 8 | 9 | while getopts e:a:b:s:n: flag 10 | do 11 | case "${flag}" in 12 | e) ENVIRONMENT=${OPTARG};; 13 | a) ACTIONED_BY=${OPTARG};; 14 | b) BUILD=${OPTARG};; 15 | n) NOTES=${OPTARG};; 16 | esac 17 | done 18 | 19 | if [[ "$BUILD" == *"stable"* ]]; then 20 | DEPLOY_TYPE="stable" 21 | fi 22 | 23 | HISTORY_FILE="./ci/deploy_manager/${ENVIRONMENT}_history/${DEPLOY_TYPE}.json" 24 | 25 | # getting previous deploy info and constructing deploy id + timestamp 26 | GET_LAST_DEPLOY=`echo ./ci/deploy_manager/get_last_deploy.sh -t $DEPLOY_TYPE -e $ENVIRONMENT` 27 | PREVIOUS_VERSION=`$GET_LAST_DEPLOY | jq .new_version` 28 | PREVIOUS_DEPLOY_ID=`$GET_LAST_DEPLOY | jq .deployment_id` 29 | DEPLOY_ID=`echo ${PREVIOUS_DEPLOY_ID} + 1 | bc` 30 | TIME=`date +"%d-%m-%y-%T"` 31 | 32 | # form deployment info json - using cat and a here-file to make it easier to read in this script 33 | DEPLOY_JSON=$( cat << END 34 | { 35 | "deployment_id": ${DEPLOY_ID}, 36 | "new_version": { 37 | "build": "${BUILD}" 38 | }, 39 | "previous_version": ${PREVIOUS_VERSION}, 40 | "time": "${TIME}", 41 | "actioned_by": "${ACTIONED_BY}", 42 | "notes": "${NOTES}" 43 | } 44 | END 45 | ) 46 | 47 | # create tmp file and then update with latest deploy info - appending it to the front of the list 48 | touch tmp 49 | jq --argjson deploy_info "$DEPLOY_JSON" '.deploys += [$deploy_info]' $HISTORY_FILE > tmp 50 | mv tmp $HISTORY_FILE 51 | 52 | jq '.deploys | max_by(.deployment_id)' $HISTORY_FILE 53 | -------------------------------------------------------------------------------- /ci/deploy_manager/update_idl.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # upgrades the IDL account for the given program and environment 4 | 5 | # usage ./ci/deploy_manager/update_idl.sh -e ENVIRONMENT -f FILE_PATH 6 | # ./ci/deploy_manager/update_idl.sh -e devnet -f target/idl/0.1.0.stable.21fc7474.json 7 | 8 | PROGRAM="monaco_protocol" 9 | 10 | while getopts e:f: flag 11 | do 12 | case "${flag}" in 13 | e) ENVIRONMENT=${OPTARG};; 14 | f) FILE_PATH=${OPTARG};; 15 | esac 16 | done 17 | 18 | TYPE="dev" 19 | if [[ "$FILE_PATH" == *"stable"* ]]; then 20 | TYPE="stable" 21 | fi 22 | 23 | WALLET_MANAGER="./ci/wallet_manager" 24 | DEPLOY_MANAGER="./ci/deploy_manager" 25 | PROGRAM_ID=`$DEPLOY_MANAGER/get_program_data.sh -e $ENVIRONMENT -t $TYPE | jq -r .program_id` 26 | IDL_ACCOUNT=`$DEPLOY_MANAGER/get_program_data.sh -e $ENVIRONMENT -t $TYPE | jq -r .idl_account` 27 | 28 | if [ $PROGRAM_ID == null ] 29 | then 30 | echo "No Program ID found \nAborting Update" 31 | exit 1 32 | else 33 | echo "Program ID: $PROGRAM_ID" 34 | fi 35 | 36 | if [ $IDL_ACCOUNT == null ] 37 | then 38 | echo "No IDL Account found \nCreate one with initial_idl.sh\nAborting Update" 39 | exit 1 40 | else 41 | echo "IDL account: $IDL_ACCOUNT" 42 | fi 43 | 44 | echo "Upgrading IDL for $PROGRAM on $ENVIRONMENT" 45 | anchor idl upgrade --provider.cluster $ENVIRONMENT --provider.wallet $WALLET_MANAGER/wallet.json $PROGRAM_ID -f ${FILE_PATH} 46 | -------------------------------------------------------------------------------- /ci/security_manager/authority_check.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Checks programs deployed for the currently set authority set with solana config set --keypair for the given solana env 4 | 5 | # usage ./authority_check.sh -e ENVIRONMENT (testnet/devnet/mainnet-beta) -n NUM_PROGRAMS 6 | 7 | set -e 8 | 9 | ENVIRONMENT="mainnet-beta" 10 | 11 | while getopts e:n: flag 12 | do 13 | case "${flag}" in 14 | e) ENVIRONMENT=${OPTARG};; 15 | n) NUM_PROGRAMS=${OPTARG};; 16 | esac 17 | done 18 | 19 | URL="https://api.${ENVIRONMENT}.solana.com" 20 | 21 | echo "Setting solana env for ${ENVIRONMENT}" 22 | solana config set --url ${URL} 23 | 24 | AUTHORITY_PUBKEY=`solana-keygen pubkey` 25 | echo "Getting programs for ${AUTHORITY_PUBKEY}" 26 | 27 | echo "Saving temporary deployed_programs file" 28 | solana program show --programs >> deployed_programs 29 | cat deployed_programs 30 | 31 | NUM_PROGRAMS_FOR_AUTHORITY=`cat deployed_programs | grep ${AUTHORITY_PUBKEY} -c` 32 | echo "Deployed programs: ${NUM_PROGRAMS_FOR_AUTHORITY}" 33 | 34 | if [ ${NUM_PROGRAMS_FOR_AUTHORITY} -gt ${NUM_PROGRAMS} ] 35 | then 36 | printf "*****\nUnknown programs associated with authority\nCheck deployed program IDs\n*****" 37 | rm -R deployed_programs 38 | exit 1 39 | fi 40 | 41 | echo "Removing temporary deployed_programs file" 42 | rm -R deployed_programs 43 | -------------------------------------------------------------------------------- /ci/security_manager/verify_program.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Full program verification - downloads assets then compares checksums 4 | 5 | # usage ./verify_program.sh -p -e ENVIRONMENT -t 6 | 7 | set -e 8 | 9 | ENVIRONMENT="mainnet-beta" 10 | SECURITY_MANAGER="./ci/security_manager" 11 | 12 | while getopts p:e:t: flag 13 | do 14 | case "${flag}" in 15 | p) PROGRAM=${OPTARG};; 16 | e) ENVIRONMENT=${OPTARG};; 17 | t) TYPE=${OPTARG};; 18 | esac 19 | done 20 | 21 | ${SECURITY_MANAGER}/verify_program_get_assets.sh -p ${PROGRAM} -e ${ENVIRONMENT} -t ${TYPE} 22 | ${SECURITY_MANAGER}/verify_program_checksum_check.sh -c ${PROGRAM}.so -p download/${PROGRAM}.so 23 | 24 | rm -f -R ${PROGRAM}.so download/${PROGRAM}.so 25 | -------------------------------------------------------------------------------- /ci/security_manager/verify_program_checksum_check.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Verified the on-chain program is the same program we deployed 4 | 5 | # usage ./verify_program_checksum_check.sh -c ON_CHAIN_PROGRAM_PATH -p ORIGINAL_PROGRAM_PATH 6 | 7 | set -e 8 | 9 | while getopts c:p: flag 10 | do 11 | case "${flag}" in 12 | c) ON_CHAIN=${OPTARG};; 13 | p) ORIGINAL=${OPTARG};; 14 | esac 15 | done 16 | 17 | # Pad out original to the size of the on-chain version 18 | # https://github.com/solana-labs/solana/blob/b8eff3456c50558736fe2f3caea4ab98e0fc6370/docs/src/cli/deploy-a-program.md#dumping-a-program-to-a-file 19 | truncate -r ${ON_CHAIN} ${ORIGINAL} 20 | 21 | sha256sum ${ON_CHAIN} > on_chain_checksum 22 | sha256sum ${ORIGINAL} > original_checksum 23 | 24 | OC_CHECKSUM=`cat on_chain_checksum | cut -d' ' -f1` 25 | OG_CHECKSUM=`cat original_checksum | cut -d' ' -f1` 26 | 27 | echo "On Chain Checksum: ${OC_CHECKSUM}" 28 | echo "Original Checksum: ${OG_CHECKSUM}" 29 | 30 | if [ ${OG_CHECKSUM} != ${OC_CHECKSUM} ] 31 | then 32 | printf "*****\nOn-chain program does not match original program\n*****" 33 | rm -f -R on_chain_checksum original_checksum ${ON_CHAIN} ${ORIGINAL} 34 | exit 1 35 | fi 36 | 37 | rm -f -R on_chain_checksum original_checksum 38 | echo "Done" 39 | -------------------------------------------------------------------------------- /ci/security_manager/verify_program_get_assets.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Get assets for latest deployed program by environment 4 | 5 | # usage ./verify_program_get_assets.sh -e ENVIRONMENT (devnet/testnet/mainnet-beta) -t DEPLOY_TYPE 6 | 7 | set -e 8 | 9 | ENVIRONMENT="mainnet-beta" 10 | DEPLOY_MANAGER="./ci/deploy_manager" 11 | BUILD_MANAGER="./ci/build_manager" 12 | BUCKET="betdex-core-programs" 13 | 14 | while getopts p:t:e: flag 15 | do 16 | case "${flag}" in 17 | p) PROGRAM=${OPTARG};; 18 | t) TYPE=${OPTARG};; 19 | e) ENVIRONMENT=${OPTARG};; 20 | esac 21 | done 22 | 23 | rm -f -R ${PROGRAM}.so target/deploy/${PROGRAM}.so 24 | 25 | URL="https://api.${ENVIRONMENT}.solana.com" 26 | 27 | echo "Getting program assets for ${TYPE} ${PROGRAM} on ${ENVIRONMENT}" 28 | 29 | echo "Setting solana env for ${ENVIRONMENT}" 30 | solana config set --url ${URL} 31 | 32 | PROGRAM_ID=`${DEPLOY_MANAGER}/get_program_data.sh -e ${ENVIRONMENT} -t ${TYPE} | jq -r .program_id` 33 | LAST_DEPLOY_BUILD=`${DEPLOY_MANAGER}/get_last_deploy.sh -p ${PROGRAM} -e ${ENVIRONMENT} | jq -r .new_version.build` 34 | 35 | echo "Getting program dump of ${PROGRAM_ID}" 36 | solana program dump ${PROGRAM_ID} ${PROGRAM}.so 37 | 38 | bash ${BUILD_MANAGER}/download_artifact.sh -b ${LAST_DEPLOY_BUILD} -t ${TYPE} -a build 39 | -------------------------------------------------------------------------------- /ci/version_manager/bump_client_version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # usage ci/version_manager/bump_client_version.sh -v < MAJOR | MINOR | PATCH > -c < CLIENT_TYPE > 4 | 5 | VERSION_BUMP="PATCH" 6 | 7 | while getopts v:c: flag 8 | do 9 | case "${flag}" in 10 | v) VERSION_BUMP=${OPTARG};; 11 | c) CLIENT=${OPTARG};; 12 | esac 13 | done 14 | 15 | VERSION_FILE="./npm-client/package.json" 16 | 17 | if [ "$CLIENT" == "admin" ]; 18 | then 19 | VERSION_FILE="./npm-admin-client/package.json" 20 | fi 21 | 22 | echo "Updating $VERSION_FILE" 23 | 24 | # get latest version info 25 | CURRENT_VERSION=`jq -r '. | .version' $VERSION_FILE` 26 | echo "Current version: ${CURRENT_VERSION}" 27 | 28 | # split current version into an array to allow us to increment version according to semantic versioning - https://semver.org/ 29 | IFS='.' 30 | read -a VERSION_BREAKDOWN <<< "$CURRENT_VERSION" 31 | IFS=',' 32 | 33 | # decide how much to increment by based on VERSION_BUMP flag 34 | echo "Setting version for a ${VERSION_BUMP} release" 35 | if [ $VERSION_BUMP == "MAJOR" ] 36 | then 37 | BUMP=`echo ${VERSION_BREAKDOWN[0]} + 1 | bc` 38 | NEXT_VERSION="${BUMP}.0.0" 39 | elif [ $VERSION_BUMP == "MINOR" ] 40 | then 41 | BUMP=`echo ${VERSION_BREAKDOWN[1]} + 1 | bc` 42 | NEXT_VERSION="${VERSION_BREAKDOWN[0]}.${BUMP}.0" 43 | else 44 | BUMP=`echo ${VERSION_BREAKDOWN[2]} + 1 | bc` 45 | NEXT_VERSION="${VERSION_BREAKDOWN[0]}.${VERSION_BREAKDOWN[1]}.${BUMP}" 46 | fi 47 | 48 | echo "New version info: $NEXT_VERSION" 49 | 50 | # create a temp file to replace current version file with 51 | touch tmp 52 | 53 | # export updated version json to tmp file 54 | jq --arg version "$NEXT_VERSION" '.version = $version ' $VERSION_FILE > tmp 55 | 56 | # update version.json 57 | mv tmp $VERSION_FILE 58 | 59 | echo 'Done' 60 | -------------------------------------------------------------------------------- /ci/version_manager/check_deploy_status.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # script to check if the version in the TOML for a program has been deployed 4 | # if the version has been deployed, exit with an error 5 | 6 | # usage ./check_deploy_status.sh -p PROGRAM_NAME 7 | 8 | set -e 9 | 10 | DEPLOYED=false 11 | 12 | while getopts p: flag 13 | do 14 | case "${flag}" in 15 | p) PROGRAM=${OPTARG};; 16 | esac 17 | done 18 | 19 | VERSION_MANAGER="./ci/version_manager" 20 | VERSION_FILE="${VERSION_MANAGER}/versions/${PROGRAM}.json" 21 | 22 | VERSION_TO_CHECK=`${VERSION_MANAGER}/get_toml_version.sh -p $PROGRAM` 23 | DEPLOYED=`jq --arg version_to_check "$VERSION_TO_CHECK" '.versions[] | select(.version == $version_to_check) |.deployed' $VERSION_FILE` 24 | 25 | echo "Checking deployment status of $PROGRAM version $VERSION_TO_CHECK" 26 | 27 | if [ "$DEPLOYED" == "true" ] 28 | then 29 | echo "Error - Version Deployed - TOML needs updating" 30 | exit 1 31 | else 32 | echo "OK to proceed" 33 | fi 34 | -------------------------------------------------------------------------------- /ci/version_manager/get_latest_version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # get the latest version info of the supplied program 4 | 5 | # usage ./get_latest_version.sh -p PROGRAM_NAME 6 | 7 | while getopts p: flag 8 | do 9 | case "${flag}" in 10 | p) PROGRAM=${OPTARG};; 11 | esac 12 | done 13 | 14 | VERSION_MANAGER="./ci/version_manager" 15 | VERSION_FILE="${VERSION_MANAGER}/versions/${PROGRAM}.json" 16 | 17 | jq '.versions | max_by(.version) ' $VERSION_FILE 18 | -------------------------------------------------------------------------------- /ci/version_manager/get_toml_version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | while getopts p: flag 4 | do 5 | case "${flag}" in 6 | p) PROGRAM=${OPTARG};; 7 | esac 8 | done 9 | 10 | TOML_PATH="./programs/$PROGRAM" 11 | 12 | # get current version from .toml file 13 | CARGO_TOML="${TOML_PATH}/Cargo.toml" 14 | IFS="=" 15 | while read -r CONFIG_NAME CONFIG_VALUE 16 | do 17 | if [ `echo $CONFIG_NAME | xargs` == "version" ] 18 | then 19 | TOML_VERSION=` echo $CONFIG_VALUE | xargs | tr -d '"'` 20 | break 21 | fi 22 | done < $CARGO_TOML 23 | 24 | echo $TOML_VERSION 25 | -------------------------------------------------------------------------------- /ci/version_manager/version_history/market.json: -------------------------------------------------------------------------------- 1 | { 2 | "versions": [ 3 | { 4 | "version": null, 5 | "previous_version": null, 6 | "checksum": null, 7 | "commit": null, 8 | "deployed": false 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /ci/version_manager/version_history/matchmaker.json: -------------------------------------------------------------------------------- 1 | { 2 | "versions": [ 3 | { 4 | "version": null, 5 | "previous_version": null, 6 | "checksum": null, 7 | "commit": null, 8 | "deployed": false 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /ci/wallet_manager/decrypt_wallet.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | gpg --quiet --batch --yes --decrypt --passphrase="$WALLET_PASSPHRASE" \ 4 | --output ./ci/wallet_manager/wallet.json ./ci/wallet_manager/wallet.json.gpg 5 | echo 'Done' 6 | -------------------------------------------------------------------------------- /ci/wallet_manager/decrypt_wallet_cleanup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "Running post decrypt script" 4 | rm -R ./ci/wallet_manager/wallet.json 5 | echo "Done" 6 | -------------------------------------------------------------------------------- /ci/wallet_manager/encrypt_wallet.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | gpg --symmetric --cipher-algo AES256 wallet.json 4 | echo 'Done' 5 | -------------------------------------------------------------------------------- /ci/wallet_manager/set_keypair.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # set default wallet keypair 4 | solana config set --keypair ./ci/wallet_manager/wallet.json 5 | -------------------------------------------------------------------------------- /ci/wallet_manager/update_wallet_balance.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # update wallet balance (currently capped at 2 SOL on devnet and 1 SOL on testnet) 4 | 5 | # usage ./update_wallet_balance.sh -p PUBKEY -a AMOUNT 6 | 7 | set -e 8 | 9 | PUBKEY="98CVwMftrhm6zutmV29frqRPfXsocbFnwjXVxYo7xbHX" 10 | UPDATE_AMOUNT=2 11 | 12 | while getopts p: flag 13 | do 14 | case "${flag}" in 15 | p) PUBKEY=${OPTARG};; 16 | a) UPDATE_AMOUNT=${OPTARG};; 17 | esac 18 | done 19 | 20 | solana airdrop --verbose $UPDATE_AMOUNT $PUBKEY 21 | -------------------------------------------------------------------------------- /ci/wallet_manager/wallet.json.gpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MonacoProtocol/protocol/a98aaf9f545709b65f6060b949572d65edc2f761/ci/wallet_manager/wallet.json.gpg -------------------------------------------------------------------------------- /clippy.toml: -------------------------------------------------------------------------------- 1 | too-many-arguments-threshold = 12 2 | large-error-threshold = 170 3 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | const jestConfig = { 2 | verbose: true, 3 | testMatch: ["**/tests/**/*.ts?(x)"], 4 | testPathIgnorePatterns: [ 5 | "tests/setup.ts", 6 | "tests/util/pdas.ts", 7 | "tests/util/test_util.ts", 8 | "tests/util/wrappers.ts", 9 | "tests/anchor/*", 10 | ], 11 | globalSetup: "/tests/setup.ts", 12 | setupFilesAfterEnv: ["/tests/util/test_util.ts"], 13 | testTimeout: 1200000, 14 | }; 15 | 16 | module.exports = jestConfig; 17 | -------------------------------------------------------------------------------- /migrations/deploy.ts: -------------------------------------------------------------------------------- 1 | // Migrations are an early feature. Currently, they're nothing more than this 2 | // single deploy script that's invoked from the CLI, injecting a provider 3 | // configured from the workspace's Anchor.toml. 4 | 5 | import anchor from "@coral-xyz/anchor"; 6 | 7 | module.exports = async function (provider) { 8 | // Configure client to use the provider. 9 | anchor.setProvider(provider); 10 | 11 | // Add your deploy script here. 12 | }; 13 | -------------------------------------------------------------------------------- /npm-admin-client/README.md: -------------------------------------------------------------------------------- 1 | # Monaco Protocol Admin Client 2 | 3 | NPM package to interface with admin functionality for the Monaco Protocol program on the [Solana network](https://solana.com/developers). The Monaco Protocol provides a decentralized liquidity network for wagering on binary-outcome events. 4 | 5 | The package opens up admin-facing interactions with the protocol including: 6 | 7 | - Create markets 8 | - Manage markets 9 | - Manage admin permissions 10 | 11 | # Documentation 12 | 13 | All endpoints exported by the library contain detailed doc strings and examples confirming to the JSDoc format. These doc strings can be viewed separately in the [docs](./docs/) directory. 14 | 15 | ## Generating Docs 16 | 17 | Docs are generated using [documentationjs](https://github.com/documentationjs/documentation). 18 | 19 | ``` 20 | npm run generateDocs 21 | ``` 22 | 23 | # Client Response Format 24 | 25 | All endpoints in the client return the same response format: 26 | 27 | ``` 28 | export type ClientResponse = { 29 | success: boolean; 30 | errors: object[]; 31 | data: T; 32 | }; 33 | ``` 34 | 35 | Each endpoint defines its own data type used in the response, for example: `createOrderUiStake` returns `Promise>` 36 | 37 | ``` 38 | export type CreateOrderResponse = { 39 | orderPk: PublicKey; 40 | tnxID: string | void; 41 | }; 42 | ``` 43 | 44 | ## Errors 45 | 46 | Errors are purposely left loosely typed as an `object[]` so that the client can remain as agnostic as possible and pass through unfiltered errors regardless of origin. 47 | 48 | If any error is encountered during a request, the client will return `success: false` and data may come back `undefined`. 49 | -------------------------------------------------------------------------------- /npm-admin-client/docs/endpoints/market_outcome.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Table of Contents 4 | 5 | * [initialiseOutcomes][1] 6 | * [Parameters][2] 7 | * [Examples][3] 8 | 9 | ## initialiseOutcomes 10 | 11 | For the given market account, initialise outcome accounts for the provided outcomes 12 | 13 | ### Parameters 14 | 15 | * `program` **Program** {program} anchor program initialized by the consuming client 16 | * `marketPk` **PublicKey** {PublicKey} publicKey of the market to initialise the outcome for 17 | * `outcomes` **[Array][4]<[string][5]>** {string\[]} list of strings representing the market outcomes 18 | * `priceLadderPk` **PublicKey?** {PublicKey | null} publicKey of the price ladder to associate with the outcomes - if null, the protocol's default price ladder will be used 19 | * `options` **TransactionOptionsBatch?** {TransactionOptionsBatch} optional parameters:
    20 |
  • batchSize - number of outcomes to create in single transaction (defaults to 2)
  • 21 |
  • confirmBatchSuccess - whether to confirm each batch transaction, if true and the current batch fails, the remaining batches will not be sent - this is overridden to always be true for initialising outcomes as they always need to be added sequentially and have their seeds validated/li> 22 |
  • computeUnitLimit - number of compute units to limit the transaction to
  • 23 |
  • computeUnitPrice - price in micro lamports per compute unit for the transaction
  • 24 |
25 | 26 | ### Examples 27 | 28 | ```javascript 29 | const marketPk = new PublicKey('7o1PXyYZtBBDFZf9cEhHopn2C9R4G6GaPwFAxaNWM33D') 30 | const outcomes = ["Monaco Protocol", "Draw"] 31 | const priceLadderPk = new PublicKey('5cL9zVtKrugMx6J6vT5LP4hdxq5TSGzrcc5GMj3YSwGk'); 32 | const initialiseOutcomeRequest = await initialiseOutcomes(program, marketPk, outcomes, priceLadderPk) 33 | ``` 34 | 35 | Returns **OutcomeInitialisationsResponse** list of the outcomes provided, their pdas and the transaction IDs performed in the request 36 | 37 | [1]: #initialiseoutcomes 38 | 39 | [2]: #parameters 40 | 41 | [3]: #examples 42 | 43 | [4]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array 44 | 45 | [5]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String 46 | -------------------------------------------------------------------------------- /npm-admin-client/docs/endpoints/market_type_create.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Table of Contents 4 | 5 | * [findMarketTypePda][1] 6 | * [Parameters][2] 7 | * [getOrCreateMarketType][3] 8 | * [Parameters][4] 9 | * [Examples][5] 10 | 11 | ## findMarketTypePda 12 | 13 | ### Parameters 14 | 15 | * `program` **Program** 16 | * `marketType` **[string][6]** 17 | 18 | Returns **ClientResponse\** 19 | 20 | ## getOrCreateMarketType 21 | 22 | For the given parameters: 23 | 24 | * Attempt to fetch and return a market type account with the given marketTypeName 25 | * If no market type account is found, attempt to create and return a new market type with the given data. 26 | 27 | ### Parameters 28 | 29 | * `program` **Program** {program} anchor program initialized by the consuming client 30 | * `marketTypeName` **[string][6]** {string} name of the market type being fetched or created 31 | * `requiresDiscriminator` **[boolean][7]?** {boolean} if creating a new market type, whether the market type requires a discriminator to be set on markets using the type 32 | * `requiresValue` **[boolean][7]?** {boolean} if creating a new market type, whether the market type requires a value (e.g. a number) to be set on markets using the type 33 | 34 | ### Examples 35 | 36 | ```javascript 37 | const marketTypeName = "NewMarketType 38 | const requiresDiscriminator = false; 39 | const requiresValue = true; 40 | const response = await getOrCreateMarketType(program, marketTypeName, requiresDiscriminator, requiresValue); 41 | ``` 42 | 43 | Returns **GetOrCreateAccountResponse** the market type account and public key - if a new account was created, also includes the transaction id 44 | 45 | [1]: #findmarkettypepda 46 | 47 | [2]: #parameters 48 | 49 | [3]: #getorcreatemarkettype 50 | 51 | [4]: #parameters-1 52 | 53 | [5]: #examples 54 | 55 | [6]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String 56 | 57 | [7]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean 58 | -------------------------------------------------------------------------------- /npm-admin-client/docs/endpoints/market_validate.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Table of Contents 4 | 5 | * [validateMarketOutcomes][1] 6 | * [Parameters][2] 7 | * [Examples][3] 8 | 9 | ## validateMarketOutcomes 10 | 11 | For the given market account, validate that all expected outcomes exist on that market and that all outcomes have the expected price ladder 12 | 13 | ### Parameters 14 | 15 | * `program` **Program** {program} anchor program initialized by the consuming client 16 | * `marketPk` **PublicKey** {PublicKey} 17 | * `expectedOutcomeTitles` **[Array][4]<[string][5]>** {string\[]} list of expected outcomes for the market 18 | * `expectedPriceLadder` **[Array][4]<[number][6]>** {number\[]} array of price points expected on each outcome 19 | 20 | ### Examples 21 | 22 | ```javascript 23 | const marketPk = new PublicKey('6KVA6wF9FwkjX2Ej1sdwX4TrsJ6MFnDwKv5D8njf1fmm') 24 | const expectedOutcomes = ["Red", "Draw", "Blue"] 25 | const priceLadder = DEFAULT_PRICE_LADDER 26 | const validateMarket = validateMarketOutcomes(program, marketPk, expectedOutcomes, expectedPriceLadder) 27 | ``` 28 | 29 | Returns **ValidateMarketResponse** Summary of the validity of the market for the given parameters, including a break down of any missing or additional outcomes or prices on the price ladders in relation to the expected and returned outcomes and price ladders 30 | 31 | [1]: #validatemarketoutcomes 32 | 33 | [2]: #parameters 34 | 35 | [3]: #examples 36 | 37 | [4]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array 38 | 39 | [5]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String 40 | 41 | [6]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number 42 | -------------------------------------------------------------------------------- /npm-admin-client/docs/types/client.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Table of Contents 4 | 5 | * [ClientResponse][1] 6 | * [Properties][2] 7 | * [FindPdaResponse][3] 8 | * [Properties][4] 9 | * [ResponseFactory][5] 10 | * [Examples][6] 11 | * [success][7] 12 | * [errors][8] 13 | * [data][9] 14 | * [TransactionResponse][10] 15 | * [Properties][11] 16 | * [TransactionBatchResponse][12] 17 | * [Properties][13] 18 | 19 | ## ClientResponse 20 | 21 | Type: {success: [boolean][14], errors: [Array][15]<[object][16]>, data: T} 22 | 23 | ### Properties 24 | 25 | * `success` **[boolean][14]** 26 | * `errors` **[Array][15]<[object][16]>** 27 | * `data` **T** 28 | 29 | ## FindPdaResponse 30 | 31 | Type: {pda: PublicKey} 32 | 33 | ### Properties 34 | 35 | * `pda` **PublicKey** 36 | 37 | ## ResponseFactory 38 | 39 | Helper to construct a client response object, each endpoint should return a response in this format 40 | 41 | ### Examples 42 | 43 | ```javascript 44 | const response = new ResponseFactory({} as OrderAccounts); 45 | try { 46 | performAction() 47 | } 48 | catch (e) { 49 | response.addError(e) 50 | } 51 | const secondaryRequest = separateRequest() 52 | if (!secondaryRequest.success){ 53 | response.addErrors(secondaryRequest.errors) 54 | return response.body 55 | } 56 | response.addResponseData({ 57 | orderPk: new PublicKey("Fy7WiqBy6MuWfnVjiPE8HQqkeLnyaLwBsk8cyyJ5WD8X") 58 | }) 59 | return response.body 60 | ``` 61 | 62 | ### success 63 | 64 | Type: [boolean][14] 65 | 66 | ### errors 67 | 68 | Type: [Array][15]<[object][16]> 69 | 70 | ### data 71 | 72 | Type: any 73 | 74 | ## TransactionResponse 75 | 76 | The transaction ID returned by a successful request 77 | 78 | Type: {tnxId: [string][17]} 79 | 80 | ### Properties 81 | 82 | * `tnxId` **[string][17]** 83 | 84 | ## TransactionBatchResponse 85 | 86 | Type: {tnxIds: [Array][15]<[string][17]>} 87 | 88 | ### Properties 89 | 90 | * `tnxIds` **[Array][15]<[string][17]>** 91 | 92 | [1]: #clientresponse 93 | 94 | [2]: #properties 95 | 96 | [3]: #findpdaresponse 97 | 98 | [4]: #properties-1 99 | 100 | [5]: #responsefactory 101 | 102 | [6]: #examples 103 | 104 | [7]: #success 105 | 106 | [8]: #errors 107 | 108 | [9]: #data 109 | 110 | [10]: #transactionresponse 111 | 112 | [11]: #properties-2 113 | 114 | [12]: #transactionbatchresponse 115 | 116 | [13]: #properties-3 117 | 118 | [14]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean 119 | 120 | [15]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array 121 | 122 | [16]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object 123 | 124 | [17]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String 125 | -------------------------------------------------------------------------------- /npm-admin-client/docs/types/default_price_ladder.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Table of Contents 4 | 5 | * [DEFAULT\_PRICE\_LADDER][1] 6 | 7 | ## DEFAULT\_PRICE\_LADDER 8 | 9 | Price ladder that provides industry-standard price ranges for a market 10 | 11 | Type: [Array][2]<[number][3]> 12 | 13 | [1]: #default_price_ladder 14 | 15 | [2]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array 16 | 17 | [3]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number 18 | -------------------------------------------------------------------------------- /npm-admin-client/docs/types/market_outcomes.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Table of Contents 4 | 5 | * [GetPublicKeys][1] 6 | * [Properties][2] 7 | * [MarketOutcomeAccount][3] 8 | * [Properties][4] 9 | * [MarketOutcomeAccounts][5] 10 | * [Properties][6] 11 | * [MarketOutcomeTitlesResponse][7] 12 | * [Properties][8] 13 | 14 | ## GetPublicKeys 15 | 16 | Type: {publicKeys: [Array][9]\} 17 | 18 | ### Properties 19 | 20 | * `publicKeys` **[Array][9]\** 21 | 22 | ## MarketOutcomeAccount 23 | 24 | Type: {index: [number][10], title: [string][11], market: PublicKey, prices: (PublicKey | null), priceLadder: [Array][9]<[number][10]>} 25 | 26 | ### Properties 27 | 28 | * `index` **[number][10]** 29 | * `title` **[string][11]** 30 | * `market` **PublicKey** 31 | * `prices` **(PublicKey | null)** 32 | * `priceLadder` **[Array][9]<[number][10]>** 33 | 34 | ## MarketOutcomeAccounts 35 | 36 | Type: {marketOutcomeAccounts: [Array][9]\>} 37 | 38 | ### Properties 39 | 40 | * `marketOutcomeAccounts` **[Array][9]\>** 41 | 42 | ## MarketOutcomeTitlesResponse 43 | 44 | Type: {marketOutcomeTitles: [Array][9]<[string][11]>} 45 | 46 | ### Properties 47 | 48 | * `marketOutcomeTitles` **[Array][9]<[string][11]>** 49 | 50 | [1]: #getpublickeys 51 | 52 | [2]: #properties 53 | 54 | [3]: #marketoutcomeaccount 55 | 56 | [4]: #properties-1 57 | 58 | [5]: #marketoutcomeaccounts 59 | 60 | [6]: #properties-2 61 | 62 | [7]: #marketoutcometitlesresponse 63 | 64 | [8]: #properties-3 65 | 66 | [9]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array 67 | 68 | [10]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number 69 | 70 | [11]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String 71 | -------------------------------------------------------------------------------- /npm-admin-client/docs/types/market_type.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Table of Contents 4 | 5 | * [MarketType][1] 6 | * [Properties][2] 7 | 8 | ## MarketType 9 | 10 | Type: {name: [string][3]} 11 | 12 | ### Properties 13 | 14 | * `name` **[string][3]** 15 | 16 | [1]: #markettype 17 | 18 | [2]: #properties 19 | 20 | [3]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String 21 | -------------------------------------------------------------------------------- /npm-admin-client/docs/types/operator.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Table of Contents 4 | 5 | * [Operator][1] 6 | * [AuthoriseOperatorResponse][2] 7 | * [Properties][3] 8 | * [AuthorisedOperatorsAccount][4] 9 | * [Properties][5] 10 | * [AuthorisedOperatorsAccountResponse][6] 11 | * [Properties][7] 12 | * [CheckOperatorRolesResponse][8] 13 | * [Properties][9] 14 | 15 | ## Operator 16 | 17 | ## AuthoriseOperatorResponse 18 | 19 | Type: {tnxId: [string][10], authorisedOperatorsPk: PublicKey, operatorPk: PublicKey} 20 | 21 | ### Properties 22 | 23 | * `tnxId` **[string][10]** 24 | * `authorisedOperatorsPk` **PublicKey** 25 | * `operatorPk` **PublicKey** 26 | 27 | ## AuthorisedOperatorsAccount 28 | 29 | Type: {authority: PublicKey, operatorList: [Array][11]\} 30 | 31 | ### Properties 32 | 33 | * `authority` **PublicKey** 34 | * `operatorList` **[Array][11]\** 35 | 36 | ## AuthorisedOperatorsAccountResponse 37 | 38 | Type: {publicKey: PublicKey, operatorsAccount: [AuthorisedOperatorsAccount][4]} 39 | 40 | ### Properties 41 | 42 | * `publicKey` **PublicKey** 43 | * `operatorsAccount` **[AuthorisedOperatorsAccount][4]** 44 | 45 | ## CheckOperatorRolesResponse 46 | 47 | Type: {operatorPk: PublicKey, admin: [boolean][12], market: [boolean][12], crank: [boolean][12]} 48 | 49 | ### Properties 50 | 51 | * `operatorPk` **PublicKey** 52 | * `admin` **[boolean][12]** 53 | * `market` **[boolean][12]** 54 | * `crank` **[boolean][12]** 55 | 56 | [1]: #operator 57 | 58 | [2]: #authoriseoperatorresponse 59 | 60 | [3]: #properties 61 | 62 | [4]: #authorisedoperatorsaccount 63 | 64 | [5]: #properties-1 65 | 66 | [6]: #authorisedoperatorsaccountresponse 67 | 68 | [7]: #properties-2 69 | 70 | [8]: #checkoperatorrolesresponse 71 | 72 | [9]: #properties-3 73 | 74 | [10]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String 75 | 76 | [11]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array 77 | 78 | [12]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean 79 | -------------------------------------------------------------------------------- /npm-admin-client/generate_docs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd $(dirname $0) 4 | 5 | declare -a endpoints=( 6 | "market_create" 7 | "market_management" 8 | "market_outcome_prices" 9 | "market_outcome" 10 | "market_type_create" 11 | "market_validate" 12 | "market_helpers" 13 | "operators" 14 | "price_ladder" 15 | "utils" 16 | ) 17 | 18 | declare -a types=( 19 | "client" 20 | "default_price_ladder" 21 | "markets" 22 | "market_type" 23 | "market_outcomes" 24 | "operator" 25 | ) 26 | 27 | npm run build 28 | wait 29 | 30 | createDocs(){ 31 | rm -R -f docs/${1}/${3}.md && 32 | echo "Generating docs for ${2}/${3}" && 33 | npm exec -- documentation build --document-exported ${2}/${3}.d.ts -f md >> docs/${1}/${3}.md 34 | } 35 | 36 | mkdir -p docs/endpoints 37 | for endpoint in ${endpoints[@]}; do 38 | createDocs "endpoints" "src" ${endpoint} & 39 | done 40 | 41 | mkdir -p docs/types 42 | for type in ${types[@]}; do 43 | createDocs "types" "types" ${type} & 44 | done 45 | 46 | wait 47 | -------------------------------------------------------------------------------- /npm-admin-client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@monaco-protocol/admin-client", 3 | "version": "13.0.0-dev", 4 | "description": "Admin interface package for the Monaco Protocol on Solana", 5 | "author": "Monaco Protocol", 6 | "license": "MIT", 7 | "repository": { 8 | "type": "git", 9 | "url": "git+https://github.com/MonacoProtocol/protocol.git", 10 | "directory": "npm-admin-client" 11 | }, 12 | "bugs": { 13 | "url": "https://github.com/MonacoProtocol/protocol/issues" 14 | }, 15 | "homepage": "https://github.com/MonacoProtocol/protocol/blob/main/npm-admin-client/README.md", 16 | "main": "src/index.js", 17 | "module": "src/index.js", 18 | "files": [ 19 | "/src", 20 | "/types" 21 | ], 22 | "scripts": { 23 | "test": "echo \"Error: no test specified\" && exit 1", 24 | "build": "tsc --downlevelIteration", 25 | "clean": "tsc --build --clean", 26 | "generateDocs": "./generate_docs.sh && npm run clean", 27 | "publishClient": "npm install && npm run build && npm publish --access public && npm run clean", 28 | "publishDevClient": "npm install && npm run build && npm publish --tag dev --access public && npm run clean", 29 | "publishRCClient": "npm install && npm run build && npm publish --tag rc --access public && npm run clean" 30 | }, 31 | "peerDependencies": { 32 | "bs58": "^4.0.1", 33 | "@coral-xyz/anchor": "~0.29.0", 34 | "@solana/spl-token": "^0.3.8", 35 | "@solana/web3.js": "^1.75.0", 36 | "typescript": "^4.5.4" 37 | }, 38 | "devDependencies": { 39 | "@types/bs58": "^4.0.1", 40 | "documentation": "^14.0.0" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /npm-admin-client/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./market_create"; 2 | export * from "./market_create_instruction"; 3 | export * from "./market_management_instructions"; 4 | export * from "./market_management"; 5 | export * from "./operators"; 6 | export * from "./market_outcome"; 7 | export * from "./market_outcome_instruction"; 8 | export * from "./market_outcome_prices"; 9 | export * from "./market_type_create"; 10 | export * from "./market_validate"; 11 | export * from "./market_helpers"; 12 | export * from "./price_ladder"; 13 | export * from "./utils"; 14 | export * from "../types"; 15 | -------------------------------------------------------------------------------- /npm-admin-client/src/market_type_create.ts: -------------------------------------------------------------------------------- 1 | import { Program } from "@coral-xyz/anchor"; 2 | import { PublicKey } from "@solana/web3.js"; 3 | import { 4 | ClientResponse, 5 | ResponseFactory, 6 | GetOrCreateAccountResponse, 7 | FindPdaResponse, 8 | } from "../types"; 9 | import { MarketType } from "../types/market_type"; 10 | 11 | export function findMarketTypePda( 12 | program: Program, 13 | marketType: string, 14 | ): ClientResponse { 15 | const responseFactory = new ResponseFactory({}); 16 | responseFactory.addResponseData({ 17 | pda: PublicKey.findProgramAddressSync( 18 | [Buffer.from("market_type"), Buffer.from(marketType)], 19 | program.programId, 20 | )[0], 21 | }); 22 | return responseFactory.body; 23 | } 24 | 25 | /** 26 | * For the given parameters: 27 | * 28 | * - Attempt to fetch and return a market type account with the given marketTypeName 29 | * - If no market type account is found, attempt to create and return a new market type with the given data. 30 | * 31 | * @param program {program} anchor program initialized by the consuming client 32 | * @param marketTypeName {string} name of the market type being fetched or created 33 | * @param requiresDiscriminator {boolean} if creating a new market type, whether the market type requires a discriminator to be set on markets using the type 34 | * @param requiresValue {boolean} if creating a new market type, whether the market type requires a value (e.g. a number) to be set on markets using the type 35 | * @returns {GetOrCreateAccountResponse} the market type account and public key - if a new account was created, also includes the transaction id 36 | * 37 | * @example 38 | * 39 | * const marketTypeName = "NewMarketType 40 | * const requiresDiscriminator = false; 41 | * const requiresValue = true; 42 | * const response = await getOrCreateMarketType(program, marketTypeName, requiresDiscriminator, requiresValue); 43 | */ 44 | export async function getOrCreateMarketType( 45 | program: Program, 46 | marketTypeName: string, 47 | requiresDiscriminator = false, 48 | requiresValue = false, 49 | ): Promise>> { 50 | const response = new ResponseFactory({}); 51 | 52 | let txId; 53 | let account; 54 | 55 | const publicKey = findMarketTypePda(program, marketTypeName).data.pda; 56 | 57 | try { 58 | account = await program.account.marketType.fetch(publicKey); 59 | } catch (_) { 60 | try { 61 | txId = await program.methods 62 | .createMarketType(marketTypeName, requiresDiscriminator, requiresValue) 63 | .accounts({ marketType: publicKey }) 64 | .rpc(); 65 | account = await program.account.marketType.fetch(publicKey); 66 | } catch (e) { 67 | response.addError(e); 68 | return response.body; 69 | } 70 | } 71 | 72 | response.addResponseData({ 73 | account, 74 | publicKey, 75 | txId, 76 | }); 77 | 78 | return response.body; 79 | } 80 | -------------------------------------------------------------------------------- /npm-admin-client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "allowJs": true, 6 | "declaration": true, 7 | "strict": true, 8 | "noImplicitAny": false, 9 | "esModuleInterop": true, 10 | "preserveConstEnums": true, 11 | "moduleResolution": "Node", 12 | "allowSyntheticDefaultImports": true, 13 | "baseUrl": "src", 14 | "downlevelIteration": true, 15 | "lib": ["es2022", "dom"], 16 | "skipLibCheck": true 17 | }, 18 | "include": ["./src/", "./types/"] 19 | } 20 | -------------------------------------------------------------------------------- /npm-admin-client/types/account.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey } from "@solana/web3.js"; 2 | 3 | export type AccountData = { 4 | publicKey: PublicKey; 5 | account: Account; 6 | }; 7 | 8 | export type GetAccount = AccountData; 9 | -------------------------------------------------------------------------------- /npm-admin-client/types/client.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey } from "@solana/web3.js"; 2 | 3 | export type ClientResponse = { 4 | success: boolean; 5 | errors: object[]; 6 | data: T; 7 | }; 8 | 9 | export type FindPdaResponse = { 10 | pda: PublicKey; 11 | }; 12 | 13 | /** 14 | * Helper to construct a client response object, each endpoint should return a response in this format 15 | * 16 | * @param opts.responseData empty object set to the response type 17 | * 18 | * @example 19 | * const response = new ResponseFactory({} as OrderAccounts); 20 | * try { 21 | * performAction() 22 | * } 23 | * catch (e) { 24 | * response.addError(e) 25 | * } 26 | * const secondaryRequest = separateRequest() 27 | * if (!secondaryRequest.success){ 28 | * response.addErrors(secondaryRequest.errors) 29 | * return response.body 30 | * } 31 | * response.addResponseData({ 32 | * orderPk: new PublicKey("Fy7WiqBy6MuWfnVjiPE8HQqkeLnyaLwBsk8cyyJ5WD8X") 33 | * }) 34 | * return response.body 35 | */ 36 | export class ResponseFactory { 37 | success: boolean; 38 | errors: object[]; 39 | data: any; 40 | 41 | constructor(opts) { 42 | this.success = true; 43 | this.errors = []; 44 | this.data = opts.responseData; 45 | } 46 | 47 | failure() { 48 | this.success = false; 49 | } 50 | 51 | /** 52 | * Add an error to the response body and mark the response as failed 53 | * 54 | * @param error {any} error to add, there is currently no type validation so anything can be pushed through 55 | */ 56 | addError(error) { 57 | this.errors.push(error); 58 | this.failure(); 59 | } 60 | 61 | /** 62 | * Add a errors to the response body and mark the response as failed, used primarily with previous client responses 63 | * 64 | * @param errors {any[]} errors array to add, there is currently no type validation so anything can be pushed through 65 | */ 66 | addErrors(errors) { 67 | this.errors.push(...errors); 68 | this.failure(); 69 | } 70 | 71 | /** 72 | * Add response data to the response following the format set with the constructor 73 | * 74 | * @param responseData {object} object making up part of or the whole of the expected responseData 75 | */ 76 | addResponseData(responseData: object) { 77 | this.data = { 78 | ...this.data, 79 | ...responseData, 80 | }; 81 | } 82 | 83 | get body() { 84 | return { 85 | success: this.success, 86 | errors: this.errors, 87 | data: this.data, 88 | }; 89 | } 90 | } 91 | 92 | /** 93 | * The transaction ID returned by a successful request 94 | */ 95 | export type TransactionResponse = { 96 | tnxId: string; 97 | }; 98 | 99 | export type TransactionBatchResponse = { 100 | tnxIds: string[]; 101 | }; 102 | -------------------------------------------------------------------------------- /npm-admin-client/types/default_price_ladder.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Price ladder that provides industry-standard price ranges for a market 3 | */ 4 | export const DEFAULT_PRICE_LADDER = [ 5 | 1.001, 1.002, 1.003, 1.004, 1.005, 1.006, 1.007, 1.008, 1.009, 1.01, 1.02, 6 | 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, 1.12, 1.13, 1.14, 1.15, 7 | 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 1.22, 1.23, 1.24, 1.25, 1.26, 1.27, 1.28, 8 | 1.29, 1.3, 1.31, 1.32, 1.33, 1.34, 1.35, 1.36, 1.37, 1.38, 1.39, 1.4, 1.41, 9 | 1.42, 1.43, 1.44, 1.45, 1.46, 1.47, 1.48, 1.49, 1.5, 1.51, 1.52, 1.53, 1.54, 10 | 1.55, 1.56, 1.57, 1.58, 1.59, 1.6, 1.61, 1.62, 1.63, 1.64, 1.65, 1.66, 1.67, 11 | 1.68, 1.69, 1.7, 1.71, 1.72, 1.73, 1.74, 1.75, 1.76, 1.77, 1.78, 1.79, 1.8, 12 | 1.81, 1.82, 1.83, 1.84, 1.85, 1.86, 1.87, 1.88, 1.89, 1.9, 1.91, 1.92, 1.93, 13 | 1.94, 1.95, 1.96, 1.97, 1.98, 1.99, 2, 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 14 | 2.07, 2.08, 2.09, 2.1, 2.11, 2.12, 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 15 | 2.2, 2.22, 2.24, 2.26, 2.28, 2.3, 2.32, 2.34, 2.36, 2.38, 2.4, 2.42, 2.44, 16 | 2.46, 2.48, 2.5, 2.52, 2.54, 2.56, 2.58, 2.6, 2.62, 2.64, 2.66, 2.68, 2.7, 17 | 2.72, 2.74, 2.76, 2.78, 2.8, 2.82, 2.84, 2.86, 2.88, 2.9, 2.92, 2.94, 2.96, 18 | 2.98, 3, 3.05, 3.1, 3.15, 3.2, 3.25, 3.3, 3.35, 3.4, 3.45, 3.5, 3.55, 3.6, 19 | 3.65, 3.7, 3.75, 3.8, 3.85, 3.9, 3.95, 4, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 20 | 4.8, 4.9, 5, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8, 5.9, 6, 6.2, 6.4, 6.6, 21 | 6.8, 7, 7.2, 7.4, 7.6, 7.8, 8, 8.2, 8.4, 8.6, 8.8, 9, 9.2, 9.4, 9.6, 9.8, 10, 22 | 10.5, 11, 11.5, 12, 12.5, 13, 13.5, 14, 14.5, 15, 15.5, 16, 16.5, 17, 17.5, 23 | 18, 18.5, 19, 19.5, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 32, 34, 36, 24 | 38, 40, 42, 44, 46, 48, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100, 110, 120, 25 | 130, 140, 150, 160, 170, 180, 190, 200, 210, 220, 230, 240, 250, 260, 270, 26 | 280, 290, 300, 320, 340, 360, 380, 400, 420, 440, 460, 480, 500, 550, 600, 27 | 650, 700, 750, 800, 900, 1000, 28 | ]; 29 | -------------------------------------------------------------------------------- /npm-admin-client/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./account"; 2 | export * from "./client"; 3 | export * from "./default_price_ladder"; 4 | export * from "./markets"; 5 | export * from "./market_type"; 6 | export * from "./market_outcomes"; 7 | export * from "./operator"; 8 | export * from "./transactions"; 9 | -------------------------------------------------------------------------------- /npm-admin-client/types/market_outcomes.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey } from "@solana/web3.js"; 2 | import { GetAccount } from "./account"; 3 | 4 | export type GetPublicKeys = { 5 | publicKeys: PublicKey[]; 6 | }; 7 | 8 | export type MarketOutcomeAccount = { 9 | index: number; 10 | title: string; 11 | market: PublicKey; 12 | prices: PublicKey | null; 13 | priceLadder: number[]; 14 | }; 15 | 16 | export type MarketOutcomeAccounts = { 17 | marketOutcomeAccounts: GetAccount[]; 18 | }; 19 | 20 | export type MarketOutcomeTitlesResponse = { 21 | marketOutcomeTitles: string[]; 22 | }; 23 | -------------------------------------------------------------------------------- /npm-admin-client/types/market_type.ts: -------------------------------------------------------------------------------- 1 | export type MarketType = { 2 | name: string; 3 | }; 4 | -------------------------------------------------------------------------------- /npm-admin-client/types/operator.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey } from "@solana/web3.js"; 2 | 3 | export enum Operator { 4 | MARKET = "MARKET", 5 | CRANK = "CRANK", 6 | ADMIN = "ADMIN", 7 | } 8 | 9 | export type AuthoriseOperatorResponse = { 10 | tnxId: string; 11 | authorisedOperatorsPk: PublicKey; 12 | operatorPk: PublicKey; 13 | }; 14 | 15 | export type AuthorisedOperatorsAccount = { 16 | authority: PublicKey; 17 | operatorList: PublicKey[]; 18 | }; 19 | 20 | export type AuthorisedOperatorsAccountResponse = { 21 | publicKey: PublicKey; 22 | operatorsAccount: AuthorisedOperatorsAccount; 23 | }; 24 | 25 | export type CheckOperatorRolesResponse = { 26 | operatorPk: PublicKey; 27 | admin: boolean; 28 | market: boolean; 29 | crank: boolean; 30 | }; 31 | -------------------------------------------------------------------------------- /npm-admin-client/types/transactions.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey, TransactionInstruction } from "@solana/web3.js"; 2 | import { web3 } from "@coral-xyz/anchor"; 3 | 4 | export type SignAndSendInstructionsResponse = { 5 | signature: web3.TransactionSignature; 6 | }; 7 | 8 | export type SignAndSendInstructionsBatchResponse = { 9 | signatures: web3.TransactionSignature[]; 10 | failedInstructions: TransactionInstruction[]; 11 | }; 12 | 13 | export type MarketInstructionResponse = { 14 | marketPk: PublicKey; 15 | instruction: TransactionInstruction; 16 | }; 17 | 18 | export type MarketOutcomeInstructionResponse = { 19 | outcome: string; 20 | outcomePda: PublicKey; 21 | instruction: TransactionInstruction; 22 | }; 23 | 24 | export type MarketOutcomesInstructionsResponse = { 25 | instructions: MarketInstructionResponse[]; 26 | }; 27 | 28 | export type TransactionOptions = { 29 | computeUnitLimit?: number; 30 | computeUnitPrice?: number; 31 | }; 32 | 33 | export type TransactionOptionsBatch = TransactionOptions & { 34 | batchSize?: number; 35 | confirmBatchSuccess?: boolean; 36 | }; 37 | -------------------------------------------------------------------------------- /npm-client/README.md: -------------------------------------------------------------------------------- 1 | # Monaco Protocol Client 2 | 3 | NPM package to interface with the Monaco Protocol program on the [Solana network](https://solana.com/developers). The Monaco Protocol provides a decentralized liquidity network for wagering on binary-outcome events. 4 | 5 | The package opens up the consumer-facing interactions with the protocol to facilitate exchanged-based applications including: 6 | 7 | - Get markets by status/event/wagering token 8 | - Place orders for markets 9 | - Cancel orders 10 | - Get market position for wallets 11 | - Get wallet token balances 12 | 13 | The package does not contain functionality to administer markets on the protocol. Admin functionality will be exposed through a separate package - coming soon. 14 | 15 | # Getting Started 16 | 17 | Examples for working with the client can be found in the [Monaco Protocol SDK Examples](https://github.com/MonacoProtocol/sdk/tree/main/examples) repository. 18 | 19 | # Documentation 20 | 21 | All endpoints exported by the library contain detailed doc strings and examples confirming to the JSDoc format. These doc strings can be viewed separately in the [docs](./docs/) directory. 22 | 23 | Supplementary documentation can be accessed from the [Monaco Protocol SDK](https://github.com/MonacoProtocol/sdk/tree/main/examples). 24 | 25 | ## Generating Docs 26 | 27 | Docs are generated using [documentationjs](https://github.com/documentationjs/documentation). 28 | 29 | ``` 30 | npm run generateDocs 31 | ``` 32 | 33 | # Client Response Format 34 | 35 | All endpoints in the client return the same response format: 36 | 37 | ``` 38 | export type ClientResponse = { 39 | success: boolean; 40 | errors: object[]; 41 | data: T; 42 | }; 43 | ``` 44 | 45 | Each endpoint defines its own data type used in the response, for example: `createOrderUiStake` returns `Promise>` 46 | 47 | ``` 48 | export type CreateOrderResponse = { 49 | orderPk: PublicKey; 50 | tnxID: string | void; 51 | }; 52 | ``` 53 | 54 | ## Errors 55 | 56 | Errors are purposely left loosely typed as an `object[]` so that the client can remain as agnostic as possible and pass through unfiltered errors regardless of origin. 57 | 58 | If any error is encountered during a request, the client will return `success: false` and data may come back `undefined`. 59 | -------------------------------------------------------------------------------- /npm-client/docs/endpoints/cancel_order_instruction.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Table of Contents 4 | 5 | * [buildCancelOrderInstruction][1] 6 | * [Parameters][2] 7 | * [Examples][3] 8 | * [buildCancelOrdersForMarketInstructions][4] 9 | * [Parameters][5] 10 | * [Examples][6] 11 | 12 | ## buildCancelOrderInstruction 13 | 14 | Constructs the instruction required to perform a cancel order transaction. 15 | 16 | ### Parameters 17 | 18 | * `program` **Program** {program} anchor program initialized by the consuming client 19 | * `orderPk` **PublicKey** {PublicKey} publicKey of the order to cancel 20 | * `mintPk` **PublicKey?** {PublicKey} Optional: publicKey of the mint account used for market entry (e.g. USDT), if not provided the market token account will be fetched from the market 21 | 22 | ### Examples 23 | 24 | ```javascript 25 | const orderPk = new PublicKey('Fy7WiqBy6MuWfnVjiPE8HQqkeLnyaLwBsk8cyyJ5WD8X') 26 | const instruction = await buildCancelOrderInstruction(program, orderPk) 27 | ``` 28 | 29 | Returns **OrderInstructionResponse** provided order publicKey and the instruction to perform a cancel order transaction 30 | 31 | ## buildCancelOrdersForMarketInstructions 32 | 33 | Constructs the instructions required to cancel all cancellable orders on the provided market. 34 | 35 | ### Parameters 36 | 37 | * `program` **Program** {program} anchor program initialized by the consuming client 38 | * `marketPk` **PublicKey** {PublicKey} publicKey of a market 39 | 40 | ### Examples 41 | 42 | ```javascript 43 | const marketPk = new PublicKey('7o1PXyYZtBBDFZf9cEhHopn2C9R4G6GaPwFAxaNWM33D') 44 | const orderInstructions = await buildCancelOrdersForMarketInstructions(program, marketPk) 45 | ``` 46 | 47 | Returns **OrderInstructionsResponse** List of provided order publicKeys and the associated instruction to perform a cancel order transaction for that order 48 | 49 | [1]: #buildcancelorderinstruction 50 | 51 | [2]: #parameters 52 | 53 | [3]: #examples 54 | 55 | [4]: #buildcancelordersformarketinstructions 56 | 57 | [5]: #parameters-1 58 | 59 | [6]: #examples-1 60 | -------------------------------------------------------------------------------- /npm-client/docs/endpoints/market_matching_pool_query.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Table of Contents 4 | 5 | * [MarketMatchingPools][1] 6 | 7 | ## MarketMatchingPools 8 | 9 | **Extends AccountQuery** 10 | 11 | [1]: #marketmatchingpools 12 | -------------------------------------------------------------------------------- /npm-client/docs/endpoints/market_outcome_query.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Table of Contents 4 | 5 | * [MarketOutcomes][1] 6 | * [Parameters][2] 7 | * [Examples][3] 8 | * [getMarketOutcomesByMarket][4] 9 | * [Parameters][5] 10 | * [Examples][6] 11 | * [getMarketOutcomeTitlesByMarket][7] 12 | * [Parameters][8] 13 | * [Examples][9] 14 | 15 | ## MarketOutcomes 16 | 17 | **Extends AccountQuery** 18 | 19 | Base market outcome query builder allowing to filter by set fields. Returns publicKeys or accounts mapped to those publicKeys; filtered to remove any accounts closed during the query process. 20 | 21 | Some preset queries are available for convenience: 22 | 23 | * getMarketOutcomesByMarket 24 | * getMarketOutcomeTitlesByMarket 25 | 26 | ### Parameters 27 | 28 | * `program` {program} anchor program initialized by the consuming client 29 | 30 | ### Examples 31 | 32 | ```javascript 33 | const marketPk = new PublicKey('7o1PXyYZtBBDFZf9cEhHopn2C9R4G6GaPwFAxaNWM33D') 34 | const marketOutcomes = await MarketOutcomes.marketOutcomeQuery(program) 35 | .filterByMarket(marketPk) 36 | .fetch(); 37 | 38 | Returns all market outcomes created for the given market. 39 | ``` 40 | 41 | ## getMarketOutcomesByMarket 42 | 43 | Get all market outcome accounts for the provided market. 44 | 45 | ### Parameters 46 | 47 | * `program` **Program** {program} anchor program initialized by the consuming client 48 | * `marketPk` **PublicKey** {PublicKey} publicKey of the market 49 | 50 | ### Examples 51 | 52 | ```javascript 53 | const marketPk = new PublicKey('7o1PXyYZtBBDFZf9cEhHopn2C9R4G6GaPwFAxaNWM33D') 54 | const marketOutcomes = await getMarketOutcomesByMarket(program, marketPk) 55 | ``` 56 | 57 | Returns **MarketOutcomeAccounts** fetched market outcome accounts mapped to their publicKey - ordered by index 58 | 59 | ## getMarketOutcomeTitlesByMarket 60 | 61 | Get all market outcome titles for the provided market. 62 | 63 | ### Parameters 64 | 65 | * `program` **Program** {program} anchor program initialized by the consuming client 66 | * `marketPk` **PublicKey** {PublicKey} publicKey of the market 67 | 68 | ### Examples 69 | 70 | ```javascript 71 | const marketPk = new PublicKey('7o1PXyYZtBBDFZf9cEhHopn2C9R4G6GaPwFAxaNWM33D') 72 | const marketOutcomeTitles = await getMarketOutcomeTitlesByMarket(program, marketPk) 73 | ``` 74 | 75 | Returns **MarketOutcomeTitlesResponse** fetched market outcome titles - ordered by index 76 | 77 | [1]: #marketoutcomes 78 | 79 | [2]: #parameters 80 | 81 | [3]: #examples 82 | 83 | [4]: #getmarketoutcomesbymarket 84 | 85 | [5]: #parameters-1 86 | 87 | [6]: #examples-1 88 | 89 | [7]: #getmarketoutcometitlesbymarket 90 | 91 | [8]: #parameters-2 92 | 93 | [9]: #examples-2 94 | -------------------------------------------------------------------------------- /npm-client/docs/endpoints/market_outcomes.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Table of Contents 4 | 5 | * [findMarketOutcomePda][1] 6 | * [Parameters][2] 7 | * [Examples][3] 8 | * [findMarketOutcomePdas][4] 9 | * [Parameters][5] 10 | * [Examples][6] 11 | 12 | ## findMarketOutcomePda 13 | 14 | For the provided market publicKey and market outcome index, return the PDA (publicKey) of the outcome account. 15 | 16 | ### Parameters 17 | 18 | * `program` **Program** {program} anchor program initialized by the consuming client 19 | * `marketPk` **PublicKey** {PublicKey} publicKey of a market 20 | * `marketOutcomeIndex` **[number][7]** {number} index representing a market outcome 21 | 22 | ### Examples 23 | 24 | ```javascript 25 | const marketPk = new PublicKey('7o1PXyYZtBBDFZf9cEhHopn2C9R4G6GaPwFAxaNWM33D') 26 | const marketOutcomeIndex = 0 27 | const marketOutcomePda = await findMarketOutcomePda(program, marketPK, marketOutcomeIndex) 28 | ``` 29 | 30 | Returns **FindPdaResponse** PDA of the market outcome account 31 | 32 | ## findMarketOutcomePdas 33 | 34 | For the provided market and market outcome indexes, return the PDAs (publicKeys) of the outcome accounts. 35 | 36 | ### Parameters 37 | 38 | * `program` **Program** {program} anchor program initialized by the consuming client 39 | * `marketPk` **PublicKey** {PublicKey} publicKey of the market to get market outcome accounts for 40 | * `marketOutcomeIndexes` **[Array][8]<[number][7]>** {number\[]} list of indexes representing market outcomes 41 | 42 | ### Examples 43 | 44 | ```javascript 45 | const marketPk = new PublicKey('7o1PXyYZtBBDFZf9cEhHopn2C9R4G6GaPwFAxaNWM33D') 46 | const marketOutcomeIndexes = [0, 1] 47 | const marketOutcomePdas = await findMarketOutcomePdas(program, marketPK, marketOutcomeIndexes) 48 | ``` 49 | 50 | Returns **GetPublicKeys** 51 | 52 | [1]: #findmarketoutcomepda 53 | 54 | [2]: #parameters 55 | 56 | [3]: #examples 57 | 58 | [4]: #findmarketoutcomepdas 59 | 60 | [5]: #parameters-1 61 | 62 | [6]: #examples-1 63 | 64 | [7]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number 65 | 66 | [8]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array 67 | -------------------------------------------------------------------------------- /npm-client/docs/endpoints/market_position_query.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Table of Contents 4 | 5 | * [MarketPositions][1] 6 | * [Parameters][2] 7 | * [Examples][3] 8 | 9 | ## MarketPositions 10 | 11 | **Extends AccountQuery** 12 | 13 | Base market position query builder allowing to filter by set fields. Returns publicKeys or accounts mapped to those publicKeys; filtered to remove any accounts closed during the query process. 14 | 15 | ### Parameters 16 | 17 | * `program` {program} anchor program initialized by the consuming client 18 | 19 | ### Examples 20 | 21 | ```javascript 22 | const marketPk = new PublicKey('7o1PXyYZtBBDFZf9cEhHopn2C9R4G6GaPwFAxaNWM33D') 23 | const marketPositions = await MarketPositions.marketPositionQuery(program) 24 | .filterByMarket(marketPk) 25 | .filterByPaid(false) 26 | .fetch(); 27 | 28 | Returns all market positions created for the given market that have not yet been paid out. 29 | ``` 30 | 31 | [1]: #marketpositions 32 | 33 | [2]: #parameters 34 | 35 | [3]: #examples 36 | -------------------------------------------------------------------------------- /npm-client/docs/endpoints/product_query.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Table of Contents 4 | 5 | * [Products][1] 6 | * [Parameters][2] 7 | * [Examples][3] 8 | 9 | ## Products 10 | 11 | **Extends AccountQuery** 12 | 13 | Base product query builder allowing to filter by set fields. Returns publicKeys or accounts mapped to those publicKeys; filtered to remove any accounts closed during the query process. 14 | 15 | ### Parameters 16 | 17 | * `program` {program} protocol\_product program initialized by the consuming client 18 | 19 | ### Examples 20 | 21 | ```javascript 22 | const authority = new PublicKey('7o1PXyYZtBBDFZf9cEhHopn2C9R4G6GaPwFAxaNWM33D') 23 | const payer = new PublicKey('5BZWY6XWPxuWFxs2jagkmUkCoBWmJ6c4YEArr83hYBWk') 24 | const products = await Products.productQuery(program) 25 | .filterByPayer(marketPk) 26 | .filterByAuthority(purchaserPk) 27 | .fetch(); 28 | 29 | // Returns all open product accounts for the specified payer and authority. 30 | ``` 31 | 32 | [1]: #products 33 | 34 | [2]: #parameters 35 | 36 | [3]: #examples 37 | -------------------------------------------------------------------------------- /npm-client/docs/endpoints/queries/account_query.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Table of Contents 4 | 5 | * [AccountQuery][1] 6 | 7 | ## AccountQuery 8 | 9 | [1]: #accountquery 10 | -------------------------------------------------------------------------------- /npm-client/docs/endpoints/trade.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Table of Contents 4 | 5 | * [findTradePda][1] 6 | * [Parameters][2] 7 | * [Examples][3] 8 | * [getTrade][4] 9 | * [Parameters][5] 10 | * [Examples][6] 11 | 12 | ## findTradePda 13 | 14 | For a given order PublicKey return a Program Derived Address (PDA) and the seed used. If a seed override is provided, it will be used instead of generating a new one. This PDA can be used for trade creation. 15 | 16 | ### Parameters 17 | 18 | * `program` **Program** {program} anchor program initialized by the consuming client 19 | * `orderPk` **PublicKey** {PublicKey} publicKey of the order 20 | * `existingTradeSeed` **[Uint8Array][7]?** {Uint8Array} (optional) distinctSeed of an existing trade 21 | 22 | ### Examples 23 | 24 | ```javascript 25 | const orderPk = new PublicKey('7o1PXyYZtBBDFZf9cEhHopn2C9R4G6GaPwFAxaNWM33D') 26 | const tradePda = await findTradePda(program, orderPk) 27 | ``` 28 | 29 | ```javascript 30 | const orderPk = new PublicKey('7o1PXyYZtBBDFZf9cEhHopn2C9R4G6GaPwFAxaNWM33D') 31 | const existingTradeSeed = Buffer.from("seed") 32 | const tradePda = await findTradePda(program, orderPk, existingTradeSeed) 33 | ``` 34 | 35 | Returns **TradePdaResponse** publicKey (PDA) and the seed used to generate it 36 | 37 | ## getTrade 38 | 39 | For the provided trade PublicKey, get the trade account. 40 | 41 | ### Parameters 42 | 43 | * `program` **Program** {program} anchor program initialized by the consuming client 44 | * `tradePk` **PublicKey** {PublicKey} publicKey of a trade 45 | 46 | ### Examples 47 | 48 | ```javascript 49 | const tradePk = new PublicKey('Fy7WiqBy6MuWfnVjiPE8HQqkeLnyaLwBsk8cyyJ5WD8X') 50 | const trade = await getTrade(program, tradePk) 51 | ``` 52 | 53 | Returns **Trade** trade account details 54 | 55 | [1]: #findtradepda 56 | 57 | [2]: #parameters 58 | 59 | [3]: #examples 60 | 61 | [4]: #gettrade 62 | 63 | [5]: #parameters-1 64 | 65 | [6]: #examples-1 66 | 67 | [7]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array 68 | -------------------------------------------------------------------------------- /npm-client/docs/types/account_query.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Table of Contents 4 | 5 | * [AccountResult][1] 6 | * [Properties][2] 7 | * [AccountQueryResult][3] 8 | * [Properties][4] 9 | 10 | ## AccountResult 11 | 12 | Type: {publicKey: PublicKey, accountInfo: AccountInfo<[Buffer][5]>, account: T} 13 | 14 | ### Properties 15 | 16 | * `publicKey` **PublicKey** 17 | * `accountInfo` **AccountInfo<[Buffer][5]>** 18 | * `account` **T** 19 | 20 | ## AccountQueryResult 21 | 22 | Type: {accounts: [Array][6]<[AccountResult][1]\>, slot: [number][7]} 23 | 24 | ### Properties 25 | 26 | * `accounts` **[Array][6]<[AccountResult][1]\>** 27 | * `slot` **[number][7]** 28 | 29 | [1]: #accountresult 30 | 31 | [2]: #properties 32 | 33 | [3]: #accountqueryresult 34 | 35 | [4]: #properties-1 36 | 37 | [5]: https://nodejs.org/api/buffer.html 38 | 39 | [6]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array 40 | 41 | [7]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number 42 | -------------------------------------------------------------------------------- /npm-client/docs/types/client.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Table of Contents 4 | 5 | * [ClientResponse][1] 6 | * [Properties][2] 7 | * [FindPdaResponse][3] 8 | * [Properties][4] 9 | * [ResponseFactory][5] 10 | * [Examples][6] 11 | * [success][7] 12 | * [errors][8] 13 | * [data][9] 14 | 15 | ## ClientResponse 16 | 17 | Type: {success: [boolean][10], errors: [Array][11]<[object][12]>, data: T} 18 | 19 | ### Properties 20 | 21 | * `success` **[boolean][10]** 22 | * `errors` **[Array][11]<[object][12]>** 23 | * `data` **T** 24 | 25 | ## FindPdaResponse 26 | 27 | Type: {pda: PublicKey} 28 | 29 | ### Properties 30 | 31 | * `pda` **PublicKey** 32 | 33 | ## ResponseFactory 34 | 35 | Helper to construct a client response object, each endpoint should return a response in this format 36 | 37 | ### Examples 38 | 39 | ```javascript 40 | const response = new ResponseFactory({} as OrderAccounts); 41 | try { 42 | performAction() 43 | } 44 | catch (e) { 45 | response.addError(e) 46 | } 47 | const secondaryRequest = separateRequest() 48 | if (!secondaryRequest.success){ 49 | response.addErrors(secondaryRequest.errors) 50 | return response.body 51 | } 52 | response.addResponseData({ 53 | orderPk: new PublicKey("Fy7WiqBy6MuWfnVjiPE8HQqkeLnyaLwBsk8cyyJ5WD8X") 54 | }) 55 | return response.body 56 | ``` 57 | 58 | ### success 59 | 60 | Type: [boolean][10] 61 | 62 | ### errors 63 | 64 | Type: [Array][11]<[object][12]> 65 | 66 | ### data 67 | 68 | Type: any 69 | 70 | [1]: #clientresponse 71 | 72 | [2]: #properties 73 | 74 | [3]: #findpdaresponse 75 | 76 | [4]: #properties-1 77 | 78 | [5]: #responsefactory 79 | 80 | [6]: #examples 81 | 82 | [7]: #success 83 | 84 | [8]: #errors 85 | 86 | [9]: #data 87 | 88 | [10]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean 89 | 90 | [11]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array 91 | 92 | [12]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object 93 | -------------------------------------------------------------------------------- /npm-client/docs/types/default_price_ladder.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Table of Contents 4 | 5 | * [DEFAULT\_PRICE\_LADDER][1] 6 | 7 | ## DEFAULT\_PRICE\_LADDER 8 | 9 | Price ladder that provides industry-standard price ranges for a market 10 | 11 | Type: [Array][2]<[number][3]> 12 | 13 | [1]: #default_price_ladder 14 | 15 | [2]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array 16 | 17 | [3]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number 18 | -------------------------------------------------------------------------------- /npm-client/docs/types/errors.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Table of Contents 4 | 5 | * [ClientError][1] 6 | * [Properties][2] 7 | * [NoCancellableOrdersFound][3] 8 | 9 | ## ClientError 10 | 11 | Type: {errorCode: [string][4], errorMessage: ClientErrors} 12 | 13 | ### Properties 14 | 15 | * `errorCode` **[string][4]** 16 | * `errorMessage` **ClientErrors** 17 | 18 | ## NoCancellableOrdersFound 19 | 20 | Type: [ClientError][1] 21 | 22 | [1]: #clienterror 23 | 24 | [2]: #properties 25 | 26 | [3]: #nocancellableordersfound 27 | 28 | [4]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String 29 | -------------------------------------------------------------------------------- /npm-client/docs/types/get_account.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Table of Contents 4 | 5 | * [AccountData][1] 6 | * [Properties][2] 7 | * [GetAccount][3] 8 | * [GetAccounts][4] 9 | * [GetPublicKeys][5] 10 | * [Properties][6] 11 | 12 | ## AccountData 13 | 14 | Type: {publicKey: PublicKey, account: Account} 15 | 16 | ### Properties 17 | 18 | * `publicKey` **PublicKey** 19 | * `account` **Account** 20 | 21 | ## GetAccount 22 | 23 | Type: [AccountData][1]\ 24 | 25 | ## GetAccounts 26 | 27 | Type: [Array][7]<[AccountData][1]\> 28 | 29 | ## GetPublicKeys 30 | 31 | Type: {publicKeys: [Array][7]\} 32 | 33 | ### Properties 34 | 35 | * `publicKeys` **[Array][7]\** 36 | 37 | [1]: #accountdata 38 | 39 | [2]: #properties 40 | 41 | [3]: #getaccount 42 | 43 | [4]: #getaccounts 44 | 45 | [5]: #getpublickeys 46 | 47 | [6]: #properties-1 48 | 49 | [7]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array 50 | -------------------------------------------------------------------------------- /npm-client/docs/types/market_position.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Table of Contents 4 | 5 | * [MarketPosition][1] 6 | * [Properties][2] 7 | * [MarketPositionAccounts][3] 8 | * [Properties][4] 9 | * [ProductMatchedRiskAndRate][5] 10 | * [Properties][6] 11 | 12 | ## MarketPosition 13 | 14 | Type: {purchaser: PublicKey, market: PublicKey, paid: [boolean][7], marketOutcomeSums: [Array][8]\, unmatchedExposures: [Array][8]\, outcomePositions: [Map][9]<[string][10], BN>, payer: PublicKey, matchedRisk: BN, matchedRiskPerProduct: [Array][8]<[ProductMatchedRiskAndRate][5]>} 15 | 16 | ### Properties 17 | 18 | * `purchaser` **PublicKey** 19 | * `market` **PublicKey** 20 | * `paid` **[boolean][7]** 21 | * `marketOutcomeSums` **[Array][8]\** 22 | * `unmatchedExposures` **[Array][8]\** 23 | * `outcomePositions` **[Map][9]<[string][10], BN>** 24 | * `payer` **PublicKey** 25 | * `matchedRisk` **BN** 26 | * `matchedRiskPerProduct` **[Array][8]<[ProductMatchedRiskAndRate][5]>** 27 | 28 | ## MarketPositionAccounts 29 | 30 | Type: {marketPositionAccounts: [Array][8]\>} 31 | 32 | ### Properties 33 | 34 | * `marketPositionAccounts` **[Array][8]\>** 35 | 36 | ## ProductMatchedRiskAndRate 37 | 38 | Type: {product: PublicKey, risk: BN, rate: [number][11]} 39 | 40 | ### Properties 41 | 42 | * `product` **PublicKey** 43 | * `risk` **BN** 44 | * `rate` **[number][11]** 45 | 46 | [1]: #marketposition 47 | 48 | [2]: #properties 49 | 50 | [3]: #marketpositionaccounts 51 | 52 | [4]: #properties-1 53 | 54 | [5]: #productmatchedriskandrate 55 | 56 | [6]: #properties-2 57 | 58 | [7]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean 59 | 60 | [8]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array 61 | 62 | [9]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Map 63 | 64 | [10]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String 65 | 66 | [11]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number 67 | -------------------------------------------------------------------------------- /npm-client/docs/types/matching_pool.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Table of Contents 4 | -------------------------------------------------------------------------------- /npm-client/docs/types/product.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Table of Contents 4 | 5 | * [Product][1] 6 | * [Properties][2] 7 | * [CreateProductResponse][3] 8 | * [Properties][4] 9 | * [ProductAccounts][5] 10 | * [Properties][6] 11 | 12 | ## Product 13 | 14 | Type: {authority: PublicKey, payer: PublicKey, commissionEscrow: PublicKey, productTitle: [string][7], commissionRate: [number][8]} 15 | 16 | ### Properties 17 | 18 | * `authority` **PublicKey** 19 | * `payer` **PublicKey** 20 | * `commissionEscrow` **PublicKey** 21 | * `productTitle` **[string][7]** 22 | * `commissionRate` **[number][8]** 23 | 24 | ## CreateProductResponse 25 | 26 | Type: {productPk: PublicKey, tnxID: ([string][7] | void)} 27 | 28 | ### Properties 29 | 30 | * `productPk` **PublicKey** 31 | * `tnxID` **([string][7] | void)** 32 | 33 | ## ProductAccounts 34 | 35 | Type: {productAccounts: [Array][9]\>} 36 | 37 | ### Properties 38 | 39 | * `productAccounts` **[Array][9]\>** 40 | 41 | [1]: #product 42 | 43 | [2]: #properties 44 | 45 | [3]: #createproductresponse 46 | 47 | [4]: #properties-1 48 | 49 | [5]: #productaccounts 50 | 51 | [6]: #properties-2 52 | 53 | [7]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String 54 | 55 | [8]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number 56 | 57 | [9]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array 58 | -------------------------------------------------------------------------------- /npm-client/docs/types/trade.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Table of Contents 4 | 5 | * [Trade][1] 6 | * [Properties][2] 7 | * [TradeAccounts][3] 8 | * [Properties][4] 9 | * [CreateTradeResponse][5] 10 | * [Properties][6] 11 | * [TradePdaResponse][7] 12 | * [Properties][8] 13 | 14 | ## Trade 15 | 16 | Type: {purchaser: PublicKey, market: PublicKey, order: PublicKey, marketOutcomeIndex: [number][9], forOutcome: [boolean][10], stake: BN, price: [number][9], creationTimestamp: BN, payer: PublicKey} 17 | 18 | ### Properties 19 | 20 | * `purchaser` **PublicKey** 21 | * `market` **PublicKey** 22 | * `order` **PublicKey** 23 | * `marketOutcomeIndex` **[number][9]** 24 | * `forOutcome` **[boolean][10]** 25 | * `stake` **BN** 26 | * `price` **[number][9]** 27 | * `creationTimestamp` **BN** 28 | * `payer` **PublicKey** 29 | 30 | ## TradeAccounts 31 | 32 | Type: {tradeAccounts: [Array][11]\>} 33 | 34 | ### Properties 35 | 36 | * `tradeAccounts` **[Array][11]\>** 37 | 38 | ## CreateTradeResponse 39 | 40 | Type: {tradePk: PublicKey, tnxID: ([string][12] | void)} 41 | 42 | ### Properties 43 | 44 | * `tradePk` **PublicKey** 45 | * `tnxID` **([string][12] | void)** 46 | 47 | ## TradePdaResponse 48 | 49 | Type: {tradePk: PublicKey, distinctSeed: [Uint8Array][13]} 50 | 51 | ### Properties 52 | 53 | * `tradePk` **PublicKey** 54 | * `distinctSeed` **[Uint8Array][13]** 55 | 56 | [1]: #trade 57 | 58 | [2]: #properties 59 | 60 | [3]: #tradeaccounts 61 | 62 | [4]: #properties-1 63 | 64 | [5]: #createtraderesponse 65 | 66 | [6]: #properties-2 67 | 68 | [7]: #tradepdaresponse 69 | 70 | [8]: #properties-3 71 | 72 | [9]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number 73 | 74 | [10]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean 75 | 76 | [11]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array 77 | 78 | [12]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String 79 | 80 | [13]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array 81 | -------------------------------------------------------------------------------- /npm-client/docs/types/transactions.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Table of Contents 4 | 5 | * [SignAndSendInstructionsResponse][1] 6 | * [Properties][2] 7 | * [SignAndSendInstructionsBatchResponse][3] 8 | * [Properties][4] 9 | 10 | ## SignAndSendInstructionsResponse 11 | 12 | Type: {signature: web3.TransactionSignature} 13 | 14 | ### Properties 15 | 16 | * `signature` **web3.TransactionSignature** 17 | 18 | ## SignAndSendInstructionsBatchResponse 19 | 20 | Type: {signatures: [Array][5]\, failedInstructions: [Array][5]\} 21 | 22 | ### Properties 23 | 24 | * `signatures` **[Array][5]\** 25 | * `failedInstructions` **[Array][5]\** 26 | 27 | [1]: #signandsendinstructionsresponse 28 | 29 | [2]: #properties 30 | 31 | [3]: #signandsendinstructionsbatchresponse 32 | 33 | [4]: #properties-1 34 | 35 | [5]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array 36 | -------------------------------------------------------------------------------- /npm-client/docs/types/wallet_tokens.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Table of Contents 4 | 5 | * [GetWalletTokenAccountResponse][1] 6 | * [Properties][2] 7 | * [GetWalletTokenAccountsResponse][3] 8 | * [Properties][4] 9 | * [GetWalletBalanceResponse][5] 10 | * [Properties][6] 11 | * [GetWalletBalancesResponse][7] 12 | * [Properties][8] 13 | 14 | ## GetWalletTokenAccountResponse 15 | 16 | Type: {tokenMint: PublicKey, associatedTokenAccount: PublicKey} 17 | 18 | ### Properties 19 | 20 | * `tokenMint` **PublicKey** 21 | * `associatedTokenAccount` **PublicKey** 22 | 23 | ## GetWalletTokenAccountsResponse 24 | 25 | Type: {accounts: [Array][9]<[GetWalletTokenAccountResponse][1]>} 26 | 27 | ### Properties 28 | 29 | * `accounts` **[Array][9]<[GetWalletTokenAccountResponse][1]>** 30 | 31 | ## GetWalletBalanceResponse 32 | 33 | Type: {token: [string][10], balance: TokenAmount} 34 | 35 | ### Properties 36 | 37 | * `token` **[string][10]** 38 | * `balance` **TokenAmount** 39 | 40 | ## GetWalletBalancesResponse 41 | 42 | Type: {balances: [Array][9]<[GetWalletBalanceResponse][5]>} 43 | 44 | ### Properties 45 | 46 | * `balances` **[Array][9]<[GetWalletBalanceResponse][5]>** 47 | 48 | [1]: #getwallettokenaccountresponse 49 | 50 | [2]: #properties 51 | 52 | [3]: #getwallettokenaccountsresponse 53 | 54 | [4]: #properties-1 55 | 56 | [5]: #getwalletbalanceresponse 57 | 58 | [6]: #properties-2 59 | 60 | [7]: #getwalletbalancesresponse 61 | 62 | [8]: #properties-3 63 | 64 | [9]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array 65 | 66 | [10]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String 67 | -------------------------------------------------------------------------------- /npm-client/generate_docs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd $(dirname $0) 4 | 5 | declare -a endpoints=( 6 | "queries/account_query" 7 | "order" 8 | "order_query" 9 | "cancel_order" 10 | "cancel_order_instruction" 11 | "create_order_instruction" 12 | "create_order" 13 | "market_matching_pools" 14 | "market_matching_pool_query" 15 | "market_outcomes" 16 | "market_outcome_query" 17 | "market_position" 18 | "market_position_query" 19 | "market_prices" 20 | "markets" 21 | "market_query" 22 | "product" 23 | "product_query" 24 | "trade" 25 | "trade_query" 26 | "utils" 27 | "wallet_tokens" 28 | ) 29 | 30 | declare -a types=( 31 | "account_query" 32 | "order" 33 | "client" 34 | "default_price_ladder" 35 | "errors" 36 | "get_account" 37 | "market_position" 38 | "market" 39 | "matching_pool" 40 | "product" 41 | "protocol" 42 | "trade" 43 | "wallet_tokens" 44 | "transactions" 45 | ) 46 | 47 | npm run build 48 | wait 49 | 50 | createDocs(){ 51 | rm -R -f docs/${1}/${3}.md && 52 | mkdir -p `dirname docs/${1}/${3}.md` 53 | echo "Generating docs for ${2}/${3}" && 54 | npm exec -- documentation build --document-exported ${2}/${3}.d.ts -f md >> docs/${1}/${3}.md 55 | } 56 | 57 | mkdir -p docs/endpoints 58 | for endpoint in ${endpoints[@]}; do 59 | createDocs "endpoints" "src" ${endpoint} & 60 | done 61 | 62 | mkdir -p docs/types 63 | for type in ${types[@]}; do 64 | createDocs "types" "types" ${type} & 65 | done 66 | 67 | wait 68 | -------------------------------------------------------------------------------- /npm-client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@monaco-protocol/client", 3 | "version": "13.0.0-dev", 4 | "description": "Interface package for the Monaco Protocol on Solana", 5 | "author": "Monaco Protocol", 6 | "license": "MIT", 7 | "repository": { 8 | "type": "git", 9 | "url": "git+https://github.com/MonacoProtocol/protocol.git", 10 | "directory": "npm-client" 11 | }, 12 | "bugs": { 13 | "url": "https://github.com/MonacoProtocol/protocol/issues" 14 | }, 15 | "homepage": "https://github.com/MonacoProtocol/protocol/blob/main/npm-client/README.md", 16 | "main": "src/index.js", 17 | "module": "src/index.js", 18 | "files": [ 19 | "/src", 20 | "/types" 21 | ], 22 | "scripts": { 23 | "build": "tsc --downlevelIteration", 24 | "clean": "tsc --build --clean", 25 | "generateDocs": "./generate_docs.sh", 26 | "publishClient": "npm install && npm run build && npm publish --access public && npm run clean", 27 | "publishDevClient": "npm install && npm run build && npm publish --tag dev --access public && npm run clean", 28 | "publishRCClient": "npm install && npm run build && npm publish --tag rc --access public && npm run clean" 29 | }, 30 | "peerDependencies": { 31 | "@coral-xyz/anchor": "~0.29.0", 32 | "@solana/spl-token": "^0.3.8", 33 | "@solana/web3.js": "^1.75.0", 34 | "bs58": "^4.0.1", 35 | "typescript": "^4.5.4", 36 | "uuid": "^9.0.0" 37 | }, 38 | "devDependencies": { 39 | "@types/bs58": "^4.0.1", 40 | "documentation": "^14.0.0" 41 | }, 42 | "dependencies": { 43 | "big.js": "^6.2.1" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /npm-client/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./order"; 2 | export * from "./order_query"; 3 | export * from "./wallet_tokens"; 4 | export * from "./market_position"; 5 | export * from "./create_order_instruction"; 6 | export * from "./create_order"; 7 | export * from "./cancel_order_instruction"; 8 | export * from "./cancel_order"; 9 | export * from "./markets"; 10 | export * from "./market_commission_payment_queues"; 11 | export * from "./market_liquidities"; 12 | export * from "./market_matching_pools"; 13 | export * from "./market_matching_queues"; 14 | export * from "./market_matching_pool_query"; 15 | export * from "./market_order_request_queues"; 16 | export * from "./market_outcomes"; 17 | export * from "./market_outcome_query"; 18 | export * from "./market_position"; 19 | export * from "./market_position_query"; 20 | export * from "./market_prices"; 21 | export * from "./market_query"; 22 | export * from "./product"; 23 | export * from "./product_query"; 24 | export * from "./trade"; 25 | export * from "./trade_query"; 26 | export * from "./utils"; 27 | export * from "../types/index"; 28 | -------------------------------------------------------------------------------- /npm-client/src/market_matching_pool_query.ts: -------------------------------------------------------------------------------- 1 | import { MarketMatchingPoolAccount } from "../types"; 2 | import { 3 | BooleanCriterion, 4 | PublicKeyCriterion, 5 | U16Criterion, 6 | } from "./queries/filtering"; 7 | import { Program } from "@coral-xyz/anchor"; 8 | import { PublicKey } from "@solana/web3.js"; 9 | import { AccountQuery } from "./queries/account_query"; 10 | 11 | export class MarketMatchingPools extends AccountQuery { 12 | public static marketMatchingPoolQuery(program: Program) { 13 | return new MarketMatchingPools(program); 14 | } 15 | 16 | private market: PublicKeyCriterion = new PublicKeyCriterion(8); 17 | private marketOutcomeIndex: U16Criterion = new U16Criterion(8 + 32); 18 | private forOutcome: BooleanCriterion = new BooleanCriterion(8 + 32 + 2); 19 | 20 | constructor(program: Program) { 21 | super(program, "MarketMatchingPool"); 22 | this.setFilterCriteria( 23 | this.market, 24 | this.marketOutcomeIndex, 25 | this.forOutcome, 26 | ); 27 | } 28 | 29 | filterByMarket(market: PublicKey): MarketMatchingPools { 30 | this.market.setValue(market); 31 | return this; 32 | } 33 | 34 | filterByMarketOutcomeIndex(marketOutcomeIndex: number): MarketMatchingPools { 35 | this.marketOutcomeIndex.setValue(marketOutcomeIndex); 36 | return this; 37 | } 38 | 39 | filterByForOutcome(forOutcome: boolean): MarketMatchingPools { 40 | this.forOutcome.setValue(forOutcome); 41 | return this; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /npm-client/src/market_position_query.ts: -------------------------------------------------------------------------------- 1 | import { Program } from "@coral-xyz/anchor"; 2 | import { MemcmpFilter, PublicKey } from "@solana/web3.js"; 3 | import { MarketPosition } from "../types"; 4 | import { AccountQuery } from "./queries/account_query"; 5 | import { BooleanCriterion, PublicKeyCriterion } from "./queries/filtering"; 6 | /** 7 | * Base market position query builder allowing to filter by set fields. Returns publicKeys or accounts mapped to those publicKeys; filtered to remove any accounts closed during the query process. 8 | * 9 | * @param program {program} anchor program initialized by the consuming client 10 | * @returns {GetPublicKeys || MarketPositionAccounts} publicKeys or accounts meeting query requirements filtered to remove any accounts closed during the query process 11 | * 12 | * @example 13 | * 14 | * const marketPk = new PublicKey('7o1PXyYZtBBDFZf9cEhHopn2C9R4G6GaPwFAxaNWM33D') 15 | * const marketPositions = await MarketPositions.marketPositionQuery(program) 16 | * .filterByMarket(marketPk) 17 | * .filterByPaid(false) 18 | * .fetch(); 19 | * 20 | * Returns all market positions created for the given market that have not yet been paid out. 21 | */ 22 | export class MarketPositions extends AccountQuery { 23 | public static marketPositionQuery(program: Program) { 24 | return new MarketPositions(program); 25 | } 26 | 27 | private purchaser = new PublicKeyCriterion(8); 28 | private market = new PublicKeyCriterion(8 + 32); 29 | private paid = new BooleanCriterion(8 + 32 + 32); 30 | 31 | constructor(program: Program) { 32 | super(program, "MarketPosition"); 33 | this.setFilterCriteria(this.purchaser, this.market, this.paid); 34 | } 35 | 36 | private toFilter(offset: number, bytes: string): MemcmpFilter { 37 | return { memcmp: { offset: offset, bytes: bytes } }; 38 | } 39 | 40 | filterByPurchaser(purchaser: PublicKey): MarketPositions { 41 | this.purchaser.setValue(purchaser); 42 | return this; 43 | } 44 | 45 | filterByMarket(market: PublicKey): MarketPositions { 46 | this.market.setValue(market); 47 | return this; 48 | } 49 | filterByPaid(paid: boolean): MarketPositions { 50 | this.paid.setValue(paid); 51 | return this; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /npm-client/src/product_query.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey } from "@solana/web3.js"; 2 | import { Program } from "@coral-xyz/anchor"; 3 | import { PublicKeyCriterion } from "./queries/filtering"; 4 | import { Product } from "../types/product"; 5 | import { AccountQuery } from "./queries/account_query"; 6 | 7 | /** 8 | * Base product query builder allowing to filter by set fields. Returns publicKeys or accounts mapped to those publicKeys; filtered to remove any accounts closed during the query process. 9 | * 10 | * @param program {program} protocol_product program initialized by the consuming client 11 | * @returns {GetPublicKeys || ProductAccounts} publicKeys or accounts meeting query requirements 12 | * 13 | * @example 14 | * 15 | * const authority = new PublicKey('7o1PXyYZtBBDFZf9cEhHopn2C9R4G6GaPwFAxaNWM33D') 16 | * const payer = new PublicKey('5BZWY6XWPxuWFxs2jagkmUkCoBWmJ6c4YEArr83hYBWk') 17 | * const products = await Products.productQuery(program) 18 | * .filterByPayer(marketPk) 19 | * .filterByAuthority(purchaserPk) 20 | * .fetch(); 21 | * 22 | * // Returns all open product accounts for the specified payer and authority. 23 | */ 24 | export class Products extends AccountQuery { 25 | public static productQuery(program: Program) { 26 | return new Products(program); 27 | } 28 | 29 | private authority: PublicKeyCriterion = new PublicKeyCriterion(8); 30 | private payer: PublicKeyCriterion = new PublicKeyCriterion(8 + 32); 31 | 32 | constructor(program: Program) { 33 | super(program, "Product"); 34 | this.setFilterCriteria(this.authority, this.payer); 35 | } 36 | 37 | filterByAuthority(authority: PublicKey): Products { 38 | this.authority.setValue(authority); 39 | return this; 40 | } 41 | 42 | filterByPayer(payer: PublicKey): Products { 43 | this.payer.setValue(payer); 44 | return this; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /npm-client/src/trade.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey } from "@solana/web3.js"; 2 | import { Program } from "@coral-xyz/anchor"; 3 | import { 4 | ClientResponse, 5 | GetAccount, 6 | ResponseFactory, 7 | Trade, 8 | TradePdaResponse, 9 | } from "../types"; 10 | import { randomSeed16 } from "./utils"; 11 | 12 | /** 13 | * For a given order PublicKey return a Program Derived Address (PDA) and the seed used. If a seed override is provided, it will be used instead of generating a new one. This PDA can be used for trade creation. 14 | * 15 | * @param program {program} anchor program initialized by the consuming client 16 | * @param orderPk {PublicKey} publicKey of the order 17 | * @param existingTradeSeed {Uint8Array} (optional) distinctSeed of an existing trade 18 | * @returns {TradePdaResponse} publicKey (PDA) and the seed used to generate it 19 | * 20 | * @example 21 | * 22 | * const orderPk = new PublicKey('7o1PXyYZtBBDFZf9cEhHopn2C9R4G6GaPwFAxaNWM33D') 23 | * const tradePda = await findTradePda(program, orderPk) 24 | * 25 | * @example 26 | * 27 | * const orderPk = new PublicKey('7o1PXyYZtBBDFZf9cEhHopn2C9R4G6GaPwFAxaNWM33D') 28 | * const existingTradeSeed = Buffer.from("seed") 29 | * const tradePda = await findTradePda(program, orderPk, existingTradeSeed) 30 | */ 31 | export async function findTradePda( 32 | program: Program, 33 | orderPk: PublicKey, 34 | existingTradeSeed?: Uint8Array, 35 | ): Promise> { 36 | const response = new ResponseFactory({} as TradePdaResponse); 37 | 38 | const distinctSeed = existingTradeSeed ? existingTradeSeed : randomSeed16(); 39 | 40 | try { 41 | const [tradePk, _] = PublicKey.findProgramAddressSync( 42 | [orderPk.toBuffer(), distinctSeed], 43 | program.programId, 44 | ); 45 | 46 | response.addResponseData({ 47 | tradePk: tradePk, 48 | distinctSeed: distinctSeed, 49 | }); 50 | } catch (e) { 51 | response.addError(e); 52 | } 53 | 54 | return response.body; 55 | } 56 | 57 | /** 58 | * For the provided trade PublicKey, get the trade account. 59 | * 60 | * @param program {program} anchor program initialized by the consuming client 61 | * @param tradePk {PublicKey} publicKey of a trade 62 | * @returns {Trade} trade account details 63 | * 64 | * @example 65 | * 66 | * const tradePk = new PublicKey('Fy7WiqBy6MuWfnVjiPE8HQqkeLnyaLwBsk8cyyJ5WD8X') 67 | * const trade = await getTrade(program, tradePk) 68 | */ 69 | export async function getTrade( 70 | program: Program, 71 | tradePk: PublicKey, 72 | ): Promise>> { 73 | const response = new ResponseFactory({} as GetAccount); 74 | try { 75 | const trade = (await program.account.trade.fetch(tradePk)) as Trade; 76 | response.addResponseData({ 77 | publicKey: tradePk, 78 | account: trade, 79 | }); 80 | } catch (e) { 81 | response.addError(e); 82 | } 83 | return response.body; 84 | } 85 | -------------------------------------------------------------------------------- /npm-client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2019", 4 | "lib": ["ES2019"], 5 | "module": "commonjs", 6 | "allowJs": true, 7 | "declaration": true, 8 | "strict": true, 9 | "noImplicitAny": false, 10 | "esModuleInterop": true, 11 | "preserveConstEnums": true, 12 | "moduleResolution": "Node", 13 | "allowSyntheticDefaultImports": true, 14 | "baseUrl": "src", 15 | "downlevelIteration": true, 16 | "skipLibCheck": true 17 | }, 18 | "include": ["./src/", "./types/"] 19 | } 20 | -------------------------------------------------------------------------------- /npm-client/types/account_query.ts: -------------------------------------------------------------------------------- 1 | import { AccountInfo, PublicKey } from "@solana/web3.js"; 2 | 3 | export type AccountResult = { 4 | publicKey: PublicKey; 5 | accountInfo: AccountInfo; 6 | account: T; 7 | }; 8 | 9 | export type AccountQueryResult = { 10 | accounts: AccountResult[]; 11 | slot: number; 12 | }; 13 | -------------------------------------------------------------------------------- /npm-client/types/client.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey } from "@solana/web3.js"; 2 | 3 | export type ClientResponse = { 4 | success: boolean; 5 | errors: object[]; 6 | data: T; 7 | }; 8 | 9 | export type FindPdaResponse = { 10 | pda: PublicKey; 11 | }; 12 | 13 | /** 14 | * Helper to construct a client response object, each endpoint should return a response in this format 15 | * 16 | * @param opts.responseData empty object set to the response type 17 | * 18 | * @example 19 | * const response = new ResponseFactory({} as OrderAccounts); 20 | * try { 21 | * performAction() 22 | * } 23 | * catch (e) { 24 | * response.addError(e) 25 | * } 26 | * const secondaryRequest = separateRequest() 27 | * if (!secondaryRequest.success){ 28 | * response.addErrors(secondaryRequest.errors) 29 | * return response.body 30 | * } 31 | * response.addResponseData({ 32 | * orderPk: new PublicKey("Fy7WiqBy6MuWfnVjiPE8HQqkeLnyaLwBsk8cyyJ5WD8X") 33 | * }) 34 | * return response.body 35 | */ 36 | export class ResponseFactory { 37 | success: boolean; 38 | errors: object[]; 39 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 40 | data: any; 41 | 42 | constructor(opts) { 43 | this.success = true; 44 | this.errors = []; 45 | this.data = opts.responseData; 46 | } 47 | 48 | failure() { 49 | this.success = false; 50 | } 51 | 52 | /** 53 | * Add an error to the response body and mark the response as failed 54 | * 55 | * @param error {any} error to add, there is currently no type validation so anything can be pushed through 56 | */ 57 | addError(error) { 58 | this.errors.push(error); 59 | this.failure(); 60 | } 61 | 62 | /** 63 | * Add a errors to the response body and mark the response as failed, used primarily with previous client responses 64 | * 65 | * @param errors {any[]} errors array to add, there is currently no type validation so anything can be pushed through 66 | */ 67 | addErrors(errors) { 68 | this.errors.push(...errors); 69 | this.failure(); 70 | } 71 | 72 | /** 73 | * Add response data to the response following the format set with the constructor 74 | * 75 | * @param responseData {object} object making up part of or the whole of the expected responseData 76 | */ 77 | addResponseData(responseData: object) { 78 | this.data = { 79 | ...this.data, 80 | ...responseData, 81 | }; 82 | } 83 | 84 | get body() { 85 | return { 86 | success: this.success, 87 | errors: this.errors, 88 | data: this.data, 89 | }; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /npm-client/types/default_price_ladder.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Price ladder that provides industry-standard price ranges for a market 3 | */ 4 | export const DEFAULT_PRICE_LADDER = [ 5 | 1.001, 1.002, 1.003, 1.004, 1.005, 1.006, 1.007, 1.008, 1.009, 1.01, 1.02, 6 | 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, 1.12, 1.13, 1.14, 1.15, 7 | 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 1.22, 1.23, 1.24, 1.25, 1.26, 1.27, 1.28, 8 | 1.29, 1.3, 1.31, 1.32, 1.33, 1.34, 1.35, 1.36, 1.37, 1.38, 1.39, 1.4, 1.41, 9 | 1.42, 1.43, 1.44, 1.45, 1.46, 1.47, 1.48, 1.49, 1.5, 1.51, 1.52, 1.53, 1.54, 10 | 1.55, 1.56, 1.57, 1.58, 1.59, 1.6, 1.61, 1.62, 1.63, 1.64, 1.65, 1.66, 1.67, 11 | 1.68, 1.69, 1.7, 1.71, 1.72, 1.73, 1.74, 1.75, 1.76, 1.77, 1.78, 1.79, 1.8, 12 | 1.81, 1.82, 1.83, 1.84, 1.85, 1.86, 1.87, 1.88, 1.89, 1.9, 1.91, 1.92, 1.93, 13 | 1.94, 1.95, 1.96, 1.97, 1.98, 1.99, 2, 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 14 | 2.07, 2.08, 2.09, 2.1, 2.11, 2.12, 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 15 | 2.2, 2.22, 2.24, 2.26, 2.28, 2.3, 2.32, 2.34, 2.36, 2.38, 2.4, 2.42, 2.44, 16 | 2.46, 2.48, 2.5, 2.52, 2.54, 2.56, 2.58, 2.6, 2.62, 2.64, 2.66, 2.68, 2.7, 17 | 2.72, 2.74, 2.76, 2.78, 2.8, 2.82, 2.84, 2.86, 2.88, 2.9, 2.92, 2.94, 2.96, 18 | 2.98, 3, 3.05, 3.1, 3.15, 3.2, 3.25, 3.3, 3.35, 3.4, 3.45, 3.5, 3.55, 3.6, 19 | 3.65, 3.7, 3.75, 3.8, 3.85, 3.9, 3.95, 4, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 20 | 4.8, 4.9, 5, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8, 5.9, 6, 6.2, 6.4, 6.6, 21 | 6.8, 7, 7.2, 7.4, 7.6, 7.8, 8, 8.2, 8.4, 8.6, 8.8, 9, 9.2, 9.4, 9.6, 9.8, 10, 22 | 10.5, 11, 11.5, 12, 12.5, 13, 13.5, 14, 14.5, 15, 15.5, 16, 16.5, 17, 17.5, 23 | 18, 18.5, 19, 19.5, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 32, 34, 36, 24 | 38, 40, 42, 44, 46, 48, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100, 110, 120, 25 | 130, 140, 150, 160, 170, 180, 190, 200, 210, 220, 230, 240, 250, 260, 270, 26 | 280, 290, 300, 320, 340, 360, 380, 400, 420, 440, 460, 480, 500, 550, 600, 27 | 650, 700, 750, 800, 900, 1000, 28 | ]; 29 | -------------------------------------------------------------------------------- /npm-client/types/errors.ts: -------------------------------------------------------------------------------- 1 | enum ClientErrors { 2 | M001 = "No cancellable orders found.", 3 | } 4 | 5 | export type ClientError = { 6 | errorCode: string; 7 | errorMessage: ClientErrors; 8 | }; 9 | 10 | export const NoCancellableOrdersFound: ClientError = { 11 | errorCode: "M001", 12 | errorMessage: ClientErrors.M001, 13 | }; 14 | -------------------------------------------------------------------------------- /npm-client/types/get_account.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey } from "@solana/web3.js"; 2 | 3 | export type AccountData = { 4 | publicKey: PublicKey; 5 | account: Account; 6 | }; 7 | 8 | export type GetAccount = AccountData; 9 | 10 | export type GetAccounts = AccountData[]; 11 | 12 | export type GetPublicKeys = { 13 | publicKeys: PublicKey[]; 14 | }; 15 | -------------------------------------------------------------------------------- /npm-client/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./client"; 2 | export * from "./default_price_ladder"; 3 | export * from "./errors"; 4 | export * from "./order"; 5 | export * from "./market"; 6 | export * from "./market_liquidities"; 7 | export * from "./get_account"; 8 | export * from "./market_matching_queue"; 9 | export * from "./market_order_request_queue"; 10 | export * from "./market_commission_payment_queue"; 11 | export * from "./market_position"; 12 | export * from "./wallet_tokens"; 13 | export * from "./trade"; 14 | export * from "./transactions"; 15 | -------------------------------------------------------------------------------- /npm-client/types/market_commission_payment_queue.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey } from "@solana/web3.js"; 2 | import { BN } from "@coral-xyz/anchor"; 3 | import { GetAccount } from "./get_account"; 4 | 5 | export type MarketCommissionPaymentQueues = { 6 | marketCommissionPaymentQueues: GetAccount[]; 7 | }; 8 | 9 | export type MarketCommissionPaymentQueue = { 10 | market: PublicKey; 11 | paymentQueue: CommissionPaymentQueue; 12 | }; 13 | 14 | export type CommissionPaymentQueue = { 15 | empty: boolean; 16 | front: number; 17 | len: number; 18 | items: CommissionPayment[]; 19 | }; 20 | 21 | export type CommissionPayment = { 22 | from: PublicKey; 23 | to: PublicKey; 24 | amount: BN; 25 | }; 26 | -------------------------------------------------------------------------------- /npm-client/types/market_liquidities.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey } from "@solana/web3.js"; 2 | import { BN } from "@coral-xyz/anchor"; 3 | import { GetAccount } from "./get_account"; 4 | 5 | export type MarketLiquiditiesAccounts = { 6 | accounts: GetAccount[]; 7 | }; 8 | 9 | export type MarketLiquidities = { 10 | market: PublicKey; 11 | enableCrossMatching: boolean; 12 | stakeMatchedTotal: BN; 13 | liquiditiesFor: MarketLiquidity[]; 14 | liquiditiesAgainst: MarketLiquidity[]; 15 | }; 16 | 17 | export type MarketLiquidity = { 18 | outcome: number; 19 | price: number; 20 | sources: LiquiditySource[]; 21 | liquidity: BN; 22 | }; 23 | 24 | export type LiquiditySource = { 25 | outcome: number; 26 | price: number; 27 | }; 28 | -------------------------------------------------------------------------------- /npm-client/types/market_matching_queue.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey } from "@solana/web3.js"; 2 | import { BN } from "@coral-xyz/anchor"; 3 | import { GetAccount } from "./get_account"; 4 | 5 | export type MarketMatchingQueues = { 6 | marketMatchingQueues: GetAccount[]; 7 | }; 8 | 9 | export type MarketMatchingQueue = { 10 | market: PublicKey; 11 | matches: MatchingQueue; 12 | }; 13 | 14 | export type MatchingQueue = { 15 | empty: boolean; 16 | front: number; 17 | len: number; 18 | items: OrderMatch[]; 19 | }; 20 | 21 | export type OrderMatch = { 22 | pk: PublicKey; 23 | purchaser: PublicKey; 24 | 25 | forOutcome: boolean; 26 | outcomeIndex: number; 27 | price: number; 28 | stake: BN; 29 | }; 30 | -------------------------------------------------------------------------------- /npm-client/types/market_order_request_queue.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey } from "@solana/web3.js"; 2 | import { BN } from "@coral-xyz/anchor"; 3 | import { GetAccount } from "./get_account"; 4 | 5 | export type MarketOrderRequestQueues = { 6 | marketOrderRequestQueues: GetAccount[]; 7 | }; 8 | 9 | export type MarketOrderRequestQueue = { 10 | market: PublicKey; 11 | orderRequests: OrderRequestQueue; 12 | }; 13 | 14 | export type OrderRequestQueue = { 15 | empty: boolean; 16 | front: number; 17 | len: number; 18 | capacity: number; 19 | items: OrderRequest[]; 20 | }; 21 | 22 | export type OrderRequest = { 23 | purchaser: PublicKey; 24 | marketOutcomeIndex: number; 25 | forOutcome: boolean; 26 | product: PublicKey | null; 27 | stake: BN; 28 | expectedPrice: number; 29 | delayExpirationTimestamp: BN; 30 | productCommissionRate: number; 31 | distinctSeed: number[]; 32 | creationTimestamp: BN; 33 | expiresOn: BN; 34 | }; 35 | -------------------------------------------------------------------------------- /npm-client/types/market_position.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey } from "@solana/web3.js"; 2 | import { BN } from "@coral-xyz/anchor"; 3 | import { GetAccount } from "./get_account"; 4 | 5 | export type MarketPosition = { 6 | purchaser: PublicKey; 7 | market: PublicKey; 8 | paid: boolean; 9 | marketOutcomeSums: BN[]; 10 | unmatchedExposures: BN[]; 11 | outcomePositions: Map; 12 | payer: PublicKey; 13 | matchedRisk: BN; 14 | matchedRiskPerProduct: ProductMatchedRiskAndRate[]; 15 | }; 16 | 17 | export type MarketPositionAccounts = { 18 | marketPositionAccounts: GetAccount[]; 19 | }; 20 | 21 | export type ProductMatchedRiskAndRate = { 22 | product: PublicKey; 23 | risk: BN; 24 | rate: number; 25 | }; 26 | -------------------------------------------------------------------------------- /npm-client/types/order.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey, TransactionInstruction } from "@solana/web3.js"; 2 | import { BN } from "@coral-xyz/anchor"; 3 | import { GetAccount } from "./get_account"; 4 | 5 | export interface OrderStatus { 6 | readonly open?: Record; 7 | readonly matched?: Record; 8 | readonly settledWin?: Record; 9 | readonly settledLose?: Record; 10 | readonly cancelled?: Record; 11 | readonly voided?: Record; 12 | } 13 | 14 | export type Match = { 15 | price: number; 16 | stake: number; 17 | }; 18 | 19 | export type Order = { 20 | purchaser: PublicKey; 21 | market: PublicKey; 22 | marketOutcomeIndex: number; 23 | forOutcome: boolean; 24 | orderStatus: OrderStatus; 25 | product: PublicKey | null; 26 | stake: BN; 27 | voidedStake: BN; 28 | expectedPrice: number; 29 | creationTimestamp: BN; 30 | stakeUnmatched: BN; 31 | payout: BN; 32 | payer: PublicKey; 33 | productCommissionRate: number; 34 | }; 35 | 36 | export type OrderInstructionResponse = { 37 | orderPk: PublicKey; 38 | instruction: TransactionInstruction; 39 | }; 40 | 41 | export type OrderInstructionsResponse = { 42 | orderInstructions: OrderInstructionResponse[]; 43 | }; 44 | 45 | export type PendingOrders = { 46 | pendingOrders: GetAccount[]; 47 | }; 48 | 49 | export type OrderAccounts = { 50 | orderAccounts: GetAccount[]; 51 | }; 52 | 53 | export type OrderTransactionResponse = { 54 | orderPk: PublicKey; 55 | tnxID: string | void; 56 | }; 57 | 58 | export type CancelOrdersResponse = { 59 | failedCancellationOrders: PublicKey[]; 60 | tnxIDs: string[]; 61 | }; 62 | 63 | export type orderPdaResponse = { 64 | orderPk: PublicKey; 65 | distinctSeed: Uint8Array; 66 | }; 67 | 68 | export type StakeInteger = { 69 | stakeInteger: BN; 70 | }; 71 | -------------------------------------------------------------------------------- /npm-client/types/product.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey } from "@solana/web3.js"; 2 | import { GetAccount } from "./get_account"; 3 | 4 | export type Product = { 5 | authority: PublicKey; 6 | payer: PublicKey; 7 | commissionEscrow: PublicKey; 8 | productTitle: string; 9 | commissionRate: number; 10 | }; 11 | 12 | export type CreateProductResponse = { 13 | productPk: PublicKey; 14 | tnxID: string | void; 15 | }; 16 | 17 | export type ProductAccounts = { 18 | productAccounts: GetAccount[]; 19 | }; 20 | -------------------------------------------------------------------------------- /npm-client/types/trade.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey } from "@solana/web3.js"; 2 | import { BN } from "@coral-xyz/anchor"; 3 | import { GetAccount } from "./get_account"; 4 | 5 | export type Trade = { 6 | purchaser: PublicKey; 7 | market: PublicKey; 8 | order: PublicKey; 9 | marketOutcomeIndex: number; 10 | forOutcome: boolean; 11 | stake: BN; 12 | price: number; 13 | creationTimestamp: BN; 14 | payer: PublicKey; 15 | }; 16 | 17 | export type TradeAccounts = { 18 | tradeAccounts: GetAccount[]; 19 | }; 20 | 21 | export type CreateTradeResponse = { 22 | tradePk: PublicKey; 23 | tnxID: string | void; 24 | }; 25 | 26 | export type TradePdaResponse = { 27 | tradePk: PublicKey; 28 | distinctSeed: Uint8Array; 29 | }; 30 | -------------------------------------------------------------------------------- /npm-client/types/transactions.ts: -------------------------------------------------------------------------------- 1 | import { TransactionInstruction } from "@solana/web3.js"; 2 | import { web3 } from "@coral-xyz/anchor"; 3 | 4 | export type SignAndSendInstructionsResponse = { 5 | signature: web3.TransactionSignature; 6 | }; 7 | 8 | export type SignAndSendInstructionsBatchResponse = { 9 | signatures: web3.TransactionSignature[]; 10 | failedInstructions: TransactionInstruction[]; 11 | }; 12 | -------------------------------------------------------------------------------- /npm-client/types/wallet_tokens.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey, TokenAmount } from "@solana/web3.js"; 2 | 3 | export type GetWalletTokenAccountResponse = { 4 | tokenMint: PublicKey; 5 | associatedTokenAccount: PublicKey; 6 | }; 7 | 8 | export type GetWalletTokenAccountsResponse = { 9 | accounts: GetWalletTokenAccountResponse[]; 10 | }; 11 | 12 | export type GetWalletBalanceResponse = { 13 | token: string; 14 | balance: TokenAmount; 15 | }; 16 | 17 | export type GetWalletBalancesResponse = { 18 | balances: GetWalletBalanceResponse[]; 19 | }; 20 | -------------------------------------------------------------------------------- /programs/monaco_protocol/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "monaco_protocol" 3 | version = "0.16.0-dev" 4 | description = "Created with Anchor" 5 | edition = "2018" 6 | 7 | [lib] 8 | crate-type = ["cdylib", "lib"] 9 | name = "monaco_protocol" 10 | doctest = false 11 | 12 | [features] 13 | no-entrypoint = [] 14 | no-idl = [] 15 | cpi = ["no-entrypoint"] 16 | default = [] 17 | stable = [] 18 | dev = [] 19 | edge = [] 20 | 21 | [dependencies] 22 | solana-program = "= 1.17.2" 23 | anchor-lang = { version = "0.29.0", features = ["init-if-needed"] } 24 | anchor-spl = "0.29.0" 25 | spl-token = "4.0.0" 26 | rust_decimal = "1.32.0" 27 | test-case = "3.2.1" 28 | protocol_product = { git = "https://github.com/MonacoProtocol/protocol-product", rev = "v0.2.0", features = ["no-entrypoint"] } 29 | -------------------------------------------------------------------------------- /programs/monaco_protocol/Xargo.toml: -------------------------------------------------------------------------------- 1 | [target.bpfel-unknown-unknown.dependencies.std] 2 | features = [] 3 | -------------------------------------------------------------------------------- /programs/monaco_protocol/src/events/mod.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod trade; 2 | -------------------------------------------------------------------------------- /programs/monaco_protocol/src/events/trade.rs: -------------------------------------------------------------------------------- 1 | use anchor_lang::prelude::*; 2 | 3 | #[event] 4 | pub struct TradeEvent { 5 | pub amount: u64, 6 | pub price: f64, 7 | pub market: Pubkey, 8 | } 9 | -------------------------------------------------------------------------------- /programs/monaco_protocol/src/instructions/clock.rs: -------------------------------------------------------------------------------- 1 | use solana_program::clock::UnixTimestamp; 2 | 3 | pub fn current_timestamp() -> UnixTimestamp { 4 | #[cfg(not(test))] 5 | { 6 | use solana_program::clock::Clock; 7 | use solana_program::sysvar::Sysvar; 8 | Clock::get().unwrap().unix_timestamp 9 | } 10 | #[cfg(test)] 11 | { 12 | use std::time::{SystemTime, UNIX_EPOCH}; 13 | SystemTime::now() 14 | .duration_since(UNIX_EPOCH) 15 | .unwrap() 16 | .as_secs() 17 | .min(UnixTimestamp::MAX as u64) as UnixTimestamp 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /programs/monaco_protocol/src/instructions/market/market_authority.rs: -------------------------------------------------------------------------------- 1 | use crate::error::CoreError; 2 | use anchor_lang::prelude::*; 3 | use solana_program::pubkey::Pubkey; 4 | 5 | pub fn verify_market_authority(operator: &Pubkey, market_authority: &Pubkey) -> Result<()> { 6 | require!( 7 | market_authority.eq(operator), 8 | CoreError::MarketAuthorityMismatch 9 | ); 10 | Ok(()) 11 | } 12 | -------------------------------------------------------------------------------- /programs/monaco_protocol/src/instructions/market/market_token_accounts.rs: -------------------------------------------------------------------------------- 1 | use anchor_lang::prelude::*; 2 | 3 | use crate::context::CloseMarket; 4 | use crate::instructions::transfer; 5 | use crate::state::market_account::{Market, MarketStatus}; 6 | use crate::CoreError; 7 | use anchor_lang::context::{Context, CpiContext}; 8 | use anchor_lang::{Key, ToAccountInfo}; 9 | use anchor_spl::token; 10 | use anchor_spl::token::{Token, TokenAccount}; 11 | 12 | const TRANSFER_SURPLUS_ALLOWED_STATUSES: [MarketStatus; 2] = 13 | [MarketStatus::Settled, MarketStatus::Voided]; 14 | 15 | pub fn transfer_market_token_surplus<'info>( 16 | market: &Account<'info, Market>, 17 | market_escrow: &Account<'info, TokenAccount>, 18 | market_funding: &Account<'info, TokenAccount>, 19 | destination_token_account: &Account<'info, TokenAccount>, 20 | token_program: &Program<'info, Token>, 21 | ) -> Result<()> { 22 | require!( 23 | TRANSFER_SURPLUS_ALLOWED_STATUSES.contains(&market.market_status), 24 | CoreError::MarketInvalidStatus 25 | ); 26 | transfer::transfer_market_escrow_surplus( 27 | market_escrow, 28 | destination_token_account, 29 | token_program, 30 | market, 31 | )?; 32 | transfer::transfer_market_funding_surplus( 33 | market_funding, 34 | destination_token_account, 35 | token_program, 36 | market, 37 | ) 38 | } 39 | 40 | pub fn close_escrow_token_account(ctx: &Context) -> Result<()> { 41 | token::close_account(CpiContext::new_with_signer( 42 | ctx.accounts.token_program.to_account_info(), 43 | token::CloseAccount { 44 | account: ctx.accounts.market_escrow.to_account_info(), 45 | destination: ctx.accounts.authority.to_account_info(), 46 | authority: ctx.accounts.market_escrow.to_account_info(), 47 | }, 48 | &[&[ 49 | "escrow".as_ref(), 50 | ctx.accounts.market.key().as_ref(), 51 | &[ctx.accounts.market.escrow_account_bump], 52 | ]], 53 | )) 54 | } 55 | 56 | pub fn close_funding_token_account(ctx: &Context) -> Result<()> { 57 | token::close_account(CpiContext::new_with_signer( 58 | ctx.accounts.token_program.to_account_info(), 59 | token::CloseAccount { 60 | account: ctx.accounts.market_funding.to_account_info(), 61 | destination: ctx.accounts.authority.to_account_info(), 62 | authority: ctx.accounts.market_funding.to_account_info(), 63 | }, 64 | &[&[ 65 | "funding".as_ref(), 66 | ctx.accounts.market.key().as_ref(), 67 | &[ctx.accounts.market.funding_account_bump], 68 | ]], 69 | )) 70 | } 71 | -------------------------------------------------------------------------------- /programs/monaco_protocol/src/instructions/market/mod.rs: -------------------------------------------------------------------------------- 1 | mod create_market; 2 | mod market_authority; 3 | mod market_token_accounts; 4 | mod move_to_inplay; 5 | mod update_market_event_start_time; 6 | mod update_market_locktime; 7 | mod update_market_status; 8 | mod update_market_title; 9 | 10 | pub use create_market::*; 11 | pub use market_authority::*; 12 | pub use market_token_accounts::*; 13 | pub use move_to_inplay::*; 14 | pub use update_market_event_start_time::*; 15 | pub use update_market_locktime::*; 16 | pub use update_market_status::*; 17 | pub use update_market_title::*; 18 | -------------------------------------------------------------------------------- /programs/monaco_protocol/src/instructions/market_liquidities/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod update_market_liquidities_with_cross_liquidity; 2 | 3 | pub use update_market_liquidities_with_cross_liquidity::update_market_liquidities_with_cross_liquidity; 4 | -------------------------------------------------------------------------------- /programs/monaco_protocol/src/instructions/market_position/create_market_position.rs: -------------------------------------------------------------------------------- 1 | use crate::instructions::current_timestamp; 2 | use crate::instructions::order_request::validate_market_for_order_request; 3 | use anchor_lang::prelude::*; 4 | use solana_program::clock::UnixTimestamp; 5 | 6 | use crate::state::market_account::*; 7 | use crate::state::market_position_account::*; 8 | 9 | pub fn create_market_position( 10 | purchaser: &Pubkey, 11 | payer: &Pubkey, 12 | market_pk: Pubkey, 13 | market: &Market, 14 | market_position: &mut MarketPosition, 15 | ) -> Result<()> { 16 | let now: UnixTimestamp = current_timestamp(); 17 | validate_market_for_order_request(market, now)?; 18 | 19 | let market_outcomes_len = usize::from(market.market_outcomes_count); 20 | 21 | market_position.purchaser = *purchaser; 22 | market_position.payer = *payer; 23 | market_position.market = market_pk; 24 | market_position 25 | .market_outcome_sums 26 | .resize(market_outcomes_len, 0_i128); 27 | market_position 28 | .unmatched_exposures 29 | .resize(market_outcomes_len, 0_u64); 30 | market_position.paid = false; 31 | 32 | if market_position.matched_risk == 0 { 33 | market_position.matched_risk_per_product = 34 | Vec::with_capacity(ProductMatchedRiskAndRate::MAX_LENGTH); 35 | } 36 | 37 | Ok(()) 38 | } 39 | -------------------------------------------------------------------------------- /programs/monaco_protocol/src/instructions/market_position/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod create_market_position; 2 | pub mod settle_market_position; 3 | pub mod update_on_order_cancellation; 4 | pub mod update_on_order_match; 5 | pub mod update_on_order_request_creation; 6 | pub mod update_product_commission_contributions; 7 | pub mod void_market_position; 8 | 9 | pub use create_market_position::*; 10 | pub use settle_market_position::*; 11 | pub use update_on_order_cancellation::*; 12 | pub use update_on_order_match::*; 13 | pub use update_on_order_request_creation::*; 14 | pub use update_product_commission_contributions::*; 15 | pub use void_market_position::*; 16 | -------------------------------------------------------------------------------- /programs/monaco_protocol/src/instructions/market_position/update_on_order_cancellation.rs: -------------------------------------------------------------------------------- 1 | use crate::error::CoreError; 2 | use crate::instructions::calculate_risk_from_stake; 3 | use crate::state::market_order_request_queue::OrderRequest; 4 | use crate::state::market_position_account::MarketPosition; 5 | use crate::state::order_account::*; 6 | use anchor_lang::prelude::*; 7 | 8 | pub fn update_on_order_cancellation( 9 | market_position: &mut MarketPosition, 10 | order: &Order, 11 | stake_to_void: u64, 12 | ) -> Result { 13 | let outcome_index = order.market_outcome_index as usize; 14 | let for_outcome = order.for_outcome; 15 | let order_exposure = match for_outcome { 16 | true => stake_to_void, 17 | false => calculate_risk_from_stake(stake_to_void, order.expected_price), 18 | }; 19 | 20 | update_exposures(market_position, outcome_index, for_outcome, order_exposure) 21 | } 22 | 23 | pub fn update_on_order_request_cancellation( 24 | market_position: &mut MarketPosition, 25 | order_request: &OrderRequest, 26 | ) -> Result { 27 | let outcome_index = order_request.market_outcome_index as usize; 28 | let for_outcome = order_request.for_outcome; 29 | let order_request_exposure = match for_outcome { 30 | true => order_request.stake, 31 | false => calculate_risk_from_stake(order_request.stake, order_request.expected_price), 32 | }; 33 | 34 | update_exposures( 35 | market_position, 36 | outcome_index, 37 | for_outcome, 38 | order_request_exposure, 39 | ) 40 | } 41 | 42 | fn update_exposures( 43 | market_position: &mut MarketPosition, 44 | outcome_index: usize, 45 | for_outcome: bool, 46 | order_exposure: u64, 47 | ) -> Result { 48 | let total_exposure_before = market_position.total_exposure(); 49 | 50 | // update unmatched_exposures 51 | match for_outcome { 52 | true => { 53 | let market_outcomes_len = market_position.unmatched_exposures.len(); 54 | for index in 0..market_outcomes_len { 55 | if outcome_index == index { 56 | continue; 57 | } 58 | market_position.unmatched_exposures[index] = market_position.unmatched_exposures 59 | [index] 60 | .checked_sub(order_exposure) 61 | .ok_or(CoreError::ArithmeticError)?; 62 | } 63 | } 64 | false => { 65 | market_position.unmatched_exposures[outcome_index] = market_position 66 | .unmatched_exposures[outcome_index] 67 | .checked_sub(order_exposure) 68 | .ok_or(CoreError::ArithmeticError)?; 69 | } 70 | } 71 | 72 | // total_exposure_change change 73 | let total_exposure_change = total_exposure_before 74 | .checked_sub(market_position.total_exposure()) 75 | .ok_or(CoreError::ArithmeticError)?; 76 | 77 | Ok(total_exposure_change) 78 | } 79 | -------------------------------------------------------------------------------- /programs/monaco_protocol/src/instructions/market_position/update_on_order_request_creation.rs: -------------------------------------------------------------------------------- 1 | use anchor_lang::prelude::*; 2 | 3 | use crate::error::CoreError; 4 | use crate::instructions::calculate_risk_from_stake; 5 | use crate::state::market_position_account::MarketPosition; 6 | 7 | pub fn update_on_order_request_creation( 8 | market_position: &mut MarketPosition, 9 | market_outcome_index: u16, 10 | for_outcome: bool, 11 | stake: u64, 12 | expected_price: f64, 13 | ) -> Result { 14 | let outcome_index = market_outcome_index as usize; 15 | let order_exposure = match for_outcome { 16 | true => stake, 17 | false => calculate_risk_from_stake(stake, expected_price), 18 | }; 19 | 20 | let total_exposure_before = market_position.total_exposure(); 21 | 22 | // update unmatched_exposures 23 | match for_outcome { 24 | true => { 25 | let market_outcomes_len = market_position.unmatched_exposures.len(); 26 | for index in 0..market_outcomes_len { 27 | if outcome_index == index { 28 | continue; 29 | } 30 | market_position.unmatched_exposures[index] = market_position.unmatched_exposures 31 | [index] 32 | .checked_add(order_exposure) 33 | .ok_or(CoreError::ArithmeticError)?; 34 | } 35 | } 36 | false => { 37 | market_position.unmatched_exposures[outcome_index] = market_position 38 | .unmatched_exposures[outcome_index] 39 | .checked_add(order_exposure) 40 | .ok_or(CoreError::ArithmeticError)?; 41 | } 42 | } 43 | 44 | // total_exposure_change change 45 | let total_exposure_change = market_position 46 | .total_exposure() 47 | .checked_sub(total_exposure_before) 48 | .ok_or(CoreError::ArithmeticError)?; 49 | 50 | Ok(total_exposure_change) 51 | } 52 | -------------------------------------------------------------------------------- /programs/monaco_protocol/src/instructions/market_position/void_market_position.rs: -------------------------------------------------------------------------------- 1 | use crate::instructions::transfer; 2 | use crate::VoidMarketPosition; 3 | use anchor_lang::prelude::*; 4 | use solana_program::log; 5 | 6 | use crate::error::CoreError; 7 | use crate::state::market_account::MarketStatus; 8 | 9 | pub fn void_market_position(ctx: Context) -> Result<()> { 10 | let market_position = &mut ctx.accounts.market_position; 11 | if market_position.paid { 12 | log::sol_log("market position has already been paid out"); 13 | return Ok(()); 14 | } 15 | 16 | let market_account = &mut ctx.accounts.market; 17 | // validate the market is ready to void 18 | require!( 19 | market_account.market_status.eq(&MarketStatus::ReadyToVoid), 20 | CoreError::VoidMarketNotReadyForVoid 21 | ); 22 | 23 | let total_exposure = market_position.total_exposure(); 24 | 25 | market_position.paid = true; 26 | market_account.decrement_unsettled_accounts_count()?; 27 | 28 | transfer::transfer_market_position_void(&ctx, total_exposure) 29 | } 30 | -------------------------------------------------------------------------------- /programs/monaco_protocol/src/instructions/market_type/create_market_type.rs: -------------------------------------------------------------------------------- 1 | use crate::state::market_type::MarketType; 2 | use crate::CoreError; 3 | use anchor_lang::{require, Result}; 4 | 5 | pub fn create_market_type( 6 | market_type: &mut MarketType, 7 | name: String, 8 | requires_discriminator: bool, 9 | requires_value: bool, 10 | ) -> Result<()> { 11 | require!( 12 | name.len() <= MarketType::NAME_MAX_LENGTH, 13 | CoreError::MarketTypeNameTooLong 14 | ); 15 | market_type.name = name; 16 | market_type.requires_discriminator = requires_discriminator; 17 | market_type.requires_value = requires_value; 18 | Ok(()) 19 | } 20 | 21 | #[cfg(test)] 22 | mod tests { 23 | use super::*; 24 | use anchor_lang::error; 25 | 26 | #[test] 27 | fn test_create_market_type_success() { 28 | let expected_name = String::from("EventResultFullTime"); 29 | let mut market_type = test_market_type(); 30 | let mut result = create_market_type(&mut market_type, expected_name.clone(), false, false); 31 | assert!(result.is_ok()); 32 | assert_eq!(market_type.name, expected_name); 33 | assert!(!market_type.requires_discriminator); 34 | assert!(!market_type.requires_value); 35 | 36 | result = create_market_type(&mut market_type, expected_name.clone(), true, false); 37 | assert!(result.is_ok()); 38 | assert!(market_type.requires_discriminator); 39 | assert!(!market_type.requires_value); 40 | 41 | result = create_market_type(&mut market_type, expected_name.clone(), false, true); 42 | assert!(result.is_ok()); 43 | assert!(!market_type.requires_discriminator); 44 | assert!(market_type.requires_value); 45 | 46 | result = create_market_type(&mut market_type, expected_name.clone(), true, true); 47 | assert!(result.is_ok()); 48 | assert!(market_type.requires_discriminator); 49 | assert!(market_type.requires_value); 50 | } 51 | 52 | #[test] 53 | fn test_create_market_type_name_too_long() { 54 | let expected_name = "a".repeat(MarketType::NAME_MAX_LENGTH + 1).to_string(); 55 | let mut market_type = test_market_type(); 56 | let result = create_market_type(&mut market_type, expected_name.clone(), false, false); 57 | assert!(result.is_err()); 58 | assert_eq!( 59 | result.err().unwrap(), 60 | error!(CoreError::MarketTypeNameTooLong) 61 | ); 62 | } 63 | 64 | fn test_market_type() -> MarketType { 65 | MarketType { 66 | name: "".to_string(), 67 | requires_discriminator: false, 68 | requires_value: false, 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /programs/monaco_protocol/src/instructions/market_type/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod create_market_type; 2 | pub use create_market_type::*; 3 | -------------------------------------------------------------------------------- /programs/monaco_protocol/src/instructions/matching/create_trade.rs: -------------------------------------------------------------------------------- 1 | use anchor_lang::prelude::*; 2 | 3 | use crate::state::trade_account::Trade; 4 | 5 | pub fn create_trade( 6 | trade: &mut Trade, 7 | purchaser_pk: &Pubkey, 8 | market_pk: &Pubkey, 9 | order_pk: &Pubkey, 10 | outcome_index: u16, 11 | for_outcome: bool, 12 | stake: u64, 13 | price: f64, 14 | creation_timestamp: i64, 15 | payer: Pubkey, 16 | ) { 17 | trade.purchaser = *purchaser_pk; 18 | trade.market = *market_pk; 19 | trade.order = *order_pk; 20 | trade.for_outcome = for_outcome; 21 | trade.market_outcome_index = outcome_index; 22 | trade.stake = stake; 23 | trade.price = price; 24 | trade.creation_timestamp = creation_timestamp; 25 | trade.payer = payer; 26 | } 27 | -------------------------------------------------------------------------------- /programs/monaco_protocol/src/instructions/matching/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod create_trade; 2 | pub mod matching_one_to_one; 3 | pub mod matching_pool; 4 | pub mod on_order_creation; 5 | pub mod on_order_match; 6 | 7 | pub use matching_one_to_one::*; 8 | pub use matching_pool::*; 9 | pub use on_order_creation::*; 10 | pub use on_order_match::*; 11 | -------------------------------------------------------------------------------- /programs/monaco_protocol/src/instructions/mod.rs: -------------------------------------------------------------------------------- 1 | pub use clock::*; 2 | pub use close::*; 3 | pub use math::*; 4 | pub use operator::*; 5 | pub use payment::*; 6 | pub use transfer::*; 7 | 8 | pub(crate) mod close; 9 | pub(crate) mod market; 10 | pub(crate) mod market_type; 11 | pub(crate) mod matching; 12 | pub(crate) mod order; 13 | pub(crate) mod order_request; 14 | pub(crate) mod price_ladder; 15 | 16 | mod clock; 17 | mod math; 18 | mod operator; 19 | mod payment; 20 | 21 | pub mod market_liquidities; 22 | pub mod market_position; 23 | pub mod transfer; 24 | -------------------------------------------------------------------------------- /programs/monaco_protocol/src/instructions/operator.rs: -------------------------------------------------------------------------------- 1 | use crate::context::AuthoriseOperator; 2 | use crate::error::CoreError; 3 | use crate::state::operator_account::OperatorType; 4 | use crate::AuthorisedOperators; 5 | use anchor_lang::prelude::*; 6 | use solana_program::pubkey::Pubkey; 7 | use std::str::FromStr; 8 | 9 | pub fn authorise_operator( 10 | authority: Pubkey, 11 | authorised_operators: &mut Account, 12 | operator: Pubkey, 13 | operator_type: String, 14 | ) -> Result<()> { 15 | validate_operator_type(operator_type)?; 16 | 17 | // TODO This field is redundant 18 | authorised_operators.authority = authority.key(); 19 | let result = authorised_operators.insert(operator); 20 | require!(result, CoreError::AuthorisedOperatorListFull); 21 | Ok(()) 22 | } 23 | 24 | pub fn remove_authorised_operator( 25 | ctx: Context, 26 | operator: Pubkey, 27 | operator_type_string: String, 28 | ) -> Result<()> { 29 | validate_operator_type(operator_type_string)?; 30 | ctx.accounts.authorised_operators.remove(operator); 31 | Ok(()) 32 | } 33 | 34 | pub fn verify_operator_authority( 35 | operator: &Pubkey, 36 | authorised_operators: &AuthorisedOperators, 37 | ) -> Result<()> { 38 | if !authorised_operators.contains(operator) { 39 | msg!("Operator is not authorised to carry out this operation."); 40 | return Err(error!(CoreError::UnauthorisedOperator)); 41 | } 42 | Ok(()) 43 | } 44 | 45 | fn validate_operator_type(operator_type: String) -> Result<()> { 46 | let result = OperatorType::from_str(&operator_type); 47 | require!(result.is_ok(), CoreError::InvalidOperatorType); 48 | Ok(()) 49 | } 50 | 51 | #[cfg(test)] 52 | mod tests { 53 | use crate::instructions::operator::validate_operator_type; 54 | 55 | #[test] 56 | fn valid_operator_type() { 57 | let result = validate_operator_type(String::from("CRANK")); 58 | assert!(result.is_ok()) 59 | } 60 | 61 | #[test] 62 | fn invalid_operator_type() { 63 | let result = validate_operator_type(String::from("CraNK")); 64 | assert!(result.is_err()) 65 | } 66 | 67 | #[test] 68 | fn valid_operator_type_invalid_type() { 69 | let result = validate_operator_type(String::from("SECRET_AGENT_007")); 70 | assert!(result.is_err()); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /programs/monaco_protocol/src/instructions/order/create_order.rs: -------------------------------------------------------------------------------- 1 | use anchor_lang::prelude::*; 2 | use solana_program::clock::UnixTimestamp; 3 | 4 | use crate::instructions::current_timestamp; 5 | use crate::state::market_account::*; 6 | use crate::state::market_order_request_queue::OrderRequest; 7 | use crate::state::order_account::*; 8 | 9 | pub fn initialize_order( 10 | order: &mut Account, 11 | market: &Account, 12 | fee_payer: Pubkey, 13 | order_request: OrderRequest, 14 | ) -> Result<()> { 15 | let now: UnixTimestamp = current_timestamp(); 16 | 17 | order.market = market.key(); 18 | order.market_outcome_index = order_request.market_outcome_index; 19 | order.for_outcome = order_request.for_outcome; 20 | 21 | order.purchaser = order_request.purchaser; 22 | order.payer = fee_payer; 23 | 24 | order.order_status = OrderStatus::Open; 25 | order.stake = order_request.stake; 26 | order.expected_price = order_request.expected_price; 27 | order.creation_timestamp = now; 28 | order.stake_unmatched = order_request.stake; 29 | order.payout = 0_u64; 30 | 31 | order.product = order_request.product; 32 | order.product_commission_rate = order_request.product_commission_rate; 33 | 34 | Ok(()) 35 | } 36 | -------------------------------------------------------------------------------- /programs/monaco_protocol/src/instructions/order/match_order.rs: -------------------------------------------------------------------------------- 1 | use anchor_lang::prelude::*; 2 | 3 | use crate::error::CoreError; 4 | use crate::instructions::market_position; 5 | use crate::state::market_position_account::MarketPosition; 6 | use crate::state::order_account::{Order, OrderStatus}; 7 | 8 | pub fn match_order( 9 | order: &mut Account, 10 | market_position: &mut MarketPosition, 11 | stake_matched: u64, 12 | price_matched: f64, 13 | ) -> Result { 14 | // validate that status is open or matched (for partial matches) 15 | if order.order_status != OrderStatus::Open && order.order_status != OrderStatus::Matched { 16 | msg!("Order Matching: status closed"); 17 | return Err(error!(CoreError::MatchingStatusClosed)); 18 | } 19 | 20 | // validate that there is enough stake to match (for partial matches) 21 | if order.stake_unmatched < stake_matched { 22 | msg!("Order Matching: remaining stake too small"); 23 | return Err(error!(CoreError::MatchingRemainingStakeTooSmall)); 24 | } 25 | 26 | order.match_stake_unmatched(stake_matched, price_matched)?; 27 | 28 | let refund = market_position::update_on_order_match( 29 | market_position, 30 | order, 31 | stake_matched, 32 | price_matched, 33 | )?; 34 | 35 | Ok(refund) 36 | } 37 | -------------------------------------------------------------------------------- /programs/monaco_protocol/src/instructions/order/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod cancel_order; 2 | pub mod cancel_order_post_market_lock; 3 | pub mod cancel_preplay_order_post_event_start; 4 | pub mod create_order; 5 | pub mod match_order; 6 | pub mod settle_order; 7 | pub mod void_order; 8 | 9 | pub use cancel_order::*; 10 | pub use cancel_order_post_market_lock::*; 11 | pub use cancel_preplay_order_post_event_start::*; 12 | pub use create_order::*; 13 | pub use match_order::*; 14 | pub use settle_order::*; 15 | pub use void_order::*; 16 | -------------------------------------------------------------------------------- /programs/monaco_protocol/src/instructions/order_request/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod create_order_request; 2 | pub mod dequeue_order_request; 3 | pub mod process_order_request; 4 | 5 | pub use create_order_request::*; 6 | pub use dequeue_order_request::*; 7 | pub use process_order_request::*; 8 | -------------------------------------------------------------------------------- /programs/monaco_protocol/src/instructions/payment.rs: -------------------------------------------------------------------------------- 1 | use crate::error::CoreError; 2 | use crate::instructions; 3 | use crate::state::market_account::Market; 4 | use crate::state::payments_queue::PaymentQueue; 5 | use anchor_lang::prelude::*; 6 | use anchor_spl::token::{Token, TokenAccount}; 7 | use protocol_product::state::product::Product; 8 | 9 | pub fn process_commission_payment<'a>( 10 | commission_payments_queue: &mut PaymentQueue, 11 | market_escrow: &Account<'a, TokenAccount>, 12 | product_escrow_token: &Account<'a, TokenAccount>, 13 | product: &Account, 14 | market: &Account, 15 | token_program: &Program<'a, Token>, 16 | ) -> Result<()> { 17 | let payment_info = commission_payments_queue.dequeue(); 18 | require!( 19 | payment_info.is_some(), 20 | CoreError::SettlementPaymentDequeueEmptyQueue 21 | ); 22 | 23 | let payment_info = payment_info.unwrap(); 24 | 25 | require!( 26 | payment_info.from.key() == market_escrow.key(), 27 | CoreError::SettlementPaymentAddressMismatch 28 | ); 29 | require!( 30 | payment_info.to.key() == product.key(), 31 | CoreError::SettlementPaymentAddressMismatch 32 | ); 33 | 34 | instructions::transfer_from_market_escrow( 35 | market_escrow, 36 | product_escrow_token, 37 | token_program, 38 | market, 39 | payment_info.amount, 40 | ) 41 | } 42 | -------------------------------------------------------------------------------- /programs/monaco_protocol/src/instructions/price_ladder/create_price_ladder.rs: -------------------------------------------------------------------------------- 1 | use crate::state::price_ladder::PriceLadder; 2 | use anchor_lang::Result; 3 | use solana_program::pubkey::Pubkey; 4 | 5 | pub fn create_price_ladder( 6 | price_ladder: &mut PriceLadder, 7 | max_number_of_prices: u16, 8 | authority: &Pubkey, 9 | ) -> Result<()> { 10 | price_ladder.authority = *authority; 11 | price_ladder.max_number_of_prices = max_number_of_prices; 12 | price_ladder.prices = vec![]; 13 | Ok(()) 14 | } 15 | 16 | #[cfg(test)] 17 | mod tests { 18 | use super::*; 19 | 20 | #[test] 21 | fn test_create_price_ladder() { 22 | let price_ladder = &mut price_ladder(); 23 | let authority = Pubkey::new_unique(); 24 | let result = create_price_ladder(price_ladder, 3, &authority); 25 | assert!(result.is_ok()); 26 | assert_eq!(price_ladder.authority, authority); 27 | assert_eq!(price_ladder.max_number_of_prices, 3); 28 | assert_eq!(price_ladder.prices, vec![] as Vec); 29 | } 30 | 31 | fn price_ladder() -> PriceLadder { 32 | PriceLadder { 33 | prices: vec![1.0], 34 | max_number_of_prices: 0, 35 | authority: Pubkey::new_unique(), 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /programs/monaco_protocol/src/instructions/price_ladder/increase_price_ladder_size.rs: -------------------------------------------------------------------------------- 1 | use crate::state::price_ladder::PriceLadder; 2 | use crate::CoreError; 3 | use anchor_lang::{require, Result}; 4 | 5 | pub fn increase_price_ladder_size( 6 | price_ladder: &mut PriceLadder, 7 | max_number_of_prices: u16, 8 | ) -> Result<()> { 9 | require!( 10 | price_ladder.max_number_of_prices < max_number_of_prices, 11 | CoreError::PriceLadderSizeCanOnlyBeIncreased 12 | ); 13 | price_ladder.max_number_of_prices = max_number_of_prices; 14 | Ok(()) 15 | } 16 | 17 | #[cfg(test)] 18 | mod tests { 19 | use super::*; 20 | use anchor_lang::error; 21 | use solana_program::pubkey::Pubkey; 22 | 23 | #[test] 24 | fn increase_size() { 25 | let price_ladder = &mut price_ladder(); 26 | let result = increase_price_ladder_size(price_ladder, 4); 27 | assert!(result.is_ok()); 28 | assert_eq!(price_ladder.max_number_of_prices, 4); 29 | } 30 | 31 | #[test] 32 | fn decrease_size() { 33 | let price_ladder = &mut price_ladder(); 34 | let result = increase_price_ladder_size(price_ladder, 2); 35 | assert!(result.is_err()); 36 | assert_eq!( 37 | result.err(), 38 | Some(error!(CoreError::PriceLadderSizeCanOnlyBeIncreased)) 39 | ); 40 | assert_eq!(price_ladder.max_number_of_prices, 3); 41 | } 42 | 43 | #[test] 44 | fn same_size() { 45 | let price_ladder = &mut price_ladder(); 46 | let result = increase_price_ladder_size(price_ladder, price_ladder.max_number_of_prices); 47 | assert!(result.is_err()); 48 | assert_eq!( 49 | result.err(), 50 | Some(error!(CoreError::PriceLadderSizeCanOnlyBeIncreased)) 51 | ); 52 | assert_eq!(price_ladder.max_number_of_prices, 3); 53 | } 54 | 55 | fn price_ladder() -> PriceLadder { 56 | PriceLadder { 57 | prices: vec![2.0, 3.0, 4.0], 58 | max_number_of_prices: 3, 59 | authority: Pubkey::new_unique(), 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /programs/monaco_protocol/src/instructions/price_ladder/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod add_prices_to_price_ladder; 2 | pub mod create_price_ladder; 3 | pub mod increase_price_ladder_size; 4 | pub use add_prices_to_price_ladder::*; 5 | pub use create_price_ladder::*; 6 | pub use increase_price_ladder_size::*; 7 | -------------------------------------------------------------------------------- /programs/monaco_protocol/src/state/market_outcome_account.rs: -------------------------------------------------------------------------------- 1 | use crate::state::type_size::*; 2 | use anchor_lang::prelude::*; 3 | use std::string::ToString; 4 | 5 | #[account] 6 | pub struct MarketOutcome { 7 | pub market: Pubkey, 8 | pub index: u16, 9 | pub title: String, 10 | pub prices: Option, 11 | pub price_ladder: Vec, 12 | } 13 | 14 | impl MarketOutcome { 15 | pub const TITLE_MAX_LENGTH: usize = 100; 16 | pub const PRICE_LADDER_LENGTH: usize = 320; 17 | 18 | pub const SIZE: usize = DISCRIMINATOR_SIZE 19 | + PUB_KEY_SIZE // market 20 | + U16_SIZE // index 21 | + vec_size(CHAR_SIZE, MarketOutcome::TITLE_MAX_LENGTH) // title 22 | + option_size(PUB_KEY_SIZE) // price ladder account 23 | + vec_size(F64_SIZE, MarketOutcome::PRICE_LADDER_LENGTH); // price_ladder 24 | } 25 | 26 | #[cfg(test)] 27 | pub fn mock_market_outcome(market_pk: Pubkey, outcome: u16) -> MarketOutcome { 28 | MarketOutcome { 29 | market: market_pk, 30 | index: outcome, 31 | title: market_pk.to_string(), 32 | prices: None, 33 | price_ladder: vec![], 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /programs/monaco_protocol/src/state/market_type.rs: -------------------------------------------------------------------------------- 1 | use crate::state::type_size::{string_size, BOOL_SIZE, DISCRIMINATOR_SIZE}; 2 | use anchor_lang::prelude::*; 3 | 4 | #[account] 5 | pub struct MarketType { 6 | pub name: String, 7 | pub requires_discriminator: bool, 8 | pub requires_value: bool, 9 | } 10 | 11 | impl MarketType { 12 | pub const NAME_MAX_LENGTH: usize = 32; 13 | 14 | pub fn size_for(str_len: usize) -> usize { 15 | DISCRIMINATOR_SIZE + string_size(str_len) + BOOL_SIZE * 2 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /programs/monaco_protocol/src/state/mod.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod market_type; 2 | pub(crate) mod operator_account; 3 | pub(crate) mod payments_queue; 4 | pub(crate) mod trade_account; 5 | pub(crate) mod type_size; 6 | 7 | pub mod market_account; 8 | pub mod market_liquidities; 9 | pub mod market_matching_pool_account; 10 | pub mod market_matching_queue_account; 11 | pub mod market_order_request_queue; 12 | pub mod market_outcome_account; 13 | pub mod market_position_account; 14 | pub mod order_account; 15 | pub mod price_ladder; 16 | -------------------------------------------------------------------------------- /programs/monaco_protocol/src/state/price_ladder.rs: -------------------------------------------------------------------------------- 1 | use crate::state::type_size::{vec_size, DISCRIMINATOR_SIZE, F64_SIZE, PUB_KEY_SIZE, U16_SIZE}; 2 | use anchor_lang::prelude::*; 3 | 4 | pub static DEFAULT_PRICES: [f64; 317] = [ 5 | 1.001, 1.002, 1.003, 1.004, 1.005, 1.006, 1.007, 1.008, 1.009, 1.01, 1.02, 1.03, 1.04, 1.05, 6 | 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, 1.12, 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 7 | 1.22, 1.23, 1.24, 1.25, 1.26, 1.27, 1.28, 1.29, 1.3, 1.31, 1.32, 1.33, 1.34, 1.35, 1.36, 1.37, 8 | 1.38, 1.39, 1.4, 1.41, 1.42, 1.43, 1.44, 1.45, 1.46, 1.47, 1.48, 1.49, 1.5, 1.51, 1.52, 1.53, 9 | 1.54, 1.55, 1.56, 1.57, 1.58, 1.59, 1.6, 1.61, 1.62, 1.63, 1.64, 1.65, 1.66, 1.67, 1.68, 1.69, 10 | 1.7, 1.71, 1.72, 1.73, 1.74, 1.75, 1.76, 1.77, 1.78, 1.79, 1.8, 1.81, 1.82, 1.83, 1.84, 1.85, 11 | 1.86, 1.87, 1.88, 1.89, 1.9, 1.91, 1.92, 1.93, 1.94, 1.95, 1.96, 1.97, 1.98, 1.99, 2.0, 2.01, 12 | 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.1, 2.11, 2.12, 2.13, 2.14, 2.15, 2.16, 2.17, 13 | 2.18, 2.19, 2.2, 2.22, 2.24, 2.26, 2.28, 2.3, 2.32, 2.34, 2.36, 2.38, 2.4, 2.42, 2.44, 2.46, 14 | 2.48, 2.5, 2.52, 2.54, 2.56, 2.58, 2.6, 2.62, 2.64, 2.66, 2.68, 2.7, 2.72, 2.74, 2.76, 2.78, 15 | 2.8, 2.82, 2.84, 2.86, 2.88, 2.9, 2.92, 2.94, 2.96, 2.98, 3.0, 3.05, 3.1, 3.15, 3.2, 3.25, 3.3, 16 | 3.35, 3.4, 3.45, 3.5, 3.55, 3.6, 3.65, 3.7, 3.75, 3.8, 3.85, 3.9, 3.95, 4.0, 4.1, 4.2, 4.3, 17 | 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5.0, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8, 5.9, 6.0, 6.2, 6.4, 18 | 6.6, 6.8, 7.0, 7.2, 7.4, 7.6, 7.8, 8.0, 8.2, 8.4, 8.6, 8.8, 9.0, 9.2, 9.4, 9.6, 9.8, 10.0, 19 | 10.5, 11.0, 11.5, 12.0, 12.5, 13.0, 13.5, 14.0, 14.5, 15.0, 15.5, 16.0, 16.5, 17.0, 17.5, 18.0, 20 | 18.5, 19.0, 19.5, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0, 29.0, 30.0, 32.0, 34.0, 21 | 36.0, 38.0, 40.0, 42.0, 44.0, 46.0, 48.0, 50.0, 55.0, 60.0, 65.0, 70.0, 75.0, 80.0, 85.0, 90.0, 22 | 95.0, 100.0, 110.0, 120.0, 130.0, 140.0, 150.0, 160.0, 170.0, 180.0, 190.0, 200.0, 210.0, 23 | 220.0, 230.0, 240.0, 250.0, 260.0, 270.0, 280.0, 290.0, 300.0, 320.0, 340.0, 360.0, 380.0, 24 | 400.0, 420.0, 440.0, 460.0, 480.0, 500.0, 550.0, 600.0, 650.0, 700.0, 750.0, 800.0, 900.0, 25 | 1000.0, 26 | ]; 27 | 28 | #[account] 29 | #[derive(Debug)] 30 | pub struct PriceLadder { 31 | pub authority: Pubkey, 32 | pub max_number_of_prices: u16, 33 | pub prices: Vec, 34 | } 35 | 36 | impl PriceLadder { 37 | pub fn size_for(number_of_prices: u16) -> usize { 38 | DISCRIMINATOR_SIZE + PUB_KEY_SIZE + U16_SIZE + vec_size(F64_SIZE, number_of_prices as usize) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /programs/monaco_protocol/src/state/trade_account.rs: -------------------------------------------------------------------------------- 1 | use crate::state::type_size::*; 2 | use anchor_lang::prelude::*; 3 | 4 | #[account] 5 | #[derive(Default)] 6 | pub struct Trade { 7 | pub purchaser: Pubkey, 8 | pub market: Pubkey, 9 | pub order: Pubkey, 10 | pub market_outcome_index: u16, 11 | pub for_outcome: bool, 12 | pub stake: u64, 13 | pub price: f64, 14 | pub creation_timestamp: i64, 15 | 16 | pub payer: Pubkey, 17 | } 18 | 19 | impl Trade { 20 | pub const SIZE: usize = DISCRIMINATOR_SIZE 21 | + (PUB_KEY_SIZE * 3) // purchaser, market, order 22 | + U16_SIZE // market_outcome_index 23 | + BOOL_SIZE // for outcome 24 | + U64_SIZE // stake 25 | + F64_SIZE // price 26 | + I64_SIZE // creation_timestamp 27 | + PUB_KEY_SIZE; // payer 28 | } 29 | -------------------------------------------------------------------------------- /programs/monaco_protocol/src/state/type_size.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | pub const BOOL_SIZE: usize = 1; 4 | pub const CHAR_SIZE: usize = 4; 5 | pub const DISCRIMINATOR_SIZE: usize = 8; 6 | pub const ENUM_SIZE: usize = 1; // for data/field-less enums 7 | pub const F32_SIZE: usize = 4; 8 | pub const F64_SIZE: usize = 8; 9 | pub const I64_SIZE: usize = 8; 10 | pub const I128_SIZE: usize = 16; 11 | pub const PUB_KEY_SIZE: usize = 32; 12 | pub const U8_SIZE: usize = 1; 13 | pub const U16_SIZE: usize = 2; 14 | pub const U32_SIZE: usize = 4; 15 | pub const U64_SIZE: usize = 8; 16 | pub const U128_SIZE: usize = 16; 17 | 18 | const OPTION_PREFIX_SIZE: usize = 1; 19 | pub const fn option_size(element_size: usize) -> usize { 20 | OPTION_PREFIX_SIZE + element_size 21 | } 22 | 23 | const VEC_PREFIX_SIZE: usize = 4; 24 | pub const fn vec_size(element_size: usize, length: usize) -> usize { 25 | VEC_PREFIX_SIZE + element_size * length 26 | } 27 | 28 | pub const fn string_size(str_len: usize) -> usize { 29 | vec_size(CHAR_SIZE, str_len) 30 | } 31 | 32 | #[cfg(test)] 33 | mod tests { 34 | use super::*; 35 | 36 | #[test] 37 | fn test_option_size() { 38 | assert_eq!(1, option_size(0_usize)); 39 | assert_eq!(2, option_size(1_usize)); 40 | assert_eq!(3, option_size(2_usize)); 41 | assert_eq!(4, option_size(3_usize)); 42 | } 43 | 44 | #[test] 45 | fn test_vec_size() { 46 | assert_eq!(4, vec_size(0_usize, 0_usize)); 47 | assert_eq!(4, vec_size(1_usize, 0_usize)); 48 | assert_eq!(4, vec_size(2_usize, 0_usize)); 49 | assert_eq!(4, vec_size(3_usize, 0_usize)); 50 | assert_eq!(4, vec_size(0_usize, 1_usize)); 51 | assert_eq!(5, vec_size(1_usize, 1_usize)); 52 | assert_eq!(6, vec_size(2_usize, 1_usize)); 53 | assert_eq!(7, vec_size(3_usize, 1_usize)); 54 | assert_eq!(4, vec_size(0_usize, 2_usize)); 55 | assert_eq!(6, vec_size(1_usize, 2_usize)); 56 | assert_eq!(8, vec_size(2_usize, 2_usize)); 57 | assert_eq!(10, vec_size(3_usize, 2_usize)); 58 | } 59 | 60 | #[test] 61 | fn test_string_size() { 62 | assert_eq!(4, string_size("".len())); 63 | assert_eq!(8, string_size("a".len())); 64 | assert_eq!(12, string_size("aa".len())); 65 | assert_eq!(16, string_size("aaa".len())); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /tests/anchor/protocol_product/protocol_product.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MonacoProtocol/protocol/a98aaf9f545709b65f6060b949572d65edc2f761/tests/anchor/protocol_product/protocol_product.so -------------------------------------------------------------------------------- /tests/market/update_market_event_start_time.ts: -------------------------------------------------------------------------------- 1 | import * as anchor from "@coral-xyz/anchor"; 2 | import assert from "assert"; 3 | import { monaco } from "../util/wrappers"; 4 | 5 | describe("Market: update start time", () => { 6 | it("success: custom time", async () => { 7 | // create a new market 8 | const market = await monaco.create3WayMarket([4.2]); 9 | const newEventStartTime = 43041841910; 10 | 11 | await monaco.program.methods 12 | .updateMarketEventStartTime(new anchor.BN(newEventStartTime)) 13 | .accounts({ 14 | market: market.pk, 15 | authorisedOperators: await monaco.findMarketAuthorisedOperatorsPda(), 16 | marketOperator: monaco.operatorPk, 17 | }) 18 | .rpc() 19 | .catch((e) => { 20 | console.error(e); 21 | throw e; 22 | }); 23 | 24 | const marketAccount = await monaco.fetchMarket(market.pk).then((o) => { 25 | return { 26 | eventStartTime: o.eventStartTimestamp.toNumber(), 27 | }; 28 | }); 29 | assert.deepEqual(marketAccount, { 30 | eventStartTime: newEventStartTime, 31 | }); 32 | }); 33 | 34 | it("success: now time", async () => { 35 | // create a new market 36 | const market = await monaco.create3WayMarket([4.2]); 37 | const marketEventStartTimestampBefore = await monaco 38 | .fetchMarket(market.pk) 39 | .then((o) => { 40 | return o.eventStartTimestamp.toNumber(); 41 | }); 42 | 43 | await monaco.program.methods 44 | .updateMarketEventStartTimeToNow() 45 | .accounts({ 46 | market: market.pk, 47 | authorisedOperators: await monaco.findMarketAuthorisedOperatorsPda(), 48 | marketOperator: monaco.operatorPk, 49 | }) 50 | .rpc() 51 | .catch((e) => { 52 | console.error(e); 53 | throw e; 54 | }); 55 | 56 | const marketEventStartTimestampAfter = await monaco 57 | .fetchMarket(market.pk) 58 | .then((o) => { 59 | return o.eventStartTimestamp.toNumber(); 60 | }); 61 | expect(marketEventStartTimestampBefore).toBeGreaterThan( 62 | marketEventStartTimestampAfter, 63 | ); 64 | }); 65 | }); 66 | -------------------------------------------------------------------------------- /tests/market/update_market_locktime.ts: -------------------------------------------------------------------------------- 1 | import * as anchor from "@coral-xyz/anchor"; 2 | import assert from "assert"; 3 | import { monaco } from "../util/wrappers"; 4 | 5 | describe("Market: update", () => { 6 | it("Success", async () => { 7 | // create a new market 8 | const market = await monaco.create3WayMarket([4.2]); 9 | const newLocktime = 1000 + Math.floor(new Date().getTime() / 1000); 10 | 11 | await monaco.program.methods 12 | .updateMarketLocktime(new anchor.BN(newLocktime)) 13 | .accounts({ 14 | market: market.pk, 15 | authorisedOperators: await monaco.findMarketAuthorisedOperatorsPda(), 16 | marketOperator: monaco.operatorPk, 17 | }) 18 | .rpc() 19 | .catch((e) => { 20 | console.error(e); 21 | throw e; 22 | }); 23 | 24 | const marketAccount = await market.getAccount().then((o) => { 25 | return { 26 | title: o.title, 27 | lockTimestamp: o.marketLockTimestamp.toNumber(), 28 | }; 29 | }); 30 | assert.deepEqual(marketAccount, { 31 | lockTimestamp: newLocktime, 32 | title: "SOME TITLE", 33 | }); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /tests/market/update_market_title.ts: -------------------------------------------------------------------------------- 1 | import assert from "assert"; 2 | import { monaco } from "../util/wrappers"; 3 | 4 | describe("Market: update", () => { 5 | it("Success", async () => { 6 | // create a new market 7 | const market = await monaco.create3WayMarket([4.2]); 8 | const newTitle = "SomeTitle1"; 9 | 10 | await monaco.program.methods 11 | .updateMarketTitle(newTitle) 12 | .accounts({ 13 | market: market.pk, 14 | authorisedOperators: await monaco.findMarketAuthorisedOperatorsPda(), 15 | marketOperator: monaco.operatorPk, 16 | }) 17 | .rpc() 18 | .catch((e) => { 19 | console.error(e); 20 | throw e; 21 | }); 22 | 23 | const marketAccount = await monaco.fetchMarket(market.pk).then((o) => { 24 | return { 25 | title: o.title, 26 | lockTimestamp: o.marketLockTimestamp.toNumber(), 27 | }; 28 | }); 29 | assert.deepEqual(marketAccount, { 30 | lockTimestamp: 1924254038, 31 | title: newTitle, 32 | }); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /tests/market_type/create_market_type.ts: -------------------------------------------------------------------------------- 1 | import { monaco } from "../util/wrappers"; 2 | import assert from "assert"; 3 | import { PublicKey } from "@solana/web3.js"; 4 | 5 | describe("Attempt to create market types with", () => { 6 | it("a valid name and a duplicate name", async () => { 7 | const name = "NAME"; 8 | 9 | const [marketTypePda] = PublicKey.findProgramAddressSync( 10 | [Buffer.from("market_type"), Buffer.from(name)], 11 | monaco.program.programId, 12 | ); 13 | 14 | try { 15 | await monaco.program.methods 16 | .createMarketType(name, false, false) 17 | .accounts({ 18 | marketType: marketTypePda, 19 | authority: monaco.provider.publicKey, 20 | }) 21 | .rpc(); 22 | } catch (e) { 23 | console.error(e); 24 | throw e; 25 | } 26 | 27 | const marketTypeAccount = await monaco.program.account.marketType.fetch( 28 | marketTypePda, 29 | ); 30 | assert.equal(marketTypeAccount.name, name); 31 | 32 | try { 33 | await monaco.program.methods 34 | .createMarketType(name, false, false) 35 | .accounts({ 36 | marketType: marketTypePda, 37 | authority: monaco.provider.publicKey, 38 | }) 39 | .rpc(); 40 | assert.fail("Expected to fail"); 41 | } catch (e) { 42 | expect(e.logs).toEqual( 43 | expect.arrayContaining([ 44 | expect.stringMatching(new RegExp(/.*Address.*already in use/)), 45 | ]), 46 | ); 47 | } 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /tests/npm-admin-client/market_outcome.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey } from "@solana/web3.js"; 2 | import { workspace } from "@coral-xyz/anchor"; 3 | import assert from "assert"; 4 | import { monaco } from "../util/wrappers"; 5 | import { initialiseOutcomes } from "../../npm-admin-client/src"; 6 | 7 | describe("Initialise outcome on market", () => { 8 | it("Initialises additional outcome", async () => { 9 | // create a new market 10 | const protocolProgram = workspace.MonacoProtocol; 11 | const market = await monaco.createMarket( 12 | ["TEAM_1_WIN", "DRAW", "TEAM_2_WIN"], 13 | [1.001, 1.01, 1.1], 14 | ); 15 | 16 | // check the state of the newly created account 17 | const account = await monaco.fetchMarket(market.pk); 18 | assert.deepEqual(account.title, "SOME TITLE"); 19 | assert.deepEqual(account.marketOutcomesCount, 3); 20 | 21 | const marketOutcomeIndex = account.marketOutcomesCount; 22 | const [marketOutcomePk] = await PublicKey.findProgramAddress( 23 | [market.pk.toBuffer(), Buffer.from(marketOutcomeIndex.toString())], 24 | monaco.program.programId, 25 | ); 26 | 27 | await initialiseOutcomes(protocolProgram, market.pk, ["EXTRA"]); 28 | 29 | const marketAccount = await monaco.fetchMarket(market.pk); 30 | assert.deepEqual(marketAccount.marketOutcomesCount, 4); 31 | 32 | const marketOutcome = await monaco.fetchMarketOutcome(marketOutcomePk); 33 | assert.deepEqual(marketOutcome.index, 3); 34 | assert.deepEqual(marketOutcome.title, "EXTRA"); 35 | assert.deepEqual(marketOutcome.priceLadder, []); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /tests/npm-client/create_order.ts: -------------------------------------------------------------------------------- 1 | import { externalPrograms, monaco } from "../util/wrappers"; 2 | import assert from "assert"; 3 | import { 4 | confirmTransaction, 5 | createOrderUiStake, 6 | Order, 7 | } from "../../npm-client"; 8 | 9 | describe("NPM client - create order", () => { 10 | it("Create order with a custom product", async () => { 11 | const market = await monaco.create3WayMarket([2.0]); 12 | await market.airdropProvider(10000); 13 | const productPk = await externalPrograms.createProduct("SOME_EXCHANGE", 99); 14 | 15 | const orderRequestTx = await createOrderUiStake( 16 | monaco.getRawProgram(), 17 | market.pk, 18 | 0, 19 | true, 20 | 2.0, 21 | 10, 22 | undefined, 23 | productPk, 24 | ); 25 | 26 | await confirmTransaction(monaco.getRawProgram(), orderRequestTx.data.tnxID); 27 | 28 | const orderPk = await market.processNextOrderRequest(); 29 | 30 | // check that product is set to our custom product 31 | const orderAccount = (await monaco.program.account.order.fetch( 32 | orderPk, 33 | )) as Order; 34 | assert.equal(orderAccount.product.toBase58(), productPk.toBase58()); 35 | }); 36 | 37 | it("Create order with default product", async () => { 38 | const market = await monaco.create3WayMarket([2.0]); 39 | await market.airdropProvider(10000); 40 | 41 | const orderRequestTx = await createOrderUiStake( 42 | monaco.getRawProgram(), 43 | market.pk, 44 | 0, 45 | true, 46 | 2.0, 47 | 10, 48 | ); 49 | await confirmTransaction(monaco.getRawProgram(), orderRequestTx.data.tnxID); 50 | 51 | const orderPk = await market.processNextOrderRequest(); 52 | 53 | // check that product is set to null (how rust Option of None is represented) 54 | const orderAccount = (await monaco.program.account.order.fetch( 55 | orderPk, 56 | )) as Order; 57 | assert.equal(orderAccount.product, null); 58 | }); 59 | 60 | it("Create order with mint decimals (6)", async () => { 61 | const market = await monaco.create3WayMarket([2.0]); 62 | await market.airdropProvider(10000); 63 | 64 | const orderRequestTx = await createOrderUiStake( 65 | monaco.getRawProgram(), 66 | market.pk, 67 | 0, 68 | true, 69 | 2.0, 70 | 10, 71 | null, 72 | null, 73 | 6, 74 | ); 75 | await confirmTransaction(monaco.getRawProgram(), orderRequestTx.data.tnxID); 76 | 77 | const orderPk = await market.processNextOrderRequest(); 78 | 79 | const orderAccount = (await monaco.program.account.order.fetch( 80 | orderPk, 81 | )) as Order; 82 | assert.equal(orderAccount.stake.toNumber(), 10000000); 83 | }); 84 | }); 85 | -------------------------------------------------------------------------------- /tests/npm-client/market_outcome.ts: -------------------------------------------------------------------------------- 1 | import { Program } from "@coral-xyz/anchor"; 2 | import assert from "assert"; 3 | import { 4 | MarketOutcomes, 5 | getMarketOutcomesByMarket, 6 | getMarketOutcomeTitlesByMarket, 7 | } from "../../npm-client/src/market_outcome_query"; 8 | import { monaco } from "../util/wrappers"; 9 | 10 | describe("Market Outcomes", () => { 11 | it("marketOutcomeQuery fetchPublicKeys", async () => { 12 | // Create market, purchaser 13 | const market = await monaco.create3WayMarket([3.0]); 14 | 15 | const response = await MarketOutcomes.marketOutcomeQuery( 16 | monaco.program as Program, 17 | ) 18 | .filterByMarket(market.pk) 19 | .fetchPublicKeys(); 20 | 21 | assert.deepEqual(response.data.publicKeys.length, 3); 22 | }); 23 | 24 | it("marketOutcomeQuery fetch", async () => { 25 | // Create market, purchaser 26 | const market = await monaco.create3WayMarket([3.0]); 27 | 28 | const response = await MarketOutcomes.marketOutcomeQuery( 29 | monaco.program as Program, 30 | ) 31 | .filterByMarket(market.pk) 32 | .fetch(); 33 | 34 | const titles = response.data.accounts.map( 35 | (account) => account.account.title, 36 | ); 37 | 38 | assert.deepEqual(titles, ["TEAM_1_WIN", "DRAW", "TEAM_2_WIN"]); 39 | }); 40 | 41 | it("getMarketOutcomesByMarket", async () => { 42 | // Create market, purchaser 43 | const market = await monaco.create3WayMarket([3.0]); 44 | 45 | const response = await getMarketOutcomesByMarket( 46 | monaco.program as Program, 47 | market.pk, 48 | ); 49 | 50 | const titles = response.data.accounts.map( 51 | (account) => account.account.title, 52 | ); 53 | 54 | assert.deepEqual(titles, ["TEAM_1_WIN", "DRAW", "TEAM_2_WIN"]); 55 | }); 56 | 57 | it("getMarketOutcomeTitlesByMarket", async () => { 58 | // Create market, purchaser 59 | const market = await monaco.create3WayMarket([3.0]); 60 | 61 | const response = await getMarketOutcomeTitlesByMarket( 62 | monaco.program as Program, 63 | market.pk, 64 | ); 65 | 66 | assert.deepEqual(response.data.marketOutcomeTitles, [ 67 | "TEAM_1_WIN", 68 | "DRAW", 69 | "TEAM_2_WIN", 70 | ]); 71 | }); 72 | }); 73 | -------------------------------------------------------------------------------- /tests/npm-client/multiple_order_query.ts: -------------------------------------------------------------------------------- 1 | import assert from "assert"; 2 | import { 3 | confirmTransaction, 4 | createOrderUiStake as createOrderNpm, 5 | getOrders, 6 | getOrdersByMarketForProviderWallet, 7 | } from "../../npm-client"; 8 | import { monaco } from "../util/wrappers"; 9 | 10 | describe("Multi Order Query", () => { 11 | const outcomeIndex = 1; 12 | const price1 = 6.0; 13 | const price2 = 7.0; 14 | const price3 = 8.0; 15 | const stake = 2000; 16 | 17 | it("Gets orders", async () => { 18 | const market = await monaco.create3WayMarket([price1, price2, price3]); 19 | await market.airdropProvider(10_000.0); 20 | 21 | const orderResponse1 = await createOrderNpm( 22 | monaco.getRawProgram(), 23 | market.pk, 24 | outcomeIndex, 25 | true, 26 | price1, 27 | stake, 28 | ); 29 | const orderResponse2 = await createOrderNpm( 30 | monaco.getRawProgram(), 31 | market.pk, 32 | outcomeIndex, 33 | true, 34 | price2, 35 | stake, 36 | ); 37 | const orderResponse3 = await createOrderNpm( 38 | monaco.getRawProgram(), 39 | market.pk, 40 | outcomeIndex, 41 | true, 42 | price3, 43 | stake, 44 | ); 45 | 46 | await Promise.all([ 47 | confirmTransaction(monaco.getRawProgram(), orderResponse1.data.tnxID), 48 | confirmTransaction(monaco.getRawProgram(), orderResponse2.data.tnxID), 49 | confirmTransaction(monaco.getRawProgram(), orderResponse3.data.tnxID), 50 | ]); 51 | 52 | const createdOrderPks = await market.processOrderRequests(); 53 | 54 | const responseByMarket = await getOrdersByMarketForProviderWallet( 55 | monaco.getRawProgram(), 56 | market.pk, 57 | ); 58 | //verify all 3 were saved 59 | assert(responseByMarket.success); 60 | assert(responseByMarket.data); 61 | assert.equal(responseByMarket.data.accounts.length, 3); 62 | assert.deepEqual(responseByMarket.errors, []); 63 | 64 | const orderPk1 = createdOrderPks[0]; 65 | const orderPk2 = createdOrderPks[1]; 66 | const orderPks = [orderPk1, orderPk2]; 67 | 68 | const responseByOrderPk = await getOrders(monaco.getRawProgram(), orderPks); 69 | 70 | assert(responseByOrderPk.success); 71 | assert(responseByOrderPk.data); 72 | assert.equal(responseByOrderPk.data.orderAccounts.length, 2); 73 | assert.deepEqual(responseByMarket.errors, []); 74 | //verify order1 key matches order 1 75 | assert.equal(responseByOrderPk.data.orderAccounts[0].publicKey, orderPk1); 76 | assert.equal( 77 | responseByOrderPk.data.orderAccounts[0].account.expectedPrice, 78 | price1, 79 | ); 80 | //verify order2 key matches order 2 81 | assert.equal(responseByOrderPk.data.orderAccounts[1].publicKey, orderPk2); 82 | assert.equal( 83 | responseByOrderPk.data.orderAccounts[1].account.expectedPrice, 84 | price2, 85 | ); 86 | }); 87 | }); 88 | -------------------------------------------------------------------------------- /tests/npm-client/stake.ts: -------------------------------------------------------------------------------- 1 | import { monaco } from "../util/wrappers"; 2 | import { uiStakeToInteger } from "../../npm-client"; 3 | import { Program } from "@coral-xyz/anchor"; 4 | import assert from "assert"; 5 | 6 | describe("Stake calculations", () => { 7 | it("JS floating point inaccuracies in stake conversion are not observed", async () => { 8 | const market = await monaco.create3WayMarket([1.001]); 9 | 10 | const uiStake = 2.01; 11 | const expectedResult = 2010000; 12 | 13 | const result = await uiStakeToInteger( 14 | monaco.program as Program, 15 | uiStake, 16 | market.pk, 17 | ); 18 | assert.equal(result.data.stakeInteger.toNumber(), expectedResult); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /tests/npm-client/trade_query.ts: -------------------------------------------------------------------------------- 1 | import assert from "assert"; 2 | import { 3 | confirmTransaction, 4 | createOrderUiStake as createOrderNpm, 5 | getTradesForProviderWallet, 6 | getTradesForMarket, 7 | getTradesForOrder, 8 | } from "../../npm-client"; 9 | import { monaco } from "../util/wrappers"; 10 | import { createWalletWithBalance } from "../util/test_util"; 11 | 12 | describe("Trades Query", () => { 13 | const outcomeIndex = 1; 14 | const price = 2.0; 15 | const stake = 10.0; 16 | const airdrop = 100.0; 17 | 18 | it("Gets trades", async () => { 19 | const [purchaser, market] = await Promise.all([ 20 | createWalletWithBalance(monaco.provider), 21 | monaco.create3WayMarket([price]), 22 | ]); 23 | await market.airdrop(purchaser, airdrop); 24 | await market.airdropProvider(airdrop); 25 | 26 | const forOrderTx = await createOrderNpm( 27 | monaco.getRawProgram(), 28 | market.pk, 29 | outcomeIndex, 30 | true, 31 | price, 32 | stake, 33 | ); 34 | await confirmTransaction(monaco.getRawProgram(), forOrderTx.data.tnxID); 35 | const forOrderPk = await market.processNextOrderRequest(); 36 | 37 | await market.againstOrder(outcomeIndex, 10.0, price, purchaser); 38 | 39 | await market.processMatchingQueue(); 40 | await new Promise((e) => setTimeout(e, 1000)); 41 | 42 | const responseForProvider = await getTradesForProviderWallet( 43 | monaco.getRawProgram(), 44 | ); 45 | 46 | assert(responseForProvider.success); 47 | assert(responseForProvider.data); 48 | assert.deepEqual(responseForProvider.errors, []); 49 | assert(responseForProvider.data.accounts.length > 0); 50 | 51 | const responseForMarket = await getTradesForMarket( 52 | monaco.getRawProgram(), 53 | market.pk, 54 | ); 55 | 56 | assert(responseForMarket.success); 57 | assert(responseForMarket.data); 58 | assert.deepEqual(responseForMarket.errors, []); 59 | assert.equal(responseForMarket.data.accounts.length, 2); 60 | 61 | const responseForOrder = await getTradesForOrder( 62 | monaco.getRawProgram(), 63 | forOrderPk, 64 | ); 65 | 66 | assert(responseForOrder.success); 67 | assert(responseForOrder.data); 68 | assert.deepEqual(responseForOrder.errors, []); 69 | assert.equal(responseForOrder.data.accounts.length, 1); 70 | }); 71 | }); 72 | -------------------------------------------------------------------------------- /tests/npm-client/wallet_tokens.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Program, 3 | AnchorProvider, 4 | setProvider, 5 | workspace, 6 | } from "@coral-xyz/anchor"; 7 | import NodeWallet from "@coral-xyz/anchor/dist/cjs/nodewallet"; 8 | import assert from "assert"; 9 | import { getWalletTokenBalancesWithSol } from "../../npm-client/src"; 10 | import { 11 | createNewMint, 12 | createAssociatedTokenAccountWithBalance, 13 | } from "../util/test_util"; 14 | 15 | describe("Get Wallet Balance", () => { 16 | const provider = AnchorProvider.local(); 17 | setProvider(provider); 18 | const newMintDecimals = 9; 19 | const newMintValue = 10000; 20 | const solanaTokenName = "solana"; 21 | 22 | it("With other token balance", async () => { 23 | const protocolProgram = workspace.MonacoProtocol as Program; 24 | const nodeWallet = provider.wallet as NodeWallet; 25 | const newMint = await createNewMint(provider, nodeWallet, newMintDecimals); 26 | 27 | await createAssociatedTokenAccountWithBalance( 28 | newMint, 29 | provider.wallet.publicKey, 30 | newMintValue, 31 | ); 32 | const balanceResponse = await getWalletTokenBalancesWithSol( 33 | protocolProgram, 34 | [newMint], 35 | ); 36 | 37 | const balance = balanceResponse.data.balances; 38 | 39 | const solanaBalance = balance.filter( 40 | (token) => token.token == solanaTokenName, 41 | )[0]; 42 | const newMintBalance = balance.filter( 43 | (token) => token.token == newMint.toString(), 44 | )[0]; 45 | 46 | assert(solanaBalance.balance.uiAmount > 0); 47 | assert.equal(solanaBalance.token, solanaTokenName); 48 | 49 | assert.equal(newMintBalance.token, newMint.toString()); 50 | assert.equal( 51 | newMintBalance.balance.amount, 52 | newMintValue * 10 ** newMintDecimals, 53 | ); 54 | assert.equal(newMintBalance.balance.decimals, newMintDecimals); 55 | assert.equal(newMintBalance.balance.uiAmount, newMintValue); 56 | assert.equal( 57 | newMintBalance.balance.uiAmountString, 58 | newMintValue.toString(), 59 | ); 60 | }); 61 | 62 | it("With no other token balance", async () => { 63 | const protocolProgram = workspace.MonacoProtocol as Program; 64 | const nodeWallet = provider.wallet as NodeWallet; 65 | const newMint = await createNewMint(provider, nodeWallet, newMintDecimals); 66 | 67 | const balanceResponse = await getWalletTokenBalancesWithSol( 68 | protocolProgram, 69 | [newMint], 70 | ); 71 | 72 | const balance = balanceResponse.data.balances; 73 | 74 | const newMintBalance = balance.filter( 75 | (token) => token.token == newMint.toString(), 76 | )[0]; 77 | 78 | assert.equal(newMintBalance.balance.amount, "0"); 79 | assert.equal(newMintBalance.balance.decimals, 0); 80 | assert.equal(newMintBalance.balance.uiAmount, 0); 81 | assert.equal(newMintBalance.balance.uiAmountString, "0"); 82 | }); 83 | }); 84 | -------------------------------------------------------------------------------- /tests/order/cancelation_payment_12.ts: -------------------------------------------------------------------------------- 1 | import assert from "assert"; 2 | import { createWalletWithBalance } from "../util/test_util"; 3 | import { monaco } from "../util/wrappers"; 4 | 5 | /* 6 | * Order Cancellation Payment 12 7 | * 8 | * In this scenario we are testing ability to cancel maker order in presence of 9 | * superior liquidity even if it's added after match has been made but still not resolved 10 | * (between order is created and match is processed). 11 | * 12 | * In this scenario maker order is created and fully matched, but it is still not processed. 13 | * Cancellation at this point should fail since there is no available liquidity. 14 | * HHowever after more liquidity is added it should succeed. 15 | */ 16 | describe("Order Cancellation Payment 12", () => { 17 | it("cancel after more liquidity added before match resolves", async () => { 18 | // Given 19 | // Create market, purchaser 20 | const [purchaser1, purchaser2, purchaser3, market] = await Promise.all([ 21 | createWalletWithBalance(monaco.provider), 22 | createWalletWithBalance(monaco.provider), 23 | createWalletWithBalance(monaco.provider), 24 | monaco.create3WayMarket([3.0]), 25 | ]); 26 | await market.airdrop(purchaser1, 100.0); 27 | await market.airdrop(purchaser2, 100.0); 28 | await market.airdrop(purchaser3, 100.0); 29 | 30 | // Create orders 31 | const forOrder1Pk = await market.forOrder(1, 10.0, 3.0, purchaser1); 32 | await market.againstOrder(1, 10.0, 3.0, purchaser2); 33 | 34 | // Try to cancel the maker order 35 | try { 36 | await market.cancel(forOrder1Pk, purchaser1); 37 | assert.fail("expected CancelationLowLiquidity"); 38 | } catch (e) { 39 | assert.equal(e.error.errorCode.code, "CancelationLowLiquidity"); 40 | } 41 | assert.deepEqual(await monaco.getOrder(forOrder1Pk), { 42 | stakeUnmatched: 10, 43 | stakeVoided: 0, 44 | status: { open: {} }, 45 | }); 46 | 47 | // Create more maker liquidity 48 | const forOrder2Pk = await market.forOrder(1, 10.0, 3.0, purchaser3); 49 | assert.deepEqual(await monaco.getOrder(forOrder2Pk), { 50 | stakeUnmatched: 10, 51 | stakeVoided: 0, 52 | status: { open: {} }, 53 | }); 54 | 55 | // Try to cancel the maker order again 56 | await market.cancel(forOrder1Pk, purchaser1); 57 | try { 58 | await monaco.getOrder(forOrder1Pk); 59 | assert.fail("Account should not exist"); 60 | } catch (e) { 61 | assert.equal( 62 | e.message, 63 | "Account does not exist or has no data " + forOrder1Pk, 64 | ); 65 | } 66 | 67 | // Match orders 68 | await market.processMatchingQueue(); 69 | 70 | assert.deepEqual(await monaco.getOrder(forOrder2Pk), { 71 | stakeUnmatched: 0, 72 | stakeVoided: 0, 73 | status: { matched: {} }, 74 | }); 75 | }); 76 | }); 77 | -------------------------------------------------------------------------------- /tests/orderRequest/dequeueOrderRequest.ts: -------------------------------------------------------------------------------- 1 | import * as anchor from "@coral-xyz/anchor"; 2 | import { createWalletWithBalance } from "../util/test_util"; 3 | import { monaco } from "../util/wrappers"; 4 | import assert from "assert"; 5 | import { MarketOrderRequestQueue } from "../../npm-client"; 6 | 7 | describe("Dequeue Order Request", () => { 8 | const provider = anchor.AnchorProvider.local(); 9 | anchor.setProvider(provider); 10 | 11 | it("success - dequeue and refund order request", async function () { 12 | const prices = [3.0]; 13 | 14 | const [purchaser, purchaser2, market] = await Promise.all([ 15 | createWalletWithBalance(monaco.provider), 16 | createWalletWithBalance(monaco.provider), 17 | monaco.create3WayMarket(prices), 18 | ]); 19 | await market.airdrop(purchaser, 1000.0); 20 | await market.airdrop(purchaser2, 1000.0); 21 | 22 | const stake = 10.0; 23 | 24 | await market.forOrderRequest(0, stake, prices[0], purchaser); 25 | await market.againstOrderRequest(1, stake, prices[0], purchaser2); 26 | 27 | assert.equal(await market.getTokenBalance(purchaser), 1000.0 - stake); 28 | assert.equal( 29 | await market.getTokenBalance(purchaser2), 30 | 1000.0 - stake * (prices[0] - 1), 31 | ); 32 | 33 | let orderRequestQueue = 34 | (await monaco.program.account.marketOrderRequestQueue.fetch( 35 | market.orderRequestQueuePk, 36 | )) as MarketOrderRequestQueue; 37 | 38 | assert.equal(orderRequestQueue.market.toBase58(), market.pk.toBase58()); 39 | assert.equal(orderRequestQueue.orderRequests.len, 2); 40 | 41 | await market.dequeueOrderRequest(); 42 | 43 | orderRequestQueue = 44 | (await monaco.program.account.marketOrderRequestQueue.fetch( 45 | market.orderRequestQueuePk, 46 | )) as MarketOrderRequestQueue; 47 | 48 | assert.equal(orderRequestQueue.orderRequests.len, 1); 49 | assert.equal(await market.getTokenBalance(purchaser), 1000.0); 50 | assert.equal( 51 | await market.getTokenBalance(purchaser2), 52 | 1000.0 - stake * (prices[0] - 1), 53 | ); 54 | 55 | await market.dequeueOrderRequest(); 56 | 57 | orderRequestQueue = 58 | await monaco.program.account.marketOrderRequestQueue.fetch( 59 | market.orderRequestQueuePk, 60 | ); 61 | 62 | assert.equal(orderRequestQueue.orderRequests.len, 0); 63 | assert.equal(await market.getTokenBalance(purchaser), 1000.0); 64 | assert.equal(await market.getTokenBalance(purchaser2), 1000.0); 65 | }); 66 | }); 67 | -------------------------------------------------------------------------------- /tests/protocol/create_order_request.ts: -------------------------------------------------------------------------------- 1 | import { createWalletWithBalance } from "../util/test_util"; 2 | import assert from "assert"; 3 | import { DEFAULT_PRICE_LADDER } from "../../npm-client/"; 4 | import { monaco } from "../util/wrappers"; 5 | 6 | describe("Protocol - Create Order Request", () => { 7 | it("fill up the queue", async () => { 8 | const prices = DEFAULT_PRICE_LADDER; 9 | 10 | const [purchaser, market] = await Promise.all([ 11 | createWalletWithBalance(monaco.provider), 12 | monaco.create3WayMarket(prices), 13 | ]); 14 | await market.airdrop(purchaser, 1000.0); 15 | 16 | let i = 0; 17 | try { 18 | for (; i < 100; i += 1) { 19 | await market.forOrderRequest(0, 1.0, prices[i], purchaser); 20 | } 21 | fail("expected OrderRequestCreationQueueFull."); 22 | } catch (e) { 23 | assert.equal(e.error.errorCode.code, "OrderRequestCreationQueueFull"); 24 | } 25 | 26 | assert.equal((await market.getOrderRequestQueue()).orderRequests.len, 50); 27 | 28 | await market.processNextOrderRequest(); 29 | 30 | assert.equal((await market.getOrderRequestQueue()).orderRequests.len, 49); 31 | 32 | try { 33 | await market.forOrderRequest(0, 1.0, prices[i], purchaser); 34 | } catch (e) { 35 | fail(e); 36 | } 37 | 38 | try { 39 | await market.forOrderRequest(0, 1.0, prices[i], purchaser); 40 | fail("expected OrderRequestCreationQueueFull."); 41 | } catch (e) { 42 | assert.equal(e.error.errorCode.code, "OrderRequestCreationQueueFull"); 43 | } 44 | assert.equal((await market.getOrderRequestQueue()).orderRequests.len, 50); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /tests/protocol/settle_market.ts: -------------------------------------------------------------------------------- 1 | import assert from "assert"; 2 | import { createWalletWithBalance } from "../util/test_util"; 3 | import { monaco } from "../util/wrappers"; 4 | 5 | describe("Security: Settle Market", () => { 6 | it("failed: matching queue not empty", async () => { 7 | // Given 8 | const outcome = 0; 9 | const price = 3.0; 10 | const stake = 10.0; 11 | 12 | // Create market, purchasers 13 | const [purchaserA, purchaserB, market] = await Promise.all([ 14 | createWalletWithBalance(monaco.provider), 15 | createWalletWithBalance(monaco.provider), 16 | monaco.create3WayMarket([price]), 17 | ]); 18 | await Promise.all([ 19 | market.airdrop(purchaserA, 100.0), 20 | market.airdrop(purchaserB, 100.0), 21 | ]); 22 | 23 | // Create matching orders 24 | await market.forOrder(outcome, stake, price, purchaserA); 25 | await market.againstOrder(outcome, stake, price, purchaserB); 26 | 27 | // Check the queue is not empty 28 | assert.deepEqual( 29 | await Promise.all([ 30 | market.getMarketMatchingQueueHead().then((head) => { 31 | return { 32 | forOutcome: head.forOutcome, 33 | outcomeIndex: head.outcomeIndex, 34 | price: head.price, 35 | stake: head.stake, 36 | }; 37 | }), 38 | market.getEscrowBalance(), 39 | market.getTokenBalance(purchaserA), 40 | market.getTokenBalance(purchaserB), 41 | ]), 42 | [ 43 | { 44 | forOutcome: true, 45 | outcomeIndex: 0, 46 | price: 3, 47 | stake: 10, 48 | }, 49 | 30, 50 | 90, 51 | 80, 52 | ], 53 | ); 54 | 55 | // SETTLE --------------------------------------------------------------------- 56 | 57 | try { 58 | await market.settle(outcome); 59 | assert.fail("expected SettlementMarketMatchingQueueNotEmpty"); 60 | } catch (e) { 61 | assert.equal( 62 | e.error.errorCode.code, 63 | "SettlementMarketMatchingQueueNotEmpty", 64 | ); 65 | } 66 | }); 67 | }); 68 | -------------------------------------------------------------------------------- /tests/setup.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey } from "@solana/web3.js"; 2 | import * as anchor from "@coral-xyz/anchor"; 3 | import { MonacoProtocol } from "../target/types/monaco_protocol"; 4 | import { 5 | authoriseAdminOperator, 6 | authoriseOperator, 7 | getOrCreateMarketType, 8 | createProtocolProduct, 9 | OperatorType, 10 | } from "./util/test_util"; 11 | 12 | module.exports = async function (_globalConfig, _projectConfig) { 13 | const provider = anchor.AnchorProvider.local(); 14 | anchor.setProvider(provider); 15 | const protocolProgram: anchor.Program = 16 | anchor.workspace.MonacoProtocol; 17 | const operatorPk: PublicKey = provider.wallet.publicKey; 18 | await authoriseAdminOperator(operatorPk, protocolProgram, provider); 19 | await authoriseOperator( 20 | operatorPk, 21 | protocolProgram, 22 | provider, 23 | OperatorType.MARKET, 24 | ); 25 | await authoriseOperator( 26 | operatorPk, 27 | protocolProgram, 28 | provider, 29 | OperatorType.CRANK, 30 | ); 31 | 32 | await createProtocolProduct(provider); 33 | 34 | await getOrCreateMarketType( 35 | protocolProgram as anchor.Program, 36 | "EventResultWinner", 37 | ); 38 | }; 39 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "types": ["jest"], 4 | "typeRoots": ["./node_modules/@types"], 5 | "lib": ["es2015"], 6 | "module": "commonjs", 7 | "target": "es6", 8 | "esModuleInterop": true, 9 | "resolveJsonModule": true 10 | } 11 | } 12 | --------------------------------------------------------------------------------