├── .eslintrc ├── .gitignore ├── .husky ├── .gitignore └── pre-commit ├── .prettierrc ├── README.md ├── jest.config.js ├── package.json ├── src ├── constants │ ├── devnet │ │ ├── farms.ts │ │ ├── index.ts │ │ ├── pools.ts │ │ └── tokens.ts │ ├── farms.ts │ ├── index.ts │ ├── orca-defaults.ts │ ├── pools.ts │ └── tokens.ts ├── index.ts ├── model │ ├── orca-factory.ts │ ├── orca │ │ ├── farm │ │ │ ├── farm-types.ts │ │ │ └── orca-farm.ts │ │ ├── orca-impl.ts │ │ └── pool │ │ │ ├── orca-pool.ts │ │ │ └── pool-types.ts │ └── quote │ │ ├── constant-product-quote.ts │ │ ├── quote-builder.ts │ │ └── stable-quote.ts ├── public │ ├── devnet │ │ ├── farms │ │ │ └── config.ts │ │ ├── index.ts │ │ ├── pools │ │ │ └── config.ts │ │ └── utils.ts │ ├── farms │ │ ├── config.ts │ │ ├── index.ts │ │ └── types.ts │ ├── index.ts │ ├── main │ │ ├── index.ts │ │ ├── orca.ts │ │ └── types.ts │ ├── pools │ │ ├── config.ts │ │ ├── index.ts │ │ └── types.ts │ └── utils │ │ ├── constants.ts │ │ ├── index.ts │ │ ├── models │ │ ├── index.ts │ │ ├── instruction.ts │ │ └── percentage.ts │ │ ├── numbers │ │ ├── decimal-utils.ts │ │ ├── index.ts │ │ ├── orca-u64.ts │ │ └── u64-utils.ts │ │ ├── pool-utils.ts │ │ ├── time-utils.ts │ │ ├── types.ts │ │ └── web3 │ │ ├── ata-utils.ts │ │ ├── deserialize-account.ts │ │ ├── get-token-count.ts │ │ ├── index.ts │ │ ├── instructions │ │ ├── farm-instructions.ts │ │ ├── pool-instructions.ts │ │ └── token-instructions.ts │ │ ├── key-utils.ts │ │ └── transactions │ │ ├── index.ts │ │ └── transaction-builder.ts └── tsconfig.json ├── test ├── model │ └── orca │ │ └── quote │ │ ├── constant-product-quote.test.ts │ │ └── stable-quote.test.ts ├── public │ └── utils │ │ └── orca-u64.test.ts ├── test-utils.ts ├── tsconfig.json └── utils │ ├── models │ └── percentage.test.ts │ └── numbers │ ├── decimal-utils.test.ts │ └── u64-utils.test.ts ├── tsconfig-base.json └── yarn.lock /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "react-app", 4 | "prettier" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | # Logs 3 | logs 4 | *.log 5 | npm-debug.log* 6 | yarn-debug.log* 7 | yarn-error.log* 8 | lerna-debug.log* 9 | 10 | # Diagnostic reports (https://nodejs.org/api/report.html) 11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | *.lcov 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (https://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # Snowpack dependency directory (https://snowpack.dev/) 46 | web_modules/ 47 | 48 | # TypeScript cache 49 | *.tsbuildinfo 50 | 51 | # Optional npm cache directory 52 | .npm 53 | 54 | # Optional eslint cache 55 | .eslintcache 56 | 57 | # Microbundle cache 58 | .rpt2_cache/ 59 | .rts2_cache_cjs/ 60 | .rts2_cache_es/ 61 | .rts2_cache_umd/ 62 | 63 | # Optional REPL history 64 | .node_repl_history 65 | 66 | # Output of 'npm pack' 67 | *.tgz 68 | 69 | # Yarn Integrity file 70 | .yarn-integrity 71 | 72 | # dotenv environment variables file 73 | .env 74 | .env.test 75 | 76 | # parcel-bundler cache (https://parceljs.org/) 77 | .cache 78 | .parcel-cache 79 | 80 | # Next.js build output 81 | .next 82 | out 83 | 84 | # Nuxt.js build / generate output 85 | .nuxt 86 | dist 87 | 88 | # Gatsby files 89 | .cache/ 90 | # Comment in the public line in if your project uses Gatsby and not Next.js 91 | # https://nextjs.org/blog/next-9-1#public-directory-support 92 | # public 93 | 94 | # vuepress build output 95 | .vuepress/dist 96 | 97 | # Serverless directories 98 | .serverless/ 99 | 100 | # FuseBox cache 101 | .fusebox/ 102 | 103 | # DynamoDB Local files 104 | .dynamodb/ 105 | 106 | # TernJS port file 107 | .tern-port 108 | 109 | # Stores VSCode versions used for testing VSCode extensions 110 | .vscode-test 111 | 112 | # yarn v2 113 | .yarn/cache 114 | .yarn/unplugged 115 | .yarn/build-state.yml 116 | .yarn/install-state.gz 117 | .pnp.* 118 | 119 | .vscode/* 120 | -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx lint-staged 5 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100 3 | } 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ⚠️ **WARNING: DEPRECATED TYPESCRIPT SDK** ⚠️ 2 | 3 | This Typescript SDK is for the **legacy pools** which are **deprecated**. We highly recommend you to use the **Whirlpools SDK** for the new and improved pools. You can find it here: 4 | 5 | 🌊 [Whirlpools SDK on npmjs](https://www.npmjs.com/package/@orca-so/whirlpools-sdk) 🌊 6 | 7 | Please update your implementations to avoid any issues or disruptions in the future. 8 | 9 | # Orca Typescript SDK 10 | 11 | The Orca SDK contains a set of simple to use APIs to allow developers to integrate with the Orca platform. 12 | 13 | Learn more Orca [here](https://docs.orca.so). 14 | 15 | ### Orca Token Swap V2 16 | 17 | - The [Orca Token Swap V2 program](https://solscan.io/account/9W959DqEETiGZocYWCQPaJ6sBmUzgfxXfqGeTEdp3aQP) uses the following commit hash of the SPL Token Swap program: [3613cea3](https://github.com/solana-labs/solana-program-library/tree/3613cea3cabbb5f7e4445d6203b7292d413732da/token-swap) 18 | 19 | ### Trading Orca Liquidity Pools 20 | 21 | - Get detailed quotes and make swaps between trading pairs in an Orca Pool 22 | - Check your Orca Pool LP token balance and total supply 23 | 24 | **Supported Orca Pools** 25 | 26 | - The SDK supports all pools currently listed on [Orca](https://www.orca.so/pools) 27 | 28 | ### Provide Liquidity to Orca Pools 29 | 30 | - Deposit liquidity to supported Orca Pools 31 | - Deposit a trading pair, and receive LP token 32 | - Withdraw liquidity from supported Orca Pools 33 | - Withdraw a trading pair in exchange for LP token 34 | 35 | **Aquafarm Support** 36 | 37 | - After depositing liquidtiy to a pool, the LP token can be deposited into 38 | the corresponding farm to receive an equivalent amount of farm token 39 | - Remember to withdraw the LP token in exchange for farm token before 40 | withdrawing liquidity from Orca Pool 41 | 42 | **DoubleDip Support** 43 | 44 | - For farms with double-dip, the aquafarm tokens can be deposited into 45 | double-dip farm to receive double-dip rewards 46 | 47 | **Features Coming Soon** 48 | 49 | - More trader information (APY, Volume) 50 | 51 | # Installation 52 | 53 | Use your environment's package manager to install @orca-so/sdk and other related packages into your project. 54 | 55 | ```bash 56 | yarn add @orca-so/sdk @solana/web3.js decimal.js 57 | ``` 58 | 59 | ```bash 60 | npm install @orca-so/sdk @solana/web3.js decimal.js 61 | ``` 62 | 63 | # Usage 64 | 65 | ```typescript 66 | import { readFile } from "mz/fs"; 67 | import { Connection, Keypair } from "@solana/web3.js"; 68 | import { getOrca, OrcaFarmConfig, OrcaPoolConfig } from "@orca-so/sdk"; 69 | import Decimal from "decimal.js"; 70 | 71 | const main = async () => { 72 | /*** Setup ***/ 73 | // 1. Read secret key file to get owner keypair 74 | const secretKeyString = await readFile("/Users/scuba/my-wallet/my-keypair.json", { 75 | encoding: "utf8", 76 | }); 77 | const secretKey = Uint8Array.from(JSON.parse(secretKeyString)); 78 | const owner = Keypair.fromSecretKey(secretKey); 79 | 80 | // 2. Initialzie Orca object with mainnet connection 81 | const connection = new Connection("https://api.mainnet-beta.solana.com", "singleGossip"); 82 | const orca = getOrca(connection); 83 | 84 | try { 85 | /*** Swap ***/ 86 | // 3. We will be swapping 0.1 SOL for some ORCA 87 | const orcaSolPool = orca.getPool(OrcaPoolConfig.ORCA_SOL); 88 | const solToken = orcaSolPool.getTokenB(); 89 | const solAmount = new Decimal(0.1); 90 | const quote = await orcaSolPool.getQuote(solToken, solAmount); 91 | const orcaAmount = quote.getMinOutputAmount(); 92 | 93 | console.log(`Swap ${solAmount.toString()} SOL for at least ${orcaAmount.toNumber()} ORCA`); 94 | const swapPayload = await orcaSolPool.swap(owner, solToken, solAmount, orcaAmount); 95 | const swapTxId = await swapPayload.execute(); 96 | console.log("Swapped:", swapTxId, "\n"); 97 | 98 | /*** Pool Deposit ***/ 99 | // 4. Deposit SOL and ORCA for LP token 100 | const { maxTokenAIn, maxTokenBIn, minPoolTokenAmountOut } = await orcaSolPool.getDepositQuote( 101 | orcaAmount, 102 | solAmount 103 | ); 104 | 105 | console.log( 106 | `Deposit at most ${maxTokenBIn.toNumber()} SOL and ${maxTokenAIn.toNumber()} ORCA, for at least ${minPoolTokenAmountOut.toNumber()} LP tokens` 107 | ); 108 | const poolDepositPayload = await orcaSolPool.deposit( 109 | owner, 110 | maxTokenAIn, 111 | maxTokenBIn, 112 | minPoolTokenAmountOut 113 | ); 114 | const poolDepositTxId = await poolDepositPayload.execute(); 115 | console.log("Pool deposited:", poolDepositTxId, "\n"); 116 | 117 | /*** Farm Deposit ***/ 118 | // 5. Deposit some ORCA_SOL LP token for farm token 119 | const lpBalance = await orcaSolPool.getLPBalance(owner.publicKey); 120 | const orcaSolFarm = orca.getFarm(OrcaFarmConfig.ORCA_SOL_AQ); 121 | const farmDepositPayload = await orcaSolFarm.deposit(owner, lpBalance); 122 | const farmDepositTxId = await farmDepositPayload.execute(); 123 | console.log("Farm deposited:", farmDepositTxId, "\n"); 124 | // Note 1: for double dip, repeat step 5 but with the double dip farm 125 | // Note 2: to harvest reward, orcaSolFarm.harvest(owner) 126 | // Note 3: to get harvestable reward amount, orcaSolFarm.getHarvestableAmount(owner.publicKey) 127 | 128 | /*** Farm Withdraw ***/ 129 | // 6. Withdraw ORCA_SOL LP token, in exchange for farm token 130 | const farmBalance = await orcaSolFarm.getFarmBalance(owner.publicKey); // withdraw the entire balance 131 | const farmWithdrawPayload = await orcaSolFarm.withdraw(owner, farmBalance); 132 | const farmWithdrawTxId = await farmWithdrawPayload.execute(); 133 | console.log("Farm withdrawn:", farmWithdrawTxId, "\n"); 134 | 135 | /*** Pool Withdraw ***/ 136 | // 6. Withdraw SOL and ORCA, in exchange for ORCA_SOL LP token 137 | const withdrawTokenAmount = await orcaSolPool.getLPBalance(owner.publicKey); 138 | const withdrawTokenMint = orcaSolPool.getPoolTokenMint(); 139 | const { maxPoolTokenAmountIn, minTokenAOut, minTokenBOut } = await orcaSolPool.getWithdrawQuote( 140 | withdrawTokenAmount, 141 | withdrawTokenMint 142 | ); 143 | 144 | console.log( 145 | `Withdraw at most ${maxPoolTokenAmountIn.toNumber()} ORCA_SOL LP token for at least ${minTokenAOut.toNumber()} ORCA and ${minTokenBOut.toNumber()} SOL` 146 | ); 147 | const poolWithdrawPayload = await orcaSolPool.withdraw( 148 | owner, 149 | maxPoolTokenAmountIn, 150 | minTokenAOut, 151 | minTokenBOut 152 | ); 153 | const poolWithdrawTxId = await poolWithdrawPayload.execute(); 154 | console.log("Pool withdrawn:", poolWithdrawTxId, "\n"); 155 | } catch (err) { 156 | console.warn(err); 157 | } 158 | }; 159 | 160 | main() 161 | .then(() => { 162 | console.log("Done"); 163 | }) 164 | .catch((e) => { 165 | console.error(e); 166 | }); 167 | ``` 168 | 169 | # Devnet Testing 170 | 171 | The example code above can be run on devnet by updating the import statement: 172 | 173 | ```typescript 174 | import { getOrca, OrcaFarmConfig, OrcaPoolConfig, Network } from "@orca-so/sdk"; 175 | ``` 176 | 177 | And changing two lines of code like so: 178 | 179 | ```typescript 180 | const connection = new Connection("https://api.devnet.solana.com", "singleGossip"); 181 | const orca = getOrca(connection, Network.DEVNET); 182 | ``` 183 | 184 | One caveat to note is that there are only a few devnet pools available, so if you try to access pools that are only 185 | available on mainnet, the code will throw an error. The example code uses ORCA_SOL, which exists on the devnet. 186 | 187 | # Technical Notes 188 | 189 | **Decimals & OrcaU64** 190 | 191 | The SDK relies on the use of [Decimal](https://github.com/MikeMcl/decimal.js/) for number inputs and Decimal/[OrcaU64](https://github.com/orca-so/typescript-sdk/blob/main/src/public/utils/orca-u64.ts) for token-value inputs. If a Decimal instance is provided for a token-value input, it will be automatically transformed to the token's scale. 192 | 193 | **Stability of the Public Util Functions** 194 | 195 | We hope you find the tools we used to build our API useful in the public/utils folder. Due to our on-going development of the Orca platform, we cannot guarrantee the stability of the util APIs. The trading APIs can only be upgraded on major version updates. 196 | 197 | # Support 198 | 199 | **Integration Questions** 200 | 201 | Have problems integrating with the SDK? Pop by over to our [Discord](https://discord.gg/nSwGWn5KSG) #integrations channel and chat with one of our engineers. 202 | 203 | **Issues / Bugs** 204 | 205 | If you found a bug, open up an issue on github with the prefix [ISSUE]. To help us be more effective in resolving the problem, be specific in the steps it took to reproduce the problem (ex. when did the issue occur, code samples, debug logs etc). 206 | 207 | **Feedback** 208 | 209 | Got ideas on how to improve the system? Open up an issue on github with the prefix [FEEDBACK] and let's brainstorm more about it together! 210 | 211 | # License 212 | 213 | [MIT](https://choosealicense.com/licenses/mit/) 214 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "roots": [ 3 | "/src", 4 | "/test" 5 | ], 6 | "testMatch": [ 7 | "**/__tests__/**/*.+(ts|tsx|js)", 8 | "**/?(*.)+(spec|test).+(ts|tsx|js)" 9 | ], 10 | "transform": { 11 | "^.+\\.(ts|tsx)$": "ts-jest" 12 | }, 13 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@orca-so/sdk", 3 | "version": "1.2.25", 4 | "description": "Typescript SDK for the Orca protocol.", 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "license": "MIT", 8 | "dependencies": { 9 | "@orca-so/aquafarm": "^0.0.12", 10 | "@orca-so/stablecurve": "^1.0.5", 11 | "@solana/spl-token": "^0.1.5", 12 | "@solana/spl-token-swap": "^0.1.2", 13 | "@solana/web3.js": "^1.24.1", 14 | "decimal.js": "^10.3.1" 15 | }, 16 | "devDependencies": { 17 | "@types/bn.js": "^4.11.6", 18 | "@types/decimal.js": "^7.4.0", 19 | "@types/jest": "^26.0.24", 20 | "@types/node": "^12.0.0", 21 | "@typescript-eslint/eslint-plugin": "^4.26.0", 22 | "@typescript-eslint/parser": "^4.26.0", 23 | "builder-pattern": "^1.3.0", 24 | "eslint-config-prettier": "^8.3.0", 25 | "eslint-config-react-app": "^6.0.0", 26 | "husky": "^7.0.1", 27 | "jest": "^27.0.6", 28 | "lint-staged": ">=10", 29 | "prettier": "^2.3.2", 30 | "ts-jest": "^27.0.3", 31 | "typescript": "^4.3.2" 32 | }, 33 | "scripts": { 34 | "build": "tsc -p src", 35 | "watch": "tsc -w -p src", 36 | "prettier-format": "prettier --config .prettierrc 'src/**/*.ts' --write", 37 | "prepare": "husky install", 38 | "prepublishOnly": "tsc -p src", 39 | "test": "jest" 40 | }, 41 | "lint-staged": { 42 | "*.{ts,md}": "yarn run prettier-format" 43 | }, 44 | "files": [ 45 | "/dist" 46 | ], 47 | "repository": { 48 | "type": "git", 49 | "url": "git+https://github.com/orca-so/typescript-sdk.git" 50 | }, 51 | "keywords": [ 52 | "orca_so", 53 | "orca", 54 | "solana", 55 | "typescript", 56 | "sdk", 57 | "crypto", 58 | "dex" 59 | ], 60 | "author": "team@orca.so", 61 | "bugs": { 62 | "url": "https://github.com/orca-so/typescript-sdk/issues" 63 | }, 64 | "homepage": "https://www.orca.so" 65 | } 66 | -------------------------------------------------------------------------------- /src/constants/devnet/farms.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey } from "@solana/web3.js"; 2 | import { OrcaFarmParams } from "../../model/orca/farm/farm-types"; 3 | 4 | /** 5 | * The following content is auto-generated. 6 | */ 7 | 8 | export const solUsdcAqFarm: OrcaFarmParams = Object.freeze({ 9 | address: new PublicKey("CzFnr34cRC1o8yrs5jTHBqDQ1FDckLapkPis6zTfqCF5"), 10 | farmTokenMint: new PublicKey("AtJF9fbQ1pbz76NYo2jtKjHuzzyaFToHLCizYk6UoHHL"), 11 | rewardTokenMint: new PublicKey("orcarKHSqC5CDDsGbho8GKvwExejWHxTqGzXgcewB9L"), 12 | rewardTokenDecimals: 6, 13 | baseTokenMint: new PublicKey("4GpUivZ2jvZqQ3vJRsoq5PwnYv6gdV9fJ9BzHT2JcRr7"), 14 | baseTokenDecimals: 6, 15 | }); 16 | 17 | export const solUsdtAqFarm: OrcaFarmParams = Object.freeze({ 18 | address: new PublicKey("ER1UZsRhzucvXY8xMmXGfbbxb442iTHk2u1rSKRMPakC"), 19 | farmTokenMint: new PublicKey("E95ABqtqnJRMG6gqEKZ16dVMfSNDUdCbEYqGUVg3tFRX"), 20 | rewardTokenMint: new PublicKey("orcarKHSqC5CDDsGbho8GKvwExejWHxTqGzXgcewB9L"), 21 | rewardTokenDecimals: 6, 22 | baseTokenMint: new PublicKey("2E4Mp6y2gFRteXiANnwzAJEhHwD3NX1wru3XvxJpGBq2"), 23 | baseTokenDecimals: 6, 24 | }); 25 | 26 | export const usdcUsdtAqFarm: OrcaFarmParams = Object.freeze({ 27 | address: new PublicKey("D7wWV4nxqEeCAk2UA2nEGWgKw2BgoZYFZFUfwWGBhDF8"), 28 | farmTokenMint: new PublicKey("3dDqVehvEpc5HMcbJUAzwMwF54xqa4nNvYN9qis7HAPe"), 29 | rewardTokenMint: new PublicKey("orcarKHSqC5CDDsGbho8GKvwExejWHxTqGzXgcewB9L"), 30 | rewardTokenDecimals: 6, 31 | baseTokenMint: new PublicKey("EBor1PR5XNGHjRVB6JDJuKVCQbvdr1CVZTaX1hTAdvQv"), 32 | baseTokenDecimals: 6, 33 | }); 34 | 35 | export const ethSolAqFarm: OrcaFarmParams = Object.freeze({ 36 | address: new PublicKey("3q4wtMRT2yKHzQGy6gxwD34i9rsafviKd78rpdDLrBfk"), 37 | farmTokenMint: new PublicKey("5NH9rNaoLKbPPP5zwCJTaMPkFACtfJA8wEmqWrXzgCMa"), 38 | rewardTokenMint: new PublicKey("orcarKHSqC5CDDsGbho8GKvwExejWHxTqGzXgcewB9L"), 39 | rewardTokenDecimals: 6, 40 | baseTokenMint: new PublicKey("8sFnpd7mM1AWxP1LXX2FWbbkaVtAopBPmPNZ9y6172WL"), 41 | baseTokenDecimals: 6, 42 | }); 43 | 44 | export const ethUsdcAqFarm: OrcaFarmParams = Object.freeze({ 45 | address: new PublicKey("3aRTv8TGtZkX4dsM4N9aUHKotcwRr6phWPHXPLN8DEYX"), 46 | farmTokenMint: new PublicKey("EeqPcczEZH2cjYBnQyGXBQx1DGs7KG1pobwdPKcwALhD"), 47 | rewardTokenMint: new PublicKey("orcarKHSqC5CDDsGbho8GKvwExejWHxTqGzXgcewB9L"), 48 | rewardTokenDecimals: 6, 49 | baseTokenMint: new PublicKey("9pRnvg7ihSJDLi6DGf3PLwr6xRRRrBPXsHYEgGL5hzgA"), 50 | baseTokenDecimals: 6, 51 | }); 52 | 53 | export const orcaSolAqFarm: OrcaFarmParams = Object.freeze({ 54 | address: new PublicKey("6YrLcQs5yFvXkRY5VkMGEfVgo5rwozJf7jXedpZxbKmi"), 55 | farmTokenMint: new PublicKey("3z8o3b4gMBpnRsrDv7ruZPcVtgoULMFyEoEEGwTsw2TR"), 56 | rewardTokenMint: new PublicKey("orcarKHSqC5CDDsGbho8GKvwExejWHxTqGzXgcewB9L"), 57 | rewardTokenDecimals: 6, 58 | baseTokenMint: new PublicKey("CmDdQhusZWyi9fue27VSktYgkHefm3JXNdzc9kCpyvYi"), 59 | baseTokenDecimals: 6, 60 | }); 61 | 62 | export const orcaUsdcAqFarm: OrcaFarmParams = Object.freeze({ 63 | address: new PublicKey("44GPPv5XedLXCNCc3Mbay1T18vc6x2bWihmmg7UJanvH"), 64 | farmTokenMint: new PublicKey("52Tv8d6Z7Lb27dqCufZPUqadZBTv3EAKGzoV6hy185As"), 65 | rewardTokenMint: new PublicKey("orcarKHSqC5CDDsGbho8GKvwExejWHxTqGzXgcewB9L"), 66 | rewardTokenDecimals: 6, 67 | baseTokenMint: new PublicKey("2ZEEntzoUN7XuMs88ukLGv5HRR1byL7wFWChryF5ZHri"), 68 | baseTokenDecimals: 6, 69 | }); 70 | 71 | export const solUsdcDoubleDip: OrcaFarmParams = Object.freeze({ 72 | address: new PublicKey("L3XdTwLLtZRrXqSk5mqcBKaorqgmM2AMDGmzfBuhLMd"), 73 | farmTokenMint: new PublicKey("7AYG2y3je8TqcLsugNkV6aPw14QyqdVFmK5EegeJmRFi"), 74 | rewardTokenMint: new PublicKey("Ff5JqsAYUD4vAfQUtfRprT4nXu9e28tTBZTDFMnJNdvd"), 75 | rewardTokenDecimals: 9, 76 | baseTokenMint: new PublicKey("AtJF9fbQ1pbz76NYo2jtKjHuzzyaFToHLCizYk6UoHHL"), 77 | baseTokenDecimals: 6, 78 | }); 79 | 80 | export const ethSolDoubleDip: OrcaFarmParams = Object.freeze({ 81 | address: new PublicKey("5jGfcgoRNpZPwfiRTp5zxNpEKP3PTeM3F9EKS9EsvX67"), 82 | farmTokenMint: new PublicKey("5Uv5T1BksJGKGFGVpfxGeGniFFgGLjavNpPWGkfUFNkr"), 83 | rewardTokenMint: new PublicKey("6PE3Mwjzx9h8kCoBp5YPed9TFoG7du8L98yucBP5ps3x"), 84 | rewardTokenDecimals: 6, 85 | baseTokenMint: new PublicKey("5NH9rNaoLKbPPP5zwCJTaMPkFACtfJA8wEmqWrXzgCMa"), 86 | baseTokenDecimals: 6, 87 | }); 88 | 89 | export const ethUsdcDoubleDip: OrcaFarmParams = Object.freeze({ 90 | address: new PublicKey("B4CTmaFpNRtXL3ZLiLrgbMZknQHFdoGu4V9tbzsjFbRT"), 91 | farmTokenMint: new PublicKey("5jdeMPvNrscuw8abZFf99X9kcxDhANcpuBHDNpnx7YPT"), 92 | rewardTokenMint: new PublicKey("EmXq3Ni9gfudTiyNKzzYvpnQqnJEMRw2ttnVXoJXjLo1"), 93 | rewardTokenDecimals: 6, 94 | baseTokenMint: new PublicKey("EeqPcczEZH2cjYBnQyGXBQx1DGs7KG1pobwdPKcwALhD"), 95 | baseTokenDecimals: 6, 96 | }); 97 | 98 | /** 99 | * Mapping for OrcaFarm parameters 100 | * Key: baseTokenMint : OrcaFarmParams 101 | */ 102 | export const orcaDevnetFarmConfigs: Record = { 103 | "4GpUivZ2jvZqQ3vJRsoq5PwnYv6gdV9fJ9BzHT2JcRr7": solUsdcAqFarm, 104 | "2E4Mp6y2gFRteXiANnwzAJEhHwD3NX1wru3XvxJpGBq2": solUsdtAqFarm, 105 | EBor1PR5XNGHjRVB6JDJuKVCQbvdr1CVZTaX1hTAdvQv: usdcUsdtAqFarm, 106 | "8sFnpd7mM1AWxP1LXX2FWbbkaVtAopBPmPNZ9y6172WL": ethSolAqFarm, 107 | "9pRnvg7ihSJDLi6DGf3PLwr6xRRRrBPXsHYEgGL5hzgA": ethUsdcAqFarm, 108 | CmDdQhusZWyi9fue27VSktYgkHefm3JXNdzc9kCpyvYi: orcaSolAqFarm, 109 | "2ZEEntzoUN7XuMs88ukLGv5HRR1byL7wFWChryF5ZHri": orcaUsdcAqFarm, 110 | AtJF9fbQ1pbz76NYo2jtKjHuzzyaFToHLCizYk6UoHHL: solUsdcDoubleDip, 111 | "5NH9rNaoLKbPPP5zwCJTaMPkFACtfJA8wEmqWrXzgCMa": ethSolDoubleDip, 112 | EeqPcczEZH2cjYBnQyGXBQx1DGs7KG1pobwdPKcwALhD: ethUsdcDoubleDip, 113 | }; 114 | -------------------------------------------------------------------------------- /src/constants/devnet/index.ts: -------------------------------------------------------------------------------- 1 | export { orcaDevnetPoolConfigs } from "./pools"; 2 | export { orcaDevnetFarmConfigs } from "./farms"; 3 | -------------------------------------------------------------------------------- /src/constants/devnet/pools.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey } from "@solana/web3.js"; 2 | import { CurveType, OrcaPoolParams } from "../../model/orca/pool/pool-types"; 3 | import { Percentage } from "../../public/utils/models/percentage"; 4 | import * as Tokens from "./tokens"; 5 | 6 | /** 7 | * The following content is auto-generated. 8 | */ 9 | 10 | export const solUsdcPool: OrcaPoolParams = Object.freeze({ 11 | address: new PublicKey("8DT1oKJPHcdJzdSf3cb2WT7L8eRjLUJeDFSe7M2QDtQE"), 12 | nonce: 255, 13 | authority: new PublicKey("BVSZP6RsqAtjvuJrXYsYN5U4XY7pLwW4PawfgVPkLbjN"), 14 | poolTokenMint: new PublicKey("4GpUivZ2jvZqQ3vJRsoq5PwnYv6gdV9fJ9BzHT2JcRr7"), 15 | poolTokenDecimals: 6, 16 | feeAccount: new PublicKey("HPzaLqtZGhTbs7WcdGMfLswKze28W75nrYytNSw7qdvi"), 17 | tokenIds: [Tokens.solToken.mint.toString(), Tokens.usdcToken.mint.toString()], 18 | tokens: { 19 | [Tokens.solToken.mint.toString()]: { 20 | ...Tokens.solToken, 21 | addr: new PublicKey("4ShvTPQ3jYZzwUpxoQFSCDZxLtxQYNPUfeL3sR9mzLjJ"), 22 | }, 23 | [Tokens.usdcToken.mint.toString()]: { 24 | ...Tokens.usdcToken, 25 | addr: new PublicKey("9eKgmUSfTkQLRBvowV9zjY3BbhAQVaGSw1jfon5UwUJM"), 26 | }, 27 | }, 28 | curveType: CurveType.ConstantProduct, 29 | feeStructure: { 30 | traderFee: Percentage.fromFraction(25, 10000), 31 | ownerFee: Percentage.fromFraction(5, 10000), 32 | }, 33 | }); 34 | 35 | export const solUsdtPool: OrcaPoolParams = Object.freeze({ 36 | address: new PublicKey("65AsoozQfBedPU3rGCB7CfBbSFhiFGaVQaeoF9mLFM3g"), 37 | nonce: 255, 38 | authority: new PublicKey("59Pu3srqBDSgWrSJKuh7xcb5omJeVkMw41eFswDWKPat"), 39 | poolTokenMint: new PublicKey("2E4Mp6y2gFRteXiANnwzAJEhHwD3NX1wru3XvxJpGBq2"), 40 | poolTokenDecimals: 6, 41 | feeAccount: new PublicKey("HmRP17zbgJUPPeueLjT2b1HVKt16CTixSJX6UpGkkZnp"), 42 | tokenIds: [Tokens.solToken.mint.toString(), Tokens.usdtToken.mint.toString()], 43 | tokens: { 44 | [Tokens.solToken.mint.toString()]: { 45 | ...Tokens.solToken, 46 | addr: new PublicKey("BhJsBxGoe39HWtwFTCxRZGhPNVZ5x9Rr2gFzNsaA6ES8"), 47 | }, 48 | [Tokens.usdtToken.mint.toString()]: { 49 | ...Tokens.usdtToken, 50 | addr: new PublicKey("Ea2gPV96MQthA5CCS4NincVidxsN8JifWhBoMJVHx8mZ"), 51 | }, 52 | }, 53 | curveType: CurveType.ConstantProduct, 54 | feeStructure: { 55 | traderFee: Percentage.fromFraction(25, 10000), 56 | ownerFee: Percentage.fromFraction(5, 10000), 57 | }, 58 | }); 59 | 60 | export const usdcUsdtPool: OrcaPoolParams = Object.freeze({ 61 | address: new PublicKey("4UJqLypzZzDvoAWCLt6qWEoddMYoSLjrJEB13AfRmV68"), 62 | nonce: 255, 63 | authority: new PublicKey("52Sp73fASLtZhBPyZu7rQoejG9sNzpNLaTTF4mJJGZge"), 64 | poolTokenMint: new PublicKey("EBor1PR5XNGHjRVB6JDJuKVCQbvdr1CVZTaX1hTAdvQv"), 65 | poolTokenDecimals: 6, 66 | feeAccount: new PublicKey("6RjV63TfeJDL7K6j8cUnaT6mWXKxqsrDFrumvqGRwss6"), 67 | tokenIds: [Tokens.usdcToken.mint.toString(), Tokens.usdtToken.mint.toString()], 68 | tokens: { 69 | [Tokens.usdcToken.mint.toString()]: { 70 | ...Tokens.usdcToken, 71 | addr: new PublicKey("Fp9PioKwFc6vmQZ5yB2pPSSx5VqkLhgX21dQYug79yUQ"), 72 | }, 73 | [Tokens.usdtToken.mint.toString()]: { 74 | ...Tokens.usdtToken, 75 | addr: new PublicKey("GazSkg8GU4cti8Dm1cYD74CQf9UXQdUzBsP27YhC4SCt"), 76 | }, 77 | }, 78 | curveType: CurveType.Stable, 79 | amp: 100, 80 | feeStructure: { 81 | traderFee: Percentage.fromFraction(9, 10000), 82 | ownerFee: Percentage.fromFraction(1, 10000), 83 | }, 84 | }); 85 | 86 | export const ethSolPool: OrcaPoolParams = Object.freeze({ 87 | address: new PublicKey("F9MgdfFEshXCTGbppcVr2DzpVxqkiVowGqd95S4vpC6D"), 88 | nonce: 251, 89 | authority: new PublicKey("FD1UJqbXtiYnMcKxcDG4MYY1vasupm2sYXAkStQhSpTb"), 90 | poolTokenMint: new PublicKey("8sFnpd7mM1AWxP1LXX2FWbbkaVtAopBPmPNZ9y6172WL"), 91 | poolTokenDecimals: 6, 92 | feeAccount: new PublicKey("8zyAMewVQuHBxJeqn5oRvanDaaEZ9uYxjHxJ9DYCRsgn"), 93 | tokenIds: [Tokens.ethToken.mint.toString(), Tokens.solToken.mint.toString()], 94 | tokens: { 95 | [Tokens.ethToken.mint.toString()]: { 96 | ...Tokens.ethToken, 97 | addr: new PublicKey("FJetz1Du8p2NWmfa9DNvHR8zC42tUCHsY3YfnkZNyZfT"), 98 | }, 99 | [Tokens.solToken.mint.toString()]: { 100 | ...Tokens.solToken, 101 | addr: new PublicKey("37o62xYE1a43Ap8neq6SdrutxQKFsFHicRamkcjHigKs"), 102 | }, 103 | }, 104 | curveType: CurveType.ConstantProduct, 105 | feeStructure: { 106 | traderFee: Percentage.fromFraction(25, 10000), 107 | ownerFee: Percentage.fromFraction(5, 10000), 108 | }, 109 | }); 110 | 111 | export const ethUsdcPool: OrcaPoolParams = Object.freeze({ 112 | address: new PublicKey("CVH3UX1fePV3fn4dE2irNgni2uRkPdEWyZeCZS5b63F3"), 113 | nonce: 255, 114 | authority: new PublicKey("3uf9wngmqKdBdrWPM9iKsXQE829sg7gH9oJghcrpePhh"), 115 | poolTokenMint: new PublicKey("9pRnvg7ihSJDLi6DGf3PLwr6xRRRrBPXsHYEgGL5hzgA"), 116 | poolTokenDecimals: 6, 117 | feeAccount: new PublicKey("9AekLW8Dq5T1XnLLC2rQscS4Y5YN2QwrYA7eaGdq7Xje"), 118 | tokenIds: [Tokens.ethToken.mint.toString(), Tokens.usdcToken.mint.toString()], 119 | tokens: { 120 | [Tokens.ethToken.mint.toString()]: { 121 | ...Tokens.ethToken, 122 | addr: new PublicKey("C7eYGeiroWzuPgqruxRmgj3xw978gRZpPTov2kqxBRpx"), 123 | }, 124 | [Tokens.usdcToken.mint.toString()]: { 125 | ...Tokens.usdcToken, 126 | addr: new PublicKey("DRdNFrRqWpqQHhJDymyZvgHBH2vTkUo5jzzTwWy7RT4h"), 127 | }, 128 | }, 129 | curveType: CurveType.ConstantProduct, 130 | feeStructure: { 131 | traderFee: Percentage.fromFraction(25, 10000), 132 | ownerFee: Percentage.fromFraction(5, 10000), 133 | }, 134 | }); 135 | 136 | export const orcaSolPool: OrcaPoolParams = Object.freeze({ 137 | address: new PublicKey("B4v9urCKnrdCMWt7rEPyA5xyuEeYQv4aDpCfGFVaCvox"), 138 | nonce: 252, 139 | authority: new PublicKey("38Q2148y3BKU6pDUfv1zpeEeKNuDHBH34WdEwo5EiTfe"), 140 | poolTokenMint: new PublicKey("CmDdQhusZWyi9fue27VSktYgkHefm3JXNdzc9kCpyvYi"), 141 | poolTokenDecimals: 6, 142 | feeAccount: new PublicKey("EEWAuP2d1KbwX14dgHwxXspPMYfxXvgf4CNRYvMakPHg"), 143 | tokenIds: [Tokens.orcaToken.mint.toString(), Tokens.solToken.mint.toString()], 144 | tokens: { 145 | [Tokens.orcaToken.mint.toString()]: { 146 | ...Tokens.orcaToken, 147 | addr: new PublicKey("HsGXFtv1uBTtWuPCEJWpxZS4QkcHwAhdPaMVSvS4fhtv"), 148 | }, 149 | [Tokens.solToken.mint.toString()]: { 150 | ...Tokens.solToken, 151 | addr: new PublicKey("3coXPvurzHQ6sYLrYi8zGWG7SLVv9mHnbqmchjKgPEmz"), 152 | }, 153 | }, 154 | curveType: CurveType.ConstantProduct, 155 | feeStructure: { 156 | traderFee: Percentage.fromFraction(25, 10000), 157 | ownerFee: Percentage.fromFraction(5, 10000), 158 | }, 159 | }); 160 | 161 | export const orcaUsdcPool: OrcaPoolParams = Object.freeze({ 162 | address: new PublicKey("GaCKuVZyo6HxUf6bkcWzDETGHqqViF6H77ax7Uxq3LXU"), 163 | nonce: 255, 164 | authority: new PublicKey("3KVqBR9cB4tNHwpNPZtedegXbQ8FbWgjzk5oob7QRnHt"), 165 | poolTokenMint: new PublicKey("2ZEEntzoUN7XuMs88ukLGv5HRR1byL7wFWChryF5ZHri"), 166 | poolTokenDecimals: 6, 167 | feeAccount: new PublicKey("9yVp1tUHNxorNZgXAs6thPeizCryHTebjKG4P8uUdXuv"), 168 | tokenIds: [Tokens.orcaToken.mint.toString(), Tokens.usdcToken.mint.toString()], 169 | tokens: { 170 | [Tokens.orcaToken.mint.toString()]: { 171 | ...Tokens.orcaToken, 172 | addr: new PublicKey("7KAqhu58omLjKjg1XNSw28JULED82mnA1vvAMVoAdA6T"), 173 | }, 174 | [Tokens.usdcToken.mint.toString()]: { 175 | ...Tokens.usdcToken, 176 | addr: new PublicKey("8E2CH9fPNXbc5pqu1dWWkNsNZWvLcBEXdBnzzXuhvJNL"), 177 | }, 178 | }, 179 | curveType: CurveType.ConstantProduct, 180 | feeStructure: { 181 | traderFee: Percentage.fromFraction(25, 10000), 182 | ownerFee: Percentage.fromFraction(5, 10000), 183 | }, 184 | }); 185 | 186 | /** 187 | * Mapping for OrcaPool parameters 188 | * Key: poolTokenMint : OrcaPoolParams 189 | */ 190 | export const orcaDevnetPoolConfigs: Record = { 191 | "4GpUivZ2jvZqQ3vJRsoq5PwnYv6gdV9fJ9BzHT2JcRr7": solUsdcPool, 192 | "2E4Mp6y2gFRteXiANnwzAJEhHwD3NX1wru3XvxJpGBq2": solUsdtPool, 193 | EBor1PR5XNGHjRVB6JDJuKVCQbvdr1CVZTaX1hTAdvQv: usdcUsdtPool, 194 | "8sFnpd7mM1AWxP1LXX2FWbbkaVtAopBPmPNZ9y6172WL": ethSolPool, 195 | "9pRnvg7ihSJDLi6DGf3PLwr6xRRRrBPXsHYEgGL5hzgA": ethUsdcPool, 196 | CmDdQhusZWyi9fue27VSktYgkHefm3JXNdzc9kCpyvYi: orcaSolPool, 197 | "2ZEEntzoUN7XuMs88ukLGv5HRR1byL7wFWChryF5ZHri": orcaUsdcPool, 198 | }; 199 | -------------------------------------------------------------------------------- /src/constants/devnet/tokens.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey } from "@solana/web3.js"; 2 | import { OrcaToken } from "../.."; 3 | 4 | /** 5 | * The following content is auto-generated. 6 | */ 7 | 8 | export const ethToken: OrcaToken = Object.freeze({ 9 | tag: "ETH", 10 | name: "Ethereum", 11 | mint: new PublicKey("Ff5JqsAYUD4vAfQUtfRprT4nXu9e28tTBZTDFMnJNdvd"), 12 | scale: 9, 13 | }); 14 | 15 | export const orcaToken: OrcaToken = Object.freeze({ 16 | tag: "ORCA", 17 | name: "Orca", 18 | mint: new PublicKey("orcarKHSqC5CDDsGbho8GKvwExejWHxTqGzXgcewB9L"), 19 | scale: 6, 20 | }); 21 | 22 | export const solToken: OrcaToken = Object.freeze({ 23 | tag: "SOL", 24 | name: "Solana", 25 | mint: new PublicKey("So11111111111111111111111111111111111111112"), 26 | scale: 9, 27 | }); 28 | 29 | export const usdcToken: OrcaToken = Object.freeze({ 30 | tag: "USDC", 31 | name: "USD Coin", 32 | mint: new PublicKey("EmXq3Ni9gfudTiyNKzzYvpnQqnJEMRw2ttnVXoJXjLo1"), 33 | scale: 6, 34 | }); 35 | 36 | export const usdtToken: OrcaToken = Object.freeze({ 37 | tag: "USDT", 38 | name: "Tether USD", 39 | mint: new PublicKey("6PE3Mwjzx9h8kCoBp5YPed9TFoG7du8L98yucBP5ps3x"), 40 | scale: 6, 41 | }); 42 | -------------------------------------------------------------------------------- /src/constants/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./orca-defaults"; 2 | export * from "./pools"; 3 | export * from "./farms"; 4 | -------------------------------------------------------------------------------- /src/constants/orca-defaults.ts: -------------------------------------------------------------------------------- 1 | import { Percentage } from "../public/utils/models/percentage"; 2 | 3 | export const defaultSlippagePercentage = Percentage.fromFraction(1, 1000); // 0.1% 4 | -------------------------------------------------------------------------------- /src/constants/tokens.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey } from "@solana/web3.js"; 2 | import { OrcaToken } from ".."; 3 | 4 | /** 5 | * The following content is auto-generated. 6 | */ 7 | 8 | export const onesolToken: OrcaToken = Object.freeze({ 9 | tag: "1SOL", 10 | name: "1Sol", 11 | mint: new PublicKey("4ThReWAbAVZjNVgs5Ui9Pk3cZ5TYaD9u6Y89fp6EFzoF"), 12 | scale: 8, 13 | }); 14 | 15 | export const aartToken: OrcaToken = Object.freeze({ 16 | tag: "AART", 17 | name: "ALL.ART", 18 | mint: new PublicKey("F3nefJBcejYbtdREjui1T9DPh5dBgpkKq7u2GAAMXs5B"), 19 | scale: 6, 20 | }); 21 | 22 | export const abrToken: OrcaToken = Object.freeze({ 23 | tag: "ABR", 24 | name: "Allbridge", 25 | mint: new PublicKey("a11bdAAuV8iB2fu7X6AxAvDTo1QZ8FXB3kk5eecdasp"), 26 | scale: 9, 27 | }); 28 | 29 | export const anaToken: OrcaToken = Object.freeze({ 30 | tag: "ANA", 31 | name: "Nirvana ANA", 32 | mint: new PublicKey("ANAxByE6G2WjFp7A4NqtWYXb3mgruyzZYg3spfxe6Lbo"), 33 | scale: 6, 34 | }); 35 | 36 | export const aptToken: OrcaToken = Object.freeze({ 37 | tag: "APT", 38 | name: "Apricot", 39 | mint: new PublicKey("APTtJyaRX5yGTsJU522N4VYWg3vCvSb65eam5GrPT5Rt"), 40 | scale: 6, 41 | }); 42 | 43 | export const atlasToken: OrcaToken = Object.freeze({ 44 | tag: "ATLAS", 45 | name: "Star Atlas", 46 | mint: new PublicKey("ATLASXmbPQxBUYbxPsV97usA3fPQYEqzQBUHgiFCUsXx"), 47 | scale: 8, 48 | }); 49 | 50 | export const audioToken: OrcaToken = Object.freeze({ 51 | tag: "AUDIO", 52 | name: "Audius (Wormhole)", 53 | mint: new PublicKey("9LzCMqDgTKYz9Drzqnpgee3SGa89up3a247ypMj2xrqM"), 54 | scale: 8, 55 | }); 56 | 57 | export const auryToken: OrcaToken = Object.freeze({ 58 | tag: "AURY", 59 | name: "Aurory", 60 | mint: new PublicKey("AURYydfxJib1ZkTir1Jn1J9ECYUtjb6rKQVmtYaixWPP"), 61 | scale: 9, 62 | }); 63 | 64 | export const avaxToken: OrcaToken = Object.freeze({ 65 | tag: "AVAX", 66 | name: "Avalanche", 67 | mint: new PublicKey("AUrMpCDYYcPuHhyNX8gEEqbmDPFUpBpHrNW3vPeCFn5Z"), 68 | scale: 9, 69 | }); 70 | 71 | export const basisToken: OrcaToken = Object.freeze({ 72 | tag: "BASIS", 73 | name: "basis.markets", 74 | mint: new PublicKey("Basis9oJw9j8cw53oMV7iqsgo6ihi9ALw4QR31rcjUJa"), 75 | scale: 6, 76 | }); 77 | 78 | export const blockToken: OrcaToken = Object.freeze({ 79 | tag: "BLOCK", 80 | name: "Blockasset", 81 | mint: new PublicKey("NFTUkR4u7wKxy9QLaX2TGvd9oZSWoMo4jqSJqdMb7Nk"), 82 | scale: 6, 83 | }); 84 | 85 | export const bopToken: OrcaToken = Object.freeze({ 86 | tag: "BOP", 87 | name: "Boring Protocol", 88 | mint: new PublicKey("BLwTnYKqf7u4qjgZrrsKeNs2EzWkMLqVCu6j8iHyrNA3"), 89 | scale: 8, 90 | }); 91 | 92 | export const btcToken: OrcaToken = Object.freeze({ 93 | tag: "BTC", 94 | name: "Bitcoin", 95 | mint: new PublicKey("9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E"), 96 | scale: 6, 97 | }); 98 | 99 | export const catoToken: OrcaToken = Object.freeze({ 100 | tag: "CATO", 101 | name: "CATO", 102 | mint: new PublicKey("5p2zjqCd1WJzAVgcEnjhb9zWDU7b9XVhFhx4usiyN7jB"), 103 | scale: 9, 104 | }); 105 | 106 | export const caveToken: OrcaToken = Object.freeze({ 107 | tag: "CAVE", 108 | name: "Crypto Cavemen", 109 | mint: new PublicKey("4SZjjNABoqhbd4hnapbvoEPEqT8mnNkfbEoAwALf1V8t"), 110 | scale: 6, 111 | }); 112 | 113 | export const celoToken: OrcaToken = Object.freeze({ 114 | tag: "CELO", 115 | name: "Celo", 116 | mint: new PublicKey("GNCjk3FmPPgZTkbQRSxr6nCvLtYMbXKMnRxg8BgJs62e"), 117 | scale: 9, 118 | }); 119 | 120 | export const chicksToken: OrcaToken = Object.freeze({ 121 | tag: "CHICKS", 122 | name: "SolChicks Token", 123 | mint: new PublicKey("cxxShYRVcepDudXhe7U62QHvw8uBJoKFifmzggGKVC2"), 124 | scale: 9, 125 | }); 126 | 127 | export const cmfiToken: OrcaToken = Object.freeze({ 128 | tag: "CMFI", 129 | name: "Compendium.Fi", 130 | mint: new PublicKey("5Wsd311hY8NXQhkt9cWHwTnqafk7BGEbLu8Py3DSnPAr"), 131 | scale: 6, 132 | }); 133 | 134 | export const copeToken: OrcaToken = Object.freeze({ 135 | tag: "COPE", 136 | name: "Cope", 137 | mint: new PublicKey("8HGyAAB1yoM1ttS7pXjHMa3dukTFGQggnFFH3hJZgzQh"), 138 | scale: 6, 139 | }); 140 | 141 | export const dflToken: OrcaToken = Object.freeze({ 142 | tag: "DFL", 143 | name: "DeFi Land", 144 | mint: new PublicKey("DFL1zNkaGPWm1BqAVqRjCZvHmwTFrEaJtbzJWgseoNJh"), 145 | scale: 9, 146 | }); 147 | 148 | export const ethToken: OrcaToken = Object.freeze({ 149 | tag: "ETH", 150 | name: "Ethereum", 151 | mint: new PublicKey("2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk"), 152 | scale: 6, 153 | }); 154 | 155 | export const fabToken: OrcaToken = Object.freeze({ 156 | tag: "FAB", 157 | name: "Fabric", 158 | mint: new PublicKey("EdAhkbj5nF9sRM7XN7ewuW8C9XEUMs8P7cnoQ57SYE96"), 159 | scale: 9, 160 | }); 161 | 162 | export const fantToken: OrcaToken = Object.freeze({ 163 | tag: "FANT", 164 | name: "Phantasia", 165 | mint: new PublicKey("FANTafPFBAt93BNJVpdu25pGPmca3RfwdsDsRrT3LX1r"), 166 | scale: 6, 167 | }); 168 | 169 | export const fidaToken: OrcaToken = Object.freeze({ 170 | tag: "FIDA", 171 | name: "Bonfida", 172 | mint: new PublicKey("EchesyfXePKdLtoiZSL8pBe8Myagyy8ZRqsACNCFGnvp"), 173 | scale: 6, 174 | }); 175 | 176 | export const frktToken: OrcaToken = Object.freeze({ 177 | tag: "FRKT", 178 | name: "FRAKT Token", 179 | mint: new PublicKey("ErGB9xa24Szxbk1M28u2Tx8rKPqzL6BroNkkzk5rG4zj"), 180 | scale: 8, 181 | }); 182 | 183 | export const ftmToken: OrcaToken = Object.freeze({ 184 | tag: "FTM", 185 | name: "Fantom", 186 | mint: new PublicKey("EsPKhGTMf3bGoy4Qm7pCv3UCcWqAmbC1UGHBTDxRjjD4"), 187 | scale: 9, 188 | }); 189 | 190 | export const fttToken: OrcaToken = Object.freeze({ 191 | tag: "FTT", 192 | name: "FTX Token", 193 | mint: new PublicKey("AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3"), 194 | scale: 6, 195 | }); 196 | 197 | export const geneToken: OrcaToken = Object.freeze({ 198 | tag: "GENE", 199 | name: "Genopets", 200 | mint: new PublicKey("GENEtH5amGSi8kHAtQoezp1XEXwZJ8vcuePYnXdKrMYz"), 201 | scale: 9, 202 | }); 203 | 204 | export const gmtToken: OrcaToken = Object.freeze({ 205 | tag: "GMT", 206 | name: "STEPN", 207 | mint: new PublicKey("7i5KKsX2weiTkry7jA4ZwSuXGhs5eJBEjY8vVxR4pfRx"), 208 | scale: 9, 209 | }); 210 | 211 | export const gofxToken: OrcaToken = Object.freeze({ 212 | tag: "GOFX", 213 | name: "GooseFX", 214 | mint: new PublicKey("GFX1ZjR2P15tmrSwow6FjyDYcEkoFb4p4gJCpLBjaxHD"), 215 | scale: 9, 216 | }); 217 | 218 | export const grapeToken: OrcaToken = Object.freeze({ 219 | tag: "GRAPE", 220 | name: "Grape", 221 | mint: new PublicKey("8upjSpvjcdpuzhfR1zriwg5NXkwDruejqNE9WNbPRtyA"), 222 | scale: 6, 223 | }); 224 | 225 | export const gstToken: OrcaToken = Object.freeze({ 226 | tag: "GST", 227 | name: "GST", 228 | mint: new PublicKey("AFbX8oGjGpmVFywbVouvhQSRmiW2aR1mohfahi4Y2AdB"), 229 | scale: 9, 230 | }); 231 | 232 | export const hbbToken: OrcaToken = Object.freeze({ 233 | tag: "HBB", 234 | name: "Hubble", 235 | mint: new PublicKey("HBB111SCo9jkCejsZfz8Ec8nH7T6THF8KEKSnvwT6XK6"), 236 | scale: 6, 237 | }); 238 | 239 | export const hdgToken: OrcaToken = Object.freeze({ 240 | tag: "HDG", 241 | name: "Hedge Token", 242 | mint: new PublicKey("5PmpMzWjraf3kSsGEKtqdUsCoLhptg4yriZ17LKKdBBy"), 243 | scale: 9, 244 | }); 245 | 246 | export const ivnToken: OrcaToken = Object.freeze({ 247 | tag: "IVN", 248 | name: "Investin", 249 | mint: new PublicKey("iVNcrNE9BRZBC9Aqf753iZiZfbszeAVUoikgT9yvr2a"), 250 | scale: 6, 251 | }); 252 | 253 | export const jetToken: OrcaToken = Object.freeze({ 254 | tag: "JET", 255 | name: "JET", 256 | mint: new PublicKey("JET6zMJWkCN9tpRT2v2jfAmm5VnQFDpUBCyaKojmGtz"), 257 | scale: 9, 258 | }); 259 | 260 | export const jsolToken: OrcaToken = Object.freeze({ 261 | tag: "JSOL", 262 | name: "JPool", 263 | mint: new PublicKey("7Q2afV64in6N6SeZsAAB81TJzwDoD6zpqmHkzi9Dcavn"), 264 | scale: 9, 265 | }); 266 | 267 | export const kinToken: OrcaToken = Object.freeze({ 268 | tag: "KIN", 269 | name: "Kin", 270 | mint: new PublicKey("kinXdEcpDQeHPEuQnqmUgtYykqKGVFq6CeVX5iAHJq6"), 271 | scale: 5, 272 | }); 273 | 274 | export const kuroToken: OrcaToken = Object.freeze({ 275 | tag: "KURO", 276 | name: "Kurobi", 277 | mint: new PublicKey("2Kc38rfQ49DFaKHQaWbijkE7fcymUMLY5guUiUsDmFfn"), 278 | scale: 6, 279 | }); 280 | 281 | export const larixToken: OrcaToken = Object.freeze({ 282 | tag: "LARIX", 283 | name: "Larix", 284 | mint: new PublicKey("Lrxqnh6ZHKbGy3dcrCED43nsoLkM1LTzU2jRfWe8qUC"), 285 | scale: 6, 286 | }); 287 | 288 | export const liqToken: OrcaToken = Object.freeze({ 289 | tag: "LIQ", 290 | name: "LIQ Protocol", 291 | mint: new PublicKey("4wjPQJ6PrkC4dHhYghwJzGBVP78DkBzA2U3kHoFNBuhj"), 292 | scale: 6, 293 | }); 294 | 295 | export const mapsToken: OrcaToken = Object.freeze({ 296 | tag: "MAPS", 297 | name: "MAPS", 298 | mint: new PublicKey("MAPS41MDahZ9QdKXhVa4dWB9RuyfV4XqhyAZ8XcYepb"), 299 | scale: 6, 300 | }); 301 | 302 | export const meanToken: OrcaToken = Object.freeze({ 303 | tag: "MEAN", 304 | name: "Meanfi", 305 | mint: new PublicKey("MEANeD3XDdUmNMsRGjASkSWdC8prLYsoRJ61pPeHctD"), 306 | scale: 6, 307 | }); 308 | 309 | export const mediaToken: OrcaToken = Object.freeze({ 310 | tag: "MEDIA", 311 | name: "Media Network", 312 | mint: new PublicKey("ETAtLmCmsoiEEKfNrHKJ2kYy3MoABhU6NQvpSfij5tDs"), 313 | scale: 6, 314 | }); 315 | 316 | export const merToken: OrcaToken = Object.freeze({ 317 | tag: "MER", 318 | name: "Mercurial", 319 | mint: new PublicKey("MERt85fc5boKw3BW1eYdxonEuJNvXbiMbs6hvheau5K"), 320 | scale: 6, 321 | }); 322 | 323 | export const mmaToken: OrcaToken = Object.freeze({ 324 | tag: "MMA", 325 | name: "MMA Gaming", 326 | mint: new PublicKey("MMAx26JtJgSWv6yH48nEHCGZcVvRbf9Lt9ALa7jSipe"), 327 | scale: 9, 328 | }); 329 | 330 | export const mndeToken: OrcaToken = Object.freeze({ 331 | tag: "MNDE", 332 | name: "Marinade Governance", 333 | mint: new PublicKey("MNDEFzGvMt87ueuHvVU9VcTqsAP5b3fTGPsHuuPA5ey"), 334 | scale: 9, 335 | }); 336 | 337 | export const mngoToken: OrcaToken = Object.freeze({ 338 | tag: "MNGO", 339 | name: "Mango Markets", 340 | mint: new PublicKey("MangoCzJ36AjZyKwVj3VnYU4GTonjfVEnJmvvWaxLac"), 341 | scale: 6, 342 | }); 343 | 344 | export const ninjaToken: OrcaToken = Object.freeze({ 345 | tag: "NINJA", 346 | name: "NINJA", 347 | mint: new PublicKey("FgX1WD9WzMU3yLwXaFSarPfkgzjLb2DZCqmkx9ExpuvJ"), 348 | scale: 6, 349 | }); 350 | 351 | export const novaToken: OrcaToken = Object.freeze({ 352 | tag: "NOVA", 353 | name: "Nova Finance", 354 | mint: new PublicKey("BDrL8huis6S5tpmozaAaT5zhE5A7ZBAB2jMMvpKEeF8A"), 355 | scale: 9, 356 | }); 357 | 358 | export const oogiToken: OrcaToken = Object.freeze({ 359 | tag: "OOGI", 360 | name: "OOGI", 361 | mint: new PublicKey("H7Qc9APCWWGDVxGD5fJHmLTmdEgT9GFatAKFNg6sHh8A"), 362 | scale: 9, 363 | }); 364 | 365 | export const orcaToken: OrcaToken = Object.freeze({ 366 | tag: "ORCA", 367 | name: "Orca", 368 | mint: new PublicKey("orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE"), 369 | scale: 6, 370 | }); 371 | 372 | export const oxyToken: OrcaToken = Object.freeze({ 373 | tag: "OXY", 374 | name: "Oxygen", 375 | mint: new PublicKey("z3dn17yLaGMKffVogeFHQ9zWVcXgqgf3PQnDsNs2g6M"), 376 | scale: 6, 377 | }); 378 | 379 | export const paiToken: OrcaToken = Object.freeze({ 380 | tag: "PAI", 381 | name: "Parrot Stable", 382 | mint: new PublicKey("Ea5SjE2Y6yvCeW5dYTn7PYMuW5ikXkvbGdcmSnXeaLjS"), 383 | scale: 6, 384 | }); 385 | 386 | export const polisToken: OrcaToken = Object.freeze({ 387 | tag: "POLIS", 388 | name: "Star Atlas DAO", 389 | mint: new PublicKey("poLisWXnNRwC6oBu1vHiuKQzFjGL4XDSu4g9qjz9qVk"), 390 | scale: 8, 391 | }); 392 | 393 | export const portToken: OrcaToken = Object.freeze({ 394 | tag: "PORT", 395 | name: "Port Finance", 396 | mint: new PublicKey("PoRTjZMPXb9T7dyU7tpLEZRQj7e6ssfAE62j2oQuc6y"), 397 | scale: 6, 398 | }); 399 | 400 | export const prtToken: OrcaToken = Object.freeze({ 401 | tag: "PRT", 402 | name: "Parrot Protocol", 403 | mint: new PublicKey("PRT88RkA4Kg5z7pKnezeNH4mafTvtQdfFgpQTGRjz44"), 404 | scale: 6, 405 | }); 406 | 407 | export const puffToken: OrcaToken = Object.freeze({ 408 | tag: "PUFF", 409 | name: "PUFF", 410 | mint: new PublicKey("G9tt98aYSznRk7jWsfuz9FnTdokxS6Brohdo9hSmjTRB"), 411 | scale: 9, 412 | }); 413 | 414 | export const rayToken: OrcaToken = Object.freeze({ 415 | tag: "RAY", 416 | name: "Raydium", 417 | mint: new PublicKey("4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R"), 418 | scale: 6, 419 | }); 420 | 421 | export const ropeToken: OrcaToken = Object.freeze({ 422 | tag: "ROPE", 423 | name: "Rope", 424 | mint: new PublicKey("8PMHT4swUMtBzgHnh5U564N5sjPSiUz2cjEQzFnnP1Fo"), 425 | scale: 9, 426 | }); 427 | 428 | export const runToken: OrcaToken = Object.freeze({ 429 | tag: "RUN", 430 | name: "Run", 431 | mint: new PublicKey("6F9XriABHfWhit6zmMUYAQBSy6XK5VF1cHXuW5LDpRtC"), 432 | scale: 9, 433 | }); 434 | 435 | export const samoToken: OrcaToken = Object.freeze({ 436 | tag: "SAMO", 437 | name: "Samoyedcoin", 438 | mint: new PublicKey("7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU"), 439 | scale: 9, 440 | }); 441 | 442 | export const saoToken: OrcaToken = Object.freeze({ 443 | tag: "SAO", 444 | name: "Sator", 445 | mint: new PublicKey("2HeykdKjzHKGm2LKHw8pDYwjKPiFEoXAz74dirhUgQvq"), 446 | scale: 9, 447 | }); 448 | 449 | export const sbToken: OrcaToken = Object.freeze({ 450 | tag: "SB", 451 | name: "SuperBonds", 452 | mint: new PublicKey("SuperbZyz7TsSdSoFAZ6RYHfAWe9NmjXBLVQpS8hqdx"), 453 | scale: 6, 454 | }); 455 | 456 | export const sbrToken: OrcaToken = Object.freeze({ 457 | tag: "SBR", 458 | name: "Saber", 459 | mint: new PublicKey("Saber2gLauYim4Mvftnrasomsv6NvAuncvMEZwcLpD1"), 460 | scale: 6, 461 | }); 462 | 463 | export const scyToken: OrcaToken = Object.freeze({ 464 | tag: "SCY", 465 | name: "Synchrony", 466 | mint: new PublicKey("SCYfrGCw8aDiqdgcpdGjV6jp4UVVQLuphxTDLNWu36f"), 467 | scale: 9, 468 | }); 469 | 470 | export const sdogeToken: OrcaToken = Object.freeze({ 471 | tag: "SDOGE", 472 | name: "SolDoge", 473 | mint: new PublicKey("8ymi88q5DtmdNTn2sPRNFkvMkszMHuLJ1e3RVdWjPa3s"), 474 | scale: 0, 475 | }); 476 | 477 | export const seededToken: OrcaToken = Object.freeze({ 478 | tag: "SEEDED", 479 | name: "Seeded Network", 480 | mint: new PublicKey("seedEDBqu63tJ7PFqvcbwvThrYUkQeqT6NLf81kLibs"), 481 | scale: 9, 482 | }); 483 | 484 | export const shdwToken: OrcaToken = Object.freeze({ 485 | tag: "SHDW", 486 | name: "Shadow", 487 | mint: new PublicKey("SHDWyBxihqiCj6YekG2GUr7wqKLeLAMK1gHZck9pL6y"), 488 | scale: 9, 489 | }); 490 | 491 | export const slcToken: OrcaToken = Object.freeze({ 492 | tag: "SLC", 493 | name: "Solice", 494 | mint: new PublicKey("METAmTMXwdb8gYzyCPfXXFmZZw4rUsXX58PNsDg7zjL"), 495 | scale: 6, 496 | }); 497 | 498 | export const slimToken: OrcaToken = Object.freeze({ 499 | tag: "SLIM", 500 | name: "Solanium", 501 | mint: new PublicKey("xxxxa1sKNGwFtw2kFn8XauW9xq8hBZ5kVtcSesTT9fW"), 502 | scale: 6, 503 | }); 504 | 505 | export const slndToken: OrcaToken = Object.freeze({ 506 | tag: "SLND", 507 | name: "Solend", 508 | mint: new PublicKey("SLNDpmoWTVADgEdndyvWzroNL7zSi1dF9PC3xHGtPwp"), 509 | scale: 6, 510 | }); 511 | 512 | export const slrsToken: OrcaToken = Object.freeze({ 513 | tag: "SLRS", 514 | name: "Solrise Finance", 515 | mint: new PublicKey("SLRSSpSLUTP7okbCUBYStWCo1vUgyt775faPqz8HUMr"), 516 | scale: 6, 517 | }); 518 | 519 | export const snyToken: OrcaToken = Object.freeze({ 520 | tag: "SNY", 521 | name: "SNY", 522 | mint: new PublicKey("4dmKkXNHdgYsXqBHCuMikNQWwVomZURhYvkkX5c4pQ7y"), 523 | scale: 6, 524 | }); 525 | 526 | export const solToken: OrcaToken = Object.freeze({ 527 | tag: "SOL", 528 | name: "Solana", 529 | mint: new PublicKey("So11111111111111111111111111111111111111112"), 530 | scale: 9, 531 | }); 532 | 533 | export const sonarToken: OrcaToken = Object.freeze({ 534 | tag: "SONAR", 535 | name: "SonarWatch", 536 | mint: new PublicKey("sonarX4VtVkQemriJeLm6CKeW3GDMyiBnnAEMw1MRAE"), 537 | scale: 9, 538 | }); 539 | 540 | export const srmToken: OrcaToken = Object.freeze({ 541 | tag: "SRM", 542 | name: "Serum", 543 | mint: new PublicKey("SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt"), 544 | scale: 6, 545 | }); 546 | 547 | export const stepToken: OrcaToken = Object.freeze({ 548 | tag: "STEP", 549 | name: "Step", 550 | mint: new PublicKey("StepAscQoEioFxxWGnh2sLBDFp9d8rvKz2Yp39iDpyT"), 551 | scale: 9, 552 | }); 553 | 554 | export const sunnyToken: OrcaToken = Object.freeze({ 555 | tag: "SUNNY", 556 | name: "Sunny Aggregator", 557 | mint: new PublicKey("SUNNYWgPQmFxe9wTZzNK7iPnJ3vYDrkgnxJRJm1s3ag"), 558 | scale: 6, 559 | }); 560 | 561 | export const sypToken: OrcaToken = Object.freeze({ 562 | tag: "SYP", 563 | name: "Sypool", 564 | mint: new PublicKey("FnKE9n6aGjQoNWRBZXy4RW6LZVao7qwBonUbiD7edUmZ"), 565 | scale: 9, 566 | }); 567 | 568 | export const takiToken: OrcaToken = Object.freeze({ 569 | tag: "TAKI", 570 | name: "Taki", 571 | mint: new PublicKey("Taki7fi3Zicv7Du1xNAWLaf6mRK7ikdn77HeGzgwvo4"), 572 | scale: 9, 573 | }); 574 | 575 | export const tttToken: OrcaToken = Object.freeze({ 576 | tag: "TTT", 577 | name: "TabTrader", 578 | mint: new PublicKey("FNFKRV3V8DtA3gVJN6UshMiLGYA8izxFwkNWmJbFjmRj"), 579 | scale: 6, 580 | }); 581 | 582 | export const tulipToken: OrcaToken = Object.freeze({ 583 | tag: "TULIP", 584 | name: "Tulip Protocol", 585 | mint: new PublicKey("TuLipcqtGVXP9XR62wM8WWCm6a9vhLs7T1uoWBk6FDs"), 586 | scale: 6, 587 | }); 588 | 589 | export const unqToken: OrcaToken = Object.freeze({ 590 | tag: "UNQ", 591 | name: "UNQ", 592 | mint: new PublicKey("UNQtEecZ5Zb4gSSVHCAWUQEoNnSVEbWiKCi1v9kdUJJ"), 593 | scale: 6, 594 | }); 595 | 596 | export const upsToken: OrcaToken = Object.freeze({ 597 | tag: "UPS", 598 | name: "UPFI Network", 599 | mint: new PublicKey("EwJN2GqUGXXzYmoAciwuABtorHczTA5LqbukKXV1viH7"), 600 | scale: 6, 601 | }); 602 | 603 | export const usdcToken: OrcaToken = Object.freeze({ 604 | tag: "USDC", 605 | name: "USD Coin", 606 | mint: new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"), 607 | scale: 6, 608 | }); 609 | 610 | export const usdhToken: OrcaToken = Object.freeze({ 611 | tag: "USDH", 612 | name: "USDH", 613 | mint: new PublicKey("USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX"), 614 | scale: 6, 615 | }); 616 | 617 | export const usdtToken: OrcaToken = Object.freeze({ 618 | tag: "USDT", 619 | name: "Tether USD", 620 | mint: new PublicKey("Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB"), 621 | scale: 6, 622 | }); 623 | 624 | export const ushToken: OrcaToken = Object.freeze({ 625 | tag: "USH", 626 | name: "Hedge USD", 627 | mint: new PublicKey("9iLH8T7zoWhY7sBmj1WK9ENbWdS1nL8n9wAxaeRitTa6"), 628 | scale: 9, 629 | }); 630 | 631 | export const uxpToken: OrcaToken = Object.freeze({ 632 | tag: "UXP", 633 | name: "UXD Protocol Token", 634 | mint: new PublicKey("UXPhBoR3qG4UCiGNJfV7MqhHyFqKN68g45GoYvAeL2M"), 635 | scale: 9, 636 | }); 637 | 638 | export const wagToken: OrcaToken = Object.freeze({ 639 | tag: "WAG", 640 | name: "Waggle", 641 | mint: new PublicKey("5tN42n9vMi6ubp67Uy4NnmM5DMZYN8aS8GeB3bEDHr6E"), 642 | scale: 9, 643 | }); 644 | 645 | export const wmpToken: OrcaToken = Object.freeze({ 646 | tag: "WMP", 647 | name: "Whalemap", 648 | mint: new PublicKey("BygDd5LURoqztD3xETc99WCxLUbTi6WYSht9XiBgZ4HW"), 649 | scale: 9, 650 | }); 651 | 652 | export const woofToken: OrcaToken = Object.freeze({ 653 | tag: "WOOF", 654 | name: "WOOF Token", 655 | mint: new PublicKey("9nEqaUcb16sQ3Tn1psbkWqyhPdLmfHWjKGymREjsAgTE"), 656 | scale: 6, 657 | }); 658 | 659 | export const zbcToken: OrcaToken = Object.freeze({ 660 | tag: "ZBC", 661 | name: "Zebec Protocol", 662 | mint: new PublicKey("zebeczgi5fSEtbpfQKVZKCJ3WgYXxjkMUkNNx7fLKAF"), 663 | scale: 9, 664 | }); 665 | 666 | export const zigToken: OrcaToken = Object.freeze({ 667 | tag: "ZIG", 668 | name: "Zignaly", 669 | mint: new PublicKey("ANqY8h3sRSwkC29FvGJenAh7VGRABVVx7Ls6Mq4BuGT"), 670 | scale: 9, 671 | }); 672 | 673 | export const daosolToken: OrcaToken = Object.freeze({ 674 | tag: "daoSOL", 675 | name: "daoSOL Token", 676 | mint: new PublicKey("GEJpt3Wjmr628FqXxTgxMce1pLntcPV4uFi8ksxMyPQh"), 677 | scale: 9, 678 | }); 679 | 680 | export const msolToken: OrcaToken = Object.freeze({ 681 | tag: "mSOL", 682 | name: "Marinade.finance", 683 | mint: new PublicKey("mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So"), 684 | scale: 9, 685 | }); 686 | 687 | export const psolToken: OrcaToken = Object.freeze({ 688 | tag: "pSOL", 689 | name: "pSOL", 690 | mint: new PublicKey("9EaLkQrbjmbbuZG9Wdpo8qfNUEjHATJFSycEmw6f1rGX"), 691 | scale: 9, 692 | }); 693 | 694 | export const srlyv2Token: OrcaToken = Object.freeze({ 695 | tag: "sRLYv2", 696 | name: "Rally (Solana)", 697 | mint: new PublicKey("RLYv2ubRMDLcGG2UyvPmnPmkfuQTsMbg4Jtygc7dmnq"), 698 | scale: 9, 699 | }); 700 | 701 | export const srlyToken: OrcaToken = Object.freeze({ 702 | tag: "sRLY", 703 | name: "Rally Solana", 704 | mint: new PublicKey("sRLY3migNrkC1HLgqotpvi66qGkdNedqPZ9TJpAQhyh"), 705 | scale: 9, 706 | }); 707 | 708 | export const scnsolToken: OrcaToken = Object.freeze({ 709 | tag: "scnSOL", 710 | name: "Socean Staked Sol", 711 | mint: new PublicKey("5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm"), 712 | scale: 9, 713 | }); 714 | 715 | export const stsolToken: OrcaToken = Object.freeze({ 716 | tag: "stSOL", 717 | name: "Lido Staked SOL", 718 | mint: new PublicKey("7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj"), 719 | scale: 9, 720 | }); 721 | 722 | export const whapiToken: OrcaToken = Object.freeze({ 723 | tag: "wHAPI", 724 | name: "HAPI", 725 | mint: new PublicKey("6VNKqgz9hk7zRShTFdg5AnkfKwZUcojzwAkzxSH3bnUm"), 726 | scale: 9, 727 | }); 728 | 729 | export const wldoToken: OrcaToken = Object.freeze({ 730 | tag: "wLDO", 731 | name: "Lido DAO", 732 | mint: new PublicKey("HZRCwxP2Vq9PCpPXooayhJ2bxTpo5xfpQrwB1svh332p"), 733 | scale: 8, 734 | }); 735 | 736 | export const wlunaToken: OrcaToken = Object.freeze({ 737 | tag: "wLUNA", 738 | name: "Terra", 739 | mint: new PublicKey("F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W"), 740 | scale: 6, 741 | }); 742 | 743 | export const wustToken: OrcaToken = Object.freeze({ 744 | tag: "wUST", 745 | name: "TerraUSD (Wormhole)", 746 | mint: new PublicKey("9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i"), 747 | scale: 6, 748 | }); 749 | 750 | export const whethToken: OrcaToken = Object.freeze({ 751 | tag: "whETH", 752 | name: "Ethereum", 753 | mint: new PublicKey("7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs"), 754 | scale: 8, 755 | }); 756 | 757 | export const wstethToken: OrcaToken = Object.freeze({ 758 | tag: "wstETH", 759 | name: "Lido Staked Ether", 760 | mint: new PublicKey("ZScHuTtqZukUrtZS43teTKGs2VqkKL8k4QCouR2n6Uo"), 761 | scale: 8, 762 | }); 763 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./public"; 2 | -------------------------------------------------------------------------------- /src/model/orca-factory.ts: -------------------------------------------------------------------------------- 1 | import { Connection } from "@solana/web3.js"; 2 | import { OrcaPoolConfig, OrcaPool, OrcaFarmConfig, OrcaFarm, Network } from ".."; 3 | import { orcaPoolConfigs, orcaFarmConfigs } from "../constants"; 4 | import { orcaDevnetFarmConfigs, orcaDevnetPoolConfigs } from "../constants/devnet"; 5 | import { getDevnetFarm, getDevnetPool } from "../public/devnet"; 6 | import { OrcaFarmImpl } from "./orca/farm/orca-farm"; 7 | import { OrcaPoolImpl } from "./orca/pool/orca-pool"; 8 | 9 | export class OrcaFactory { 10 | getPool(connection: Connection, network: Network, config: OrcaPoolConfig): OrcaPool { 11 | if (network === Network.DEVNET) { 12 | const devnetConfig = getDevnetPool(config); 13 | return new OrcaPoolImpl(connection, network, orcaDevnetPoolConfigs[devnetConfig]); 14 | } 15 | 16 | return new OrcaPoolImpl(connection, network, orcaPoolConfigs[config]); 17 | } 18 | 19 | getFarm(connection: Connection, network: Network, config: OrcaFarmConfig): OrcaFarm { 20 | if (network === Network.DEVNET) { 21 | const devnetConfig = getDevnetFarm(config); 22 | return new OrcaFarmImpl(connection, orcaDevnetFarmConfigs[devnetConfig]); 23 | } 24 | 25 | return new OrcaFarmImpl(connection, orcaFarmConfigs[config]); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/model/orca/farm/farm-types.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey } from "@solana/web3.js"; 2 | 3 | /** 4 | * An Orca aquafarm token 5 | * @param address The farm account address 6 | * @param farmTokenMint Mint address for the farm token 7 | * @param rewardTokenMint Mint address for the farm reward token 8 | * @param rewardTokenDecimals Number of decimal places for the reward token 9 | * @param baseTokenMint Mint address for the base token 10 | * @param baseTokenDecimals Number of decimal places for the base token 11 | */ 12 | export type OrcaFarmParams = { 13 | address: PublicKey; 14 | farmTokenMint: PublicKey; 15 | rewardTokenMint: PublicKey; 16 | rewardTokenDecimals: number; 17 | baseTokenMint: PublicKey; 18 | baseTokenDecimals: number; 19 | }; 20 | -------------------------------------------------------------------------------- /src/model/orca/farm/orca-farm.ts: -------------------------------------------------------------------------------- 1 | import { Aquafarm, fetchGlobalFarms, fetchUserFarms, getUserFarmAddress } from "@orca-so/aquafarm"; 2 | import { TOKEN_PROGRAM_ID, u64 } from "@solana/spl-token"; 3 | import { Connection, Keypair, PublicKey } from "@solana/web3.js"; 4 | import Decimal from "decimal.js"; 5 | import { 6 | deriveAssociatedTokenAddress, 7 | deserializeAccount, 8 | OrcaU64, 9 | ORCA_FARM_ID, 10 | resolveOrCreateAssociatedTokenAddress, 11 | TransactionBuilder, 12 | TransactionPayload, 13 | U64Utils, 14 | } from "../../.."; 15 | import { OrcaFarm, ZERO } from "../../../public/"; 16 | import { 17 | createFarmConvertTokensInstruction, 18 | createFarmHarvestRewardInstruction, 19 | createFarmRevertTokensInstruction, 20 | createInitUserFarmInstruction, 21 | } from "../../../public/utils/web3/instructions/farm-instructions"; 22 | import { createApprovalInstruction } from "../../../public/utils/web3/instructions/pool-instructions"; 23 | import { Owner } from "../../../public/utils/web3/key-utils"; 24 | import { OrcaFarmParams } from "./farm-types"; 25 | 26 | export class OrcaFarmImpl implements OrcaFarm { 27 | private connection: Connection; 28 | private farmParams: OrcaFarmParams; 29 | 30 | constructor(connection: Connection, config: OrcaFarmParams) { 31 | this.connection = connection; 32 | this.farmParams = config; 33 | } 34 | 35 | public async getFarmBalance(owner: PublicKey): Promise { 36 | const address = await deriveAssociatedTokenAddress(owner, this.farmParams.farmTokenMint); 37 | 38 | const accountInfo = await this.connection.getAccountInfo(address); 39 | 40 | // User does not have a balance for this account 41 | if (accountInfo == undefined) { 42 | return OrcaU64.fromNumber(0, this.farmParams.baseTokenDecimals); 43 | } 44 | const result = deserializeAccount(accountInfo?.data); 45 | if (result == undefined) { 46 | throw new Error("Failed to parse user account for LP token."); 47 | } 48 | 49 | return OrcaU64.fromU64(result.amount, this.farmParams.baseTokenDecimals); 50 | } 51 | 52 | public async getFarmSupply(): Promise { 53 | const context = await this.connection.getTokenSupply(this.farmParams.farmTokenMint); 54 | 55 | const amt = new u64(context.value.amount); 56 | 57 | return OrcaU64.fromU64(amt, this.farmParams.baseTokenDecimals); 58 | } 59 | 60 | public async deposit( 61 | owner: Keypair | PublicKey, 62 | baseTokenAmount: Decimal | OrcaU64 63 | ): Promise { 64 | const _owner = new Owner(owner); 65 | const ownerAddress = _owner.publicKey; 66 | 67 | const baseTokenAmount_U64 = U64Utils.toFarmU64( 68 | baseTokenAmount, 69 | this.farmParams, 70 | "baseTokenAmount" 71 | ); 72 | 73 | const { address: farmAddress, rewardTokenMint } = this.farmParams; 74 | const userFarmPublicKey = ( 75 | await getUserFarmAddress(farmAddress, ownerAddress, TOKEN_PROGRAM_ID, ORCA_FARM_ID) 76 | )[0]; 77 | 78 | const globalFarms = await fetchGlobalFarms(this.connection, [farmAddress], ORCA_FARM_ID); 79 | const userFarms = await fetchUserFarms( 80 | this.connection, 81 | ownerAddress, 82 | [farmAddress], 83 | ORCA_FARM_ID 84 | ); 85 | 86 | if (!globalFarms) { 87 | throw new Error("Failed to get globalFarms information"); 88 | } 89 | const farm = new Aquafarm(globalFarms[0], ORCA_FARM_ID, userFarms && userFarms[0]); 90 | 91 | // If the user lacks the user farm, create it 92 | const initUserFarmInstruction = await createInitUserFarmInstruction( 93 | farm, 94 | userFarmPublicKey, 95 | _owner 96 | ); 97 | 98 | // If the user lacks the farm token account, create it 99 | const { address: userFarmTokenPublicKey, ...resolveFarmTokenInstructions } = 100 | await resolveOrCreateAssociatedTokenAddress( 101 | this.connection, 102 | _owner, 103 | farm.globalFarm.farmTokenMint 104 | ); 105 | 106 | // If the user lacks the reward token account, create it 107 | const { address: userRewardTokenPublicKey, ...resolveRewardTokenInstructions } = 108 | await resolveOrCreateAssociatedTokenAddress(this.connection, _owner, rewardTokenMint); 109 | 110 | // If the user lacks the base token account, create it 111 | const { address: userBaseTokenPublicKey, ...resolveBaseTokenInstructions } = 112 | await resolveOrCreateAssociatedTokenAddress( 113 | this.connection, 114 | _owner, 115 | this.farmParams.baseTokenMint 116 | ); 117 | 118 | // Approve transfer of base token to be converted to farm tokens 119 | const { userTransferAuthority, ...transferBaseTokenInstruction } = createApprovalInstruction( 120 | ownerAddress, 121 | baseTokenAmount_U64, 122 | userBaseTokenPublicKey 123 | ); 124 | 125 | // Convert base tokens to farm tokens 126 | const convertToFarmTokens = await createFarmConvertTokensInstruction( 127 | farm, 128 | userTransferAuthority.publicKey, 129 | userBaseTokenPublicKey, 130 | userFarmTokenPublicKey, 131 | userRewardTokenPublicKey, 132 | baseTokenAmount_U64, 133 | userFarmPublicKey, 134 | _owner 135 | ); 136 | 137 | return await new TransactionBuilder(this.connection, ownerAddress, _owner) 138 | .addInstruction(initUserFarmInstruction) 139 | .addInstruction(resolveFarmTokenInstructions) 140 | .addInstruction(resolveBaseTokenInstructions) 141 | .addInstruction(resolveRewardTokenInstructions) 142 | .addInstruction(transferBaseTokenInstruction) 143 | .addInstruction(convertToFarmTokens) 144 | .build(); 145 | } 146 | 147 | public async withdraw( 148 | owner: Keypair | PublicKey, 149 | baseTokenAmount: Decimal | OrcaU64 150 | ): Promise { 151 | const _owner = new Owner(owner); 152 | const ownerAddress = _owner.publicKey; 153 | 154 | const baseTokenAmount_U64 = U64Utils.toFarmU64( 155 | baseTokenAmount, 156 | this.farmParams, 157 | "baseTokenAmount" 158 | ); 159 | 160 | const { address: farmAddress, rewardTokenMint } = this.farmParams; 161 | const userFarmPublicKey = ( 162 | await getUserFarmAddress(farmAddress, ownerAddress, TOKEN_PROGRAM_ID, ORCA_FARM_ID) 163 | )[0]; 164 | 165 | const globalFarms = await fetchGlobalFarms(this.connection, [farmAddress], ORCA_FARM_ID); 166 | const userFarms = await fetchUserFarms( 167 | this.connection, 168 | ownerAddress, 169 | [farmAddress], 170 | ORCA_FARM_ID 171 | ); 172 | 173 | if (!globalFarms) { 174 | throw new Error("Failed to get globalFarms information"); 175 | } 176 | const farm = new Aquafarm(globalFarms[0], ORCA_FARM_ID, userFarms && userFarms[0]); 177 | 178 | if (!farm.isUserFarmInitialized()) { 179 | throw new Error("Failed to get userFarm information. Warning: withdraw from deposit address"); 180 | } 181 | 182 | // If the user lacks the farm token account, create it 183 | const { address: userFarmTokenPublicKey, ...resolveFarmTokenInstructions } = 184 | await resolveOrCreateAssociatedTokenAddress( 185 | this.connection, 186 | _owner, 187 | farm.globalFarm.farmTokenMint 188 | ); 189 | 190 | // If the user lacks the reward token account, create it 191 | const { address: userRewardTokenPublicKey, ...resolveRewardTokenInstructions } = 192 | await resolveOrCreateAssociatedTokenAddress(this.connection, _owner, rewardTokenMint); 193 | 194 | // Get user's baseToken token account 195 | const { address: userBaseTokenPublicKey, ...resolveBaseTokenInstructions } = 196 | await resolveOrCreateAssociatedTokenAddress( 197 | this.connection, 198 | _owner, 199 | this.farmParams.baseTokenMint 200 | ); 201 | 202 | // Approve transfer of farm tokens to be reverted to base tokens 203 | const { userTransferAuthority, ...transferFarmTokenInstruction } = createApprovalInstruction( 204 | ownerAddress, 205 | baseTokenAmount_U64, 206 | userFarmTokenPublicKey 207 | ); 208 | 209 | // Revert farm tokens to base tokens 210 | const revertFromFarmTokens = await createFarmRevertTokensInstruction( 211 | farm, 212 | userTransferAuthority.publicKey, 213 | userBaseTokenPublicKey, 214 | userFarmTokenPublicKey, 215 | userRewardTokenPublicKey, 216 | baseTokenAmount_U64, 217 | _owner 218 | ); 219 | 220 | return await new TransactionBuilder(this.connection, ownerAddress, _owner) 221 | .addInstruction(resolveFarmTokenInstructions) 222 | .addInstruction(resolveRewardTokenInstructions) 223 | .addInstruction(resolveBaseTokenInstructions) 224 | .addInstruction(transferFarmTokenInstruction) 225 | .addInstruction(revertFromFarmTokens) 226 | .build(); 227 | } 228 | 229 | public async getHarvestableAmount(ownerPublicKey: PublicKey): Promise { 230 | const { address: farmAddress, baseTokenDecimals } = this.farmParams; 231 | 232 | const globalFarms = await fetchGlobalFarms(this.connection, [farmAddress], ORCA_FARM_ID); 233 | const userFarms = await fetchUserFarms( 234 | this.connection, 235 | ownerPublicKey, 236 | [farmAddress], 237 | ORCA_FARM_ID 238 | ); 239 | 240 | if (!globalFarms) { 241 | throw new Error("Failed to get globalFarms information"); 242 | } 243 | 244 | const farm = new Aquafarm(globalFarms[0], ORCA_FARM_ID, userFarms && userFarms[0]); 245 | 246 | if (!farm.isUserFarmInitialized()) { 247 | return OrcaU64.fromU64(ZERO, baseTokenDecimals); 248 | } 249 | 250 | const farmSupply = await this.getFarmSupply(); 251 | const harvestableAmount = farm.getCurrentHarvestableAmount(farmSupply.toU64()) ?? ZERO; 252 | return OrcaU64.fromU64(harvestableAmount, baseTokenDecimals); 253 | } 254 | 255 | public async harvest(owner: Keypair | PublicKey): Promise { 256 | const _owner = new Owner(owner); 257 | const ownerAddress = _owner.publicKey; 258 | 259 | const { address: farmAddress, rewardTokenMint } = this.farmParams; 260 | 261 | const globalFarms = await fetchGlobalFarms(this.connection, [farmAddress], ORCA_FARM_ID); 262 | const userFarms = await fetchUserFarms( 263 | this.connection, 264 | ownerAddress, 265 | [farmAddress], 266 | ORCA_FARM_ID 267 | ); 268 | 269 | if (!globalFarms) { 270 | throw new Error("Failed to get globalFarms information"); 271 | } 272 | 273 | const farm = new Aquafarm(globalFarms[0], ORCA_FARM_ID, userFarms && userFarms[0]); 274 | 275 | if (!farm.isUserFarmInitialized()) { 276 | throw new Error("Failed to get userFarm information"); 277 | } 278 | 279 | // If the user lacks the reward token account, create it 280 | const { address: userRewardTokenPublicKey, ...resolveRewardTokenInstructions } = 281 | await resolveOrCreateAssociatedTokenAddress(this.connection, _owner, rewardTokenMint); 282 | 283 | const harvestRewardInstruction = await createFarmHarvestRewardInstruction( 284 | farm, 285 | userRewardTokenPublicKey, 286 | _owner 287 | ); 288 | 289 | return await new TransactionBuilder(this.connection, ownerAddress, _owner) 290 | .addInstruction(resolveRewardTokenInstructions) 291 | .addInstruction(harvestRewardInstruction) 292 | .build(); 293 | } 294 | 295 | public async getDailyEmissions(): Promise { 296 | const { address, rewardTokenDecimals } = this.farmParams; 297 | 298 | const globalFarms = await fetchGlobalFarms(this.connection, [address], ORCA_FARM_ID); 299 | 300 | if (!globalFarms) { 301 | throw new Error("Failed to get globalFarms information"); 302 | } 303 | 304 | const value = new Decimal(globalFarms[0].emissionsPerSecondNumerator.toString()) 305 | .mul(60 * 60 * 24) 306 | .div(globalFarms[0].emissionsPerSecondDenominator.toString()) 307 | .div(new Decimal(10).pow(rewardTokenDecimals)); 308 | 309 | return OrcaU64.fromDecimal(value, rewardTokenDecimals); 310 | } 311 | } 312 | -------------------------------------------------------------------------------- /src/model/orca/orca-impl.ts: -------------------------------------------------------------------------------- 1 | import { Connection } from "@solana/web3.js"; 2 | import { Orca, OrcaFarm, OrcaPool, OrcaPoolConfig, OrcaFarmConfig, Network } from "../../public"; 3 | import { OrcaFactory } from "../orca-factory"; 4 | 5 | export class OrcaImpl implements Orca { 6 | private connection: Connection; 7 | private network: Network; 8 | private factory: OrcaFactory; 9 | 10 | constructor(connection: Connection, network: Network) { 11 | this.connection = connection; 12 | this.network = network; 13 | this.factory = new OrcaFactory(); 14 | } 15 | 16 | getPool(pool: OrcaPoolConfig): OrcaPool { 17 | return this.factory.getPool(this.connection, this.network, pool); 18 | } 19 | 20 | getFarm(farm: OrcaFarmConfig): OrcaFarm { 21 | return this.factory.getFarm(this.connection, this.network, farm); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/model/orca/pool/orca-pool.ts: -------------------------------------------------------------------------------- 1 | import { u64 } from "@solana/spl-token"; 2 | import { Connection, PublicKey, Keypair } from "@solana/web3.js"; 3 | import Decimal from "decimal.js"; 4 | import { defaultSlippagePercentage } from "../../../constants/orca-defaults"; 5 | 6 | import { 7 | OrcaU64, 8 | deriveAssociatedTokenAddress, 9 | deserializeAccount, 10 | getTokens, 11 | U64Utils, 12 | PoolTokenCount, 13 | getTokenCount, 14 | TransactionBuilder, 15 | OrcaPool, 16 | OrcaToken, 17 | OrcaPoolToken, 18 | Quote, 19 | TransactionPayload, 20 | Percentage, 21 | resolveOrCreateAssociatedTokenAddress, 22 | ZERO, 23 | DepositQuote, 24 | WithdrawQuote, 25 | DecimalUtil, 26 | Network, 27 | ORCA_TOKEN_SWAP_ID_DEVNET, 28 | ORCA_TOKEN_SWAP_ID, 29 | } from "../../../public"; 30 | import { 31 | createApprovalInstruction, 32 | createDepositInstruction, 33 | createSwapInstruction, 34 | createWithdrawInstruction, 35 | } from "../../../public/utils/web3/instructions/pool-instructions"; 36 | import { Owner } from "../../../public/utils/web3/key-utils"; 37 | import { QuotePoolParams, QuoteBuilderFactory } from "../../quote/quote-builder"; 38 | import { OrcaPoolParams } from "./pool-types"; 39 | 40 | export class OrcaPoolImpl implements OrcaPool { 41 | private connection: Connection; 42 | private poolParams: OrcaPoolParams; 43 | private orcaTokenSwapId: PublicKey; 44 | 45 | constructor(connection: Connection, network: Network, config: OrcaPoolParams) { 46 | this.connection = connection; 47 | this.poolParams = config; 48 | 49 | this.orcaTokenSwapId = 50 | network === Network.MAINNET ? ORCA_TOKEN_SWAP_ID : ORCA_TOKEN_SWAP_ID_DEVNET; 51 | } 52 | 53 | public getTokenA(): OrcaPoolToken { 54 | const tokenId = this.poolParams.tokenIds[0]; 55 | return this.poolParams.tokens[tokenId]; 56 | } 57 | 58 | public getTokenB(): OrcaPoolToken { 59 | const tokenId = this.poolParams.tokenIds[1]; 60 | return this.poolParams.tokens[tokenId]; 61 | } 62 | 63 | public getPoolTokenMint(): PublicKey { 64 | return this.poolParams.poolTokenMint; 65 | } 66 | 67 | public async getLPBalance(owner: PublicKey): Promise { 68 | const address = await deriveAssociatedTokenAddress(owner, this.poolParams.poolTokenMint); 69 | 70 | const accountInfo = await this.connection.getAccountInfo(address); 71 | 72 | // User does not have a balance for this account 73 | if (accountInfo == undefined) { 74 | return OrcaU64.fromNumber(0, this.poolParams.poolTokenDecimals); 75 | } 76 | const result = deserializeAccount(accountInfo?.data); 77 | if (result == undefined) { 78 | throw new Error("Failed to parse user account for LP token."); 79 | } 80 | 81 | return OrcaU64.fromU64(result.amount, this.poolParams.poolTokenDecimals); 82 | } 83 | 84 | public async getLPSupply(): Promise { 85 | const context = await this.connection.getTokenSupply(this.poolParams.poolTokenMint); 86 | 87 | const amt = new u64(context.value.amount); 88 | 89 | return OrcaU64.fromU64(amt, this.poolParams.poolTokenDecimals); 90 | } 91 | 92 | public async getQuote( 93 | inputToken: OrcaToken, 94 | inputAmount: Decimal | OrcaU64, 95 | slippage?: Decimal 96 | ): Promise { 97 | const { inputPoolToken, outputPoolToken } = getTokens( 98 | this.poolParams, 99 | inputToken.mint.toString() 100 | ); 101 | 102 | const { inputTokenCount, outputTokenCount } = await getTokenCount( 103 | this.connection, 104 | this.poolParams, 105 | inputPoolToken, 106 | outputPoolToken 107 | ); 108 | 109 | return this.getQuoteWithPoolAmounts( 110 | inputToken, 111 | inputAmount, 112 | inputTokenCount, 113 | outputTokenCount, 114 | slippage 115 | ); 116 | } 117 | 118 | public async getQuoteWithPoolAmounts( 119 | inputToken: OrcaToken, 120 | inputAmount: Decimal | OrcaU64, 121 | inputTokenPoolAmount: u64, 122 | outputTokenPoolAmount: u64, 123 | slippage?: Decimal 124 | ): Promise { 125 | const slippageTolerance = 126 | slippage === undefined ? defaultSlippagePercentage : Percentage.fromDecimal(slippage); 127 | 128 | const feeStructure = this.poolParams.feeStructure; 129 | 130 | const { inputPoolToken, outputPoolToken } = getTokens( 131 | this.poolParams, 132 | inputToken.mint.toString() 133 | ); 134 | const inputAmountU64 = U64Utils.toTokenU64(inputAmount, inputPoolToken, "inputAmount"); 135 | 136 | const { 137 | value: { feeCalculator }, 138 | } = await this.connection.getRecentBlockhashAndContext("singleGossip"); 139 | 140 | const quoteParams: QuotePoolParams = { 141 | inputToken: inputPoolToken, 142 | outputToken: outputPoolToken, 143 | inputTokenCount: inputTokenPoolAmount, 144 | outputTokenCount: outputTokenPoolAmount, 145 | feeStructure: feeStructure, 146 | slippageTolerance: slippageTolerance, 147 | lamportsPerSignature: feeCalculator.lamportsPerSignature, 148 | amp: this.poolParams.amp !== undefined ? new u64(this.poolParams.amp) : undefined, 149 | }; 150 | 151 | const quoteBuilder = QuoteBuilderFactory.getBuilder(this.poolParams.curveType); 152 | 153 | const quote = quoteBuilder?.buildQuote(quoteParams, inputAmountU64); 154 | 155 | if (quote == undefined) { 156 | throw new Error("Failed to get quote!"); 157 | } 158 | 159 | return quote; 160 | } 161 | 162 | public async swap( 163 | owner: Keypair | PublicKey, 164 | inputToken: OrcaToken, 165 | amountIn: Decimal | OrcaU64, 166 | minimumAmountOut: Decimal | OrcaU64 167 | ): Promise { 168 | const _owner = new Owner(owner); 169 | 170 | const ownerAddress = _owner.publicKey; 171 | 172 | const { inputPoolToken, outputPoolToken } = getTokens( 173 | this.poolParams, 174 | inputToken.mint.toString() 175 | ); 176 | const amountInU64 = U64Utils.toTokenU64(amountIn, inputPoolToken, "amountIn"); 177 | const minimumAmountOutU64 = U64Utils.toTokenU64( 178 | minimumAmountOut, 179 | outputPoolToken, 180 | "minimumAmountOut" 181 | ); 182 | 183 | const { address: inputPoolTokenUserAddress, ...resolveInputAddrInstructions } = 184 | await resolveOrCreateAssociatedTokenAddress( 185 | this.connection, 186 | _owner, 187 | inputPoolToken.mint, 188 | amountInU64 189 | ); 190 | 191 | const { address: outputPoolTokenUserAddress, ...resolveOutputAddrInstructions } = 192 | await resolveOrCreateAssociatedTokenAddress(this.connection, _owner, outputPoolToken.mint); 193 | 194 | if (inputPoolTokenUserAddress === undefined || outputPoolTokenUserAddress === undefined) { 195 | throw new Error("Unable to derive input / output token associated address."); 196 | } 197 | 198 | const { userTransferAuthority, ...approvalInstruction } = createApprovalInstruction( 199 | ownerAddress, 200 | amountInU64, 201 | inputPoolTokenUserAddress 202 | ); 203 | 204 | const swapInstruction = await createSwapInstruction( 205 | this.poolParams, 206 | _owner, 207 | inputPoolToken, 208 | inputPoolTokenUserAddress, 209 | outputPoolToken, 210 | outputPoolTokenUserAddress, 211 | amountInU64, 212 | minimumAmountOutU64, 213 | userTransferAuthority.publicKey, 214 | this.orcaTokenSwapId 215 | ); 216 | 217 | return await new TransactionBuilder(this.connection, ownerAddress, _owner) 218 | .addInstruction(resolveInputAddrInstructions) 219 | .addInstruction(resolveOutputAddrInstructions) 220 | .addInstruction(approvalInstruction) 221 | .addInstruction(swapInstruction) 222 | .build(); 223 | } 224 | 225 | public async getDepositQuote( 226 | maxTokenAIn: Decimal | OrcaU64, 227 | maxTokenBIn: Decimal | OrcaU64, 228 | slippage?: Decimal 229 | ): Promise { 230 | const slippageTolerance = 231 | slippage === undefined ? defaultSlippagePercentage : Percentage.fromDecimal(slippage); 232 | 233 | const maxTokenAIn_U64 = U64Utils.toTokenU64(maxTokenAIn, this.getTokenA(), "maxTokenAIn"); 234 | const maxTokenBIn_U64 = U64Utils.toTokenU64(maxTokenBIn, this.getTokenB(), "maxTokenBIn"); 235 | 236 | const { inputTokenCount: tokenAAmount, outputTokenCount: tokenBAmount } = await getTokenCount( 237 | this.connection, 238 | this.poolParams, 239 | this.getTokenA(), 240 | this.getTokenB() 241 | ); 242 | const lpSupply = await this.getLPSupply(); 243 | 244 | if (tokenAAmount.eq(ZERO) || tokenBAmount.eq(ZERO)) { 245 | return { 246 | minPoolTokenAmountOut: OrcaU64.fromU64(ZERO, lpSupply.scale), 247 | maxTokenAIn: OrcaU64.fromU64(maxTokenAIn_U64, this.getTokenA().scale), 248 | maxTokenBIn: OrcaU64.fromU64(maxTokenBIn_U64, this.getTokenB().scale), 249 | }; 250 | } 251 | 252 | const poolTokenAmountWithA = maxTokenAIn_U64 253 | .mul(slippageTolerance.denominator) 254 | .mul(lpSupply.toU64()) 255 | .div(tokenAAmount) 256 | .div(slippageTolerance.numerator.add(slippageTolerance.denominator)); 257 | 258 | const poolTokenAmountWithB = maxTokenBIn_U64 259 | .mul(slippageTolerance.denominator) 260 | .mul(lpSupply.toU64()) 261 | .div(tokenBAmount) 262 | .div(slippageTolerance.numerator.add(slippageTolerance.denominator)); 263 | 264 | // Pick the smaller value of the two to calculate the minimum poolTokenAmount out 265 | const minPoolTokenAmountOut_U64 = poolTokenAmountWithA.gt(poolTokenAmountWithB) 266 | ? poolTokenAmountWithB 267 | : poolTokenAmountWithA; 268 | 269 | return { 270 | minPoolTokenAmountOut: OrcaU64.fromU64(minPoolTokenAmountOut_U64, lpSupply.scale), 271 | maxTokenAIn: OrcaU64.fromU64(maxTokenAIn_U64, this.getTokenA().scale), 272 | maxTokenBIn: OrcaU64.fromU64(maxTokenBIn_U64, this.getTokenB().scale), 273 | }; 274 | } 275 | 276 | public async deposit( 277 | owner: Keypair | PublicKey, 278 | maxTokenAIn: Decimal | OrcaU64, 279 | maxTokenBIn: Decimal | OrcaU64, 280 | minPoolTokenAmountOut: Decimal | OrcaU64 281 | ): Promise { 282 | const _owner = new Owner(owner); 283 | const ownerAddress = _owner.publicKey; 284 | 285 | const tokenA = this.getTokenA(); 286 | const tokenB = this.getTokenB(); 287 | 288 | const maxTokenAIn_U64 = U64Utils.toTokenU64(maxTokenAIn, tokenA, "maxTokenAIn"); 289 | const maxTokenBIn_U64 = U64Utils.toTokenU64(maxTokenBIn, tokenB, "maxTokenBIn"); 290 | const minPoolTokenAmountOut_U64 = U64Utils.toPoolU64( 291 | minPoolTokenAmountOut, 292 | this.poolParams, 293 | "poolTokenAmount" 294 | ); 295 | 296 | // If tokenA is SOL, this will create a new wSOL account with maxTokenAIn_U64 297 | // Otherwise, get tokenA's associated token account 298 | const { address: userTokenAPublicKey, ...resolveTokenAInstrucitons } = 299 | await resolveOrCreateAssociatedTokenAddress( 300 | this.connection, 301 | _owner, 302 | tokenA.mint, 303 | maxTokenAIn_U64 304 | ); 305 | 306 | // If tokenB is SOL, this will create a new wSOL account with maxTokenBIn_U64 307 | // Otherwise, get tokenB's associated token account 308 | const { address: userTokenBPublicKey, ...resolveTokenBInstrucitons } = 309 | await resolveOrCreateAssociatedTokenAddress( 310 | this.connection, 311 | _owner, 312 | tokenB.mint, 313 | maxTokenBIn_U64 314 | ); 315 | 316 | // If the user lacks the pool token account, create it 317 | const { address: userPoolTokenPublicKey, ...resolvePoolTokenInstructions } = 318 | await resolveOrCreateAssociatedTokenAddress( 319 | this.connection, 320 | _owner, 321 | this.poolParams.poolTokenMint 322 | ); 323 | 324 | // Approve transfer of the tokens being deposited 325 | const { userTransferAuthority, ...transferTokenAInstruction } = createApprovalInstruction( 326 | ownerAddress, 327 | maxTokenAIn_U64, 328 | userTokenAPublicKey 329 | ); 330 | const { ...transferTokenBInstruction } = createApprovalInstruction( 331 | ownerAddress, 332 | maxTokenBIn_U64, 333 | userTokenBPublicKey, 334 | userTransferAuthority 335 | ); 336 | 337 | // Create the deposit instruction 338 | const depositInstruction = await createDepositInstruction( 339 | this.poolParams, 340 | userTransferAuthority.publicKey, 341 | userTokenAPublicKey, 342 | userTokenBPublicKey, 343 | userPoolTokenPublicKey, 344 | minPoolTokenAmountOut_U64, 345 | maxTokenAIn_U64, 346 | maxTokenBIn_U64, 347 | tokenA.addr, 348 | tokenB.addr, 349 | this.orcaTokenSwapId, 350 | _owner 351 | ); 352 | 353 | return await new TransactionBuilder(this.connection, ownerAddress, _owner) 354 | .addInstruction(resolveTokenAInstrucitons) 355 | .addInstruction(resolveTokenBInstrucitons) 356 | .addInstruction(resolvePoolTokenInstructions) 357 | .addInstruction(transferTokenAInstruction) 358 | .addInstruction(transferTokenBInstruction) 359 | .addInstruction(depositInstruction) 360 | .build(); 361 | } 362 | 363 | public async getWithdrawQuote( 364 | withdrawTokenAmount: Decimal | OrcaU64, 365 | withdrawTokenMint: PublicKey, 366 | slippage?: Decimal 367 | ): Promise { 368 | const slippageTolerance = 369 | slippage === undefined ? defaultSlippagePercentage : Percentage.fromDecimal(slippage); 370 | 371 | const lpSupply = await this.getLPSupply(); 372 | const { inputTokenCount: tokenAAmount, outputTokenCount: tokenBAmount } = await getTokenCount( 373 | this.connection, 374 | this.poolParams, 375 | this.getTokenA(), 376 | this.getTokenB() 377 | ); 378 | 379 | // withdrawTokenAmount needs represent amounts for one of the following: poolTokenAmount, tokenAAmount, or tokenBAmount 380 | // determine which token this amount represents, then calculate poolTokenIn_U64 381 | let poolTokenIn_U64 = ZERO; 382 | if (withdrawTokenMint.equals(this.getPoolTokenMint())) { 383 | poolTokenIn_U64 = U64Utils.toPoolU64( 384 | withdrawTokenAmount, 385 | this.poolParams, 386 | "withdrawTokenAmount" 387 | ); 388 | } else if ( 389 | withdrawTokenMint.equals(this.getTokenA().mint) || 390 | withdrawTokenMint.equals(this.getTokenB().mint) 391 | ) { 392 | const token = withdrawTokenMint.equals(this.getTokenA().mint) 393 | ? this.getTokenA() 394 | : this.getTokenB(); 395 | const totalAmount = token.mint.equals(this.getTokenA().mint) ? tokenAAmount : tokenBAmount; 396 | 397 | const numerator = 398 | withdrawTokenAmount instanceof OrcaU64 399 | ? withdrawTokenAmount.toDecimal() 400 | : withdrawTokenAmount; 401 | const denominator = DecimalUtil.fromU64(totalAmount, token.scale); 402 | const poolTokenIn = lpSupply.toDecimal().div(denominator).mul(numerator); 403 | poolTokenIn_U64 = U64Utils.toPoolU64(poolTokenIn, this.poolParams, "poolTokenIn"); 404 | } else { 405 | throw new Error( 406 | `Unable to get withdraw quote with an invalid withdrawTokenMint ${withdrawTokenMint}` 407 | ); 408 | } 409 | 410 | if (poolTokenIn_U64.eq(ZERO)) { 411 | return { 412 | maxPoolTokenAmountIn: OrcaU64.fromU64(ZERO, lpSupply.scale), 413 | minTokenAOut: OrcaU64.fromU64(ZERO, this.getTokenA().scale), 414 | minTokenBOut: OrcaU64.fromU64(ZERO, this.getTokenB().scale), 415 | }; 416 | } 417 | 418 | const minTokenAOut = new OrcaU64( 419 | poolTokenIn_U64 420 | .mul(slippageTolerance.denominator) 421 | .mul(tokenAAmount) 422 | .div(lpSupply.toU64()) 423 | .div(slippageTolerance.numerator.add(slippageTolerance.denominator)), 424 | this.getTokenA().scale 425 | ); 426 | 427 | const minTokenBOut = new OrcaU64( 428 | poolTokenIn_U64 429 | .mul(slippageTolerance.denominator) 430 | .mul(tokenBAmount) 431 | .div(lpSupply.toU64()) 432 | .div(slippageTolerance.numerator.add(slippageTolerance.denominator)), 433 | this.getTokenB().scale 434 | ); 435 | 436 | return { 437 | maxPoolTokenAmountIn: OrcaU64.fromU64(poolTokenIn_U64, lpSupply.scale), 438 | minTokenAOut, 439 | minTokenBOut, 440 | }; 441 | } 442 | 443 | public async withdraw( 444 | owner: Keypair | PublicKey, 445 | poolTokenAmountIn: Decimal | OrcaU64, 446 | minTokenAOut: Decimal | OrcaU64, 447 | minTokenBOut: Decimal | OrcaU64 448 | ): Promise { 449 | const _owner = new Owner(owner); 450 | const ownerAddress = _owner.publicKey; 451 | 452 | const tokenA = this.getTokenA(); 453 | const tokenB = this.getTokenB(); 454 | 455 | const minTokenAOut_U64 = U64Utils.toTokenU64(minTokenAOut, tokenA, "minTokenAOut"); 456 | const minTokenBOut_U64 = U64Utils.toTokenU64(minTokenBOut, tokenB, "minTokenBOut"); 457 | const poolTokenAmountIn_U64 = U64Utils.toPoolU64( 458 | poolTokenAmountIn, 459 | this.poolParams, 460 | "poolTokenAmountIn" 461 | ); 462 | 463 | // Create a token account for tokenA, if necessary 464 | const { address: userTokenAPublicKey, ...resolveTokenAInstrucitons } = 465 | await resolveOrCreateAssociatedTokenAddress(this.connection, _owner, tokenA.mint); 466 | 467 | // Create a token account for tokenB, if necessary 468 | const { address: userTokenBPublicKey, ...resolveTokenBInstrucitons } = 469 | await resolveOrCreateAssociatedTokenAddress(this.connection, _owner, tokenB.mint); 470 | 471 | // Get user's poolToken token account 472 | const { address: userPoolTokenPublicKey, ...resolvePoolTokenInstructions } = 473 | await resolveOrCreateAssociatedTokenAddress( 474 | this.connection, 475 | _owner, 476 | this.poolParams.poolTokenMint 477 | ); 478 | 479 | // Approve transfer of pool token 480 | const { userTransferAuthority, ...transferPoolTokenInstruction } = createApprovalInstruction( 481 | ownerAddress, 482 | poolTokenAmountIn_U64, 483 | userPoolTokenPublicKey 484 | ); 485 | 486 | // Create the withdraw instruction 487 | const withdrawInstruction = await createWithdrawInstruction( 488 | this.poolParams, 489 | userTransferAuthority.publicKey, 490 | userTokenAPublicKey, 491 | userTokenBPublicKey, 492 | userPoolTokenPublicKey, 493 | poolTokenAmountIn_U64, 494 | minTokenAOut_U64, 495 | minTokenBOut_U64, 496 | tokenA.addr, 497 | tokenB.addr, 498 | this.orcaTokenSwapId, 499 | _owner 500 | ); 501 | 502 | return await new TransactionBuilder(this.connection, ownerAddress, _owner) 503 | .addInstruction(resolveTokenAInstrucitons) 504 | .addInstruction(resolveTokenBInstrucitons) 505 | .addInstruction(resolvePoolTokenInstructions) 506 | .addInstruction(transferPoolTokenInstruction) 507 | .addInstruction(withdrawInstruction) 508 | .build(); 509 | } 510 | } 511 | -------------------------------------------------------------------------------- /src/model/orca/pool/pool-types.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey } from "@solana/web3.js"; 2 | import { OrcaPoolToken } from "../../.."; 3 | import { Percentage } from "../../../public"; 4 | 5 | /** 6 | * An Orca token-swap pool 7 | * @param address The pool account address 8 | * @param nonce The nonce used to generate the pool authority 9 | * @param authority The pool authority PDA address to sign instructions 10 | * @param poolTokenMint Mint address for the pool token 11 | * @param poolTokenDecimals Number of decimal places for the pool token 12 | * @param feeAccount Public address of the pool token fee account 13 | * @param tokenIds The ids of the tokens in this pool 14 | * @param tokens The id, token object of the tokens in this pool 15 | * @param curveType Trading curve type. 0 - ConstantProduct, 1 - ConstantPrice, 2 - Stable, 3 - Offset 16 | * @param feeStructure The % of fees collected by this pool 17 | * @param amp The amplification coefficient for a stable curve pool (defines how flat the AMM curve is when prices are similar) 18 | */ 19 | export type OrcaPoolParams = { 20 | address: PublicKey; 21 | nonce: number; 22 | authority: PublicKey; 23 | poolTokenMint: PublicKey; 24 | poolTokenDecimals: number; 25 | feeAccount: PublicKey; 26 | tokenIds: string[]; 27 | tokens: Record; 28 | curveType: CurveType; 29 | feeStructure: FeeStructure; 30 | amp?: number; 31 | }; 32 | 33 | export enum CurveType { 34 | ConstantProduct, 35 | ConstantPrice, 36 | Stable, 37 | Offset, 38 | } 39 | 40 | /** 41 | * @param traderFee Percentage of the fee that goes to the liquidity providers 42 | * @param ownerFee Percentage of the fee that goes to orca 43 | */ 44 | export type FeeStructure = { 45 | traderFee: Percentage; 46 | ownerFee: Percentage; 47 | }; 48 | -------------------------------------------------------------------------------- /src/model/quote/constant-product-quote.ts: -------------------------------------------------------------------------------- 1 | import { u64 } from "@solana/spl-token"; 2 | import Decimal from "decimal.js"; 3 | import { solToken } from "../../constants/tokens"; 4 | import { ZERO, ONE, DecimalUtil, U64Utils, OrcaU64, Quote } from "../../public"; 5 | import { QuotePoolParams } from "./quote-builder"; 6 | 7 | /** 8 | * ConstantProductPools 9 | * 10 | * Product price curve: 11 | * x = inputTokenCount 12 | * y = outputTokenCount 13 | * k = x * y 14 | */ 15 | 16 | function calculateFee(inputTradeAmount: u64, feeNumerator: u64, feeDenominator: u64): u64 { 17 | if (feeNumerator.eq(ZERO) || inputTradeAmount.eq(ZERO)) { 18 | return ZERO; 19 | } 20 | 21 | const fee = inputTradeAmount.mul(feeNumerator).div(feeDenominator); 22 | // minimum fee of one token 23 | return fee.eq(ZERO) ? ONE : fee; 24 | } 25 | 26 | function getInputAmountLessFees(inputTradeAmount: u64, params: QuotePoolParams): u64 { 27 | const fees = getLPFees(inputTradeAmount, params); 28 | return fees.gt(inputTradeAmount) ? new u64(0) : inputTradeAmount.sub(fees); 29 | } 30 | 31 | function getRate(inputTradeAmountU64: u64, params: QuotePoolParams): Decimal { 32 | if (inputTradeAmountU64.eq(ZERO)) { 33 | return new Decimal(0); 34 | } 35 | 36 | const expectedOutputAmountU64 = getExpectedOutputAmount(inputTradeAmountU64, params); 37 | const inputTradeAmount = DecimalUtil.fromU64(inputTradeAmountU64, params.inputToken.scale); 38 | const outputTradeAmount = DecimalUtil.fromU64(expectedOutputAmountU64, params.outputToken.scale); 39 | return outputTradeAmount.div(inputTradeAmount).toDecimalPlaces(params.outputToken.scale); 40 | } 41 | 42 | function getPriceImpact(inputTradeAmount: u64, params: QuotePoolParams): Decimal { 43 | if (inputTradeAmount.eq(ZERO) || params.outputTokenCount.eq(ZERO)) { 44 | return new Decimal(0); 45 | } 46 | 47 | const noSlippageOutputCountU64 = getExpectedOutputAmountWithNoSlippage(inputTradeAmount, params); 48 | const outputCountU64 = getExpectedOutputAmount(inputTradeAmount, params); 49 | if (noSlippageOutputCountU64.isZero()) { 50 | // The minimum fee of one token makes inputTradeLessFees zero when the input is minimal, 51 | // and the output is also zero. 52 | return new Decimal(0); 53 | } 54 | 55 | const noSlippageOutputCount = DecimalUtil.fromU64( 56 | noSlippageOutputCountU64, 57 | params.outputToken.scale 58 | ); 59 | const outputCount = DecimalUtil.fromU64(outputCountU64, params.outputToken.scale); 60 | 61 | const impact = noSlippageOutputCount.sub(outputCount).div(noSlippageOutputCount); 62 | return impact.mul(100).toDecimalPlaces(params.outputToken.scale); 63 | } 64 | 65 | function getLPFees(inputTradeAmount: u64, params: QuotePoolParams): u64 { 66 | const { feeStructure } = params; 67 | const tradingFee = calculateFee( 68 | inputTradeAmount, 69 | feeStructure.traderFee.numerator, 70 | feeStructure.traderFee.denominator 71 | ); 72 | 73 | const ownerFee = calculateFee( 74 | inputTradeAmount, 75 | feeStructure.ownerFee.numerator, 76 | feeStructure.ownerFee.denominator 77 | ); 78 | 79 | return new u64(tradingFee.add(ownerFee).toString()); 80 | } 81 | 82 | function getExpectedOutputAmount(inputTradeAmount: u64, params: QuotePoolParams): u64 { 83 | const inputTradeLessFees = getInputAmountLessFees(inputTradeAmount, params); 84 | return getOutputAmount(inputTradeLessFees, params); 85 | } 86 | 87 | function getExpectedOutputAmountWithNoSlippage( 88 | inputTradeAmount: u64, 89 | params: QuotePoolParams 90 | ): u64 { 91 | if (params.inputTokenCount.eq(ZERO)) { 92 | return params.outputTokenCount; 93 | } 94 | 95 | const inputTradeLessFees = getInputAmountLessFees(inputTradeAmount, params); 96 | return inputTradeLessFees.mul(params.outputTokenCount).div(params.inputTokenCount); 97 | } 98 | 99 | function getMinimumAmountOut(inputTradeAmount: u64, params: QuotePoolParams): u64 { 100 | const slippageTolerance = params.slippageTolerance; 101 | const expectedOutputAmountFees = getExpectedOutputAmount(inputTradeAmount, params); 102 | const result = expectedOutputAmountFees 103 | .mul(slippageTolerance.denominator.sub(slippageTolerance.numerator)) 104 | .div(slippageTolerance.denominator); 105 | return result; 106 | } 107 | 108 | // Note: This function matches the calculation done on SERUM and on Web UI. 109 | // Given k = currInputTokenCount * currOutputTokenCount and k = newInputTokenCount * newOutputTokenCount, 110 | // solve for newOutputTokenCount 111 | function getOutputAmount(inputTradeAmount: u64, params: QuotePoolParams): u64 { 112 | const [poolInputAmount, poolOutputAmount] = [params.inputTokenCount, params.outputTokenCount]; 113 | 114 | const invariant = poolInputAmount.mul(poolOutputAmount); 115 | 116 | const [newPoolOutputAmount] = U64Utils.ceilingDivision( 117 | invariant, 118 | poolInputAmount.add(inputTradeAmount) 119 | ); 120 | 121 | const outputAmount = poolOutputAmount.sub(newPoolOutputAmount); 122 | 123 | return new u64(outputAmount.toString()); 124 | } 125 | 126 | function getNetworkFees(params: QuotePoolParams) { 127 | let numSigs; 128 | if (params.inputToken === solToken || params.outputToken === solToken) { 129 | numSigs = 3; 130 | } else { 131 | numSigs = 2; 132 | } 133 | 134 | return params.lamportsPerSignature * numSigs; 135 | } 136 | 137 | export class ConstantProductPoolQuoteBuilder { 138 | buildQuote(params: QuotePoolParams, inputTradeAmount: u64): Quote { 139 | return { 140 | getRate: () => getRate(inputTradeAmount, params), 141 | getPriceImpact: () => getPriceImpact(inputTradeAmount, params), 142 | getLPFees: () => 143 | OrcaU64.fromU64(getLPFees(inputTradeAmount, params), params.inputToken.scale), 144 | getNetworkFees: () => OrcaU64.fromNumber(getNetworkFees(params)), 145 | getExpectedOutputAmount: () => 146 | OrcaU64.fromU64( 147 | getExpectedOutputAmount(inputTradeAmount, params), 148 | params.outputToken.scale 149 | ), 150 | getMinOutputAmount: () => 151 | OrcaU64.fromU64(getMinimumAmountOut(inputTradeAmount, params), params.outputToken.scale), 152 | }; 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /src/model/quote/quote-builder.ts: -------------------------------------------------------------------------------- 1 | import { u64 } from "@solana/spl-token"; 2 | import { OrcaToken, Quote } from "../.."; 3 | import { PoolTokenCount, Percentage } from "../../public"; 4 | import { FeeStructure, CurveType } from "../orca/pool/pool-types"; 5 | import { ConstantProductPoolQuoteBuilder } from "./constant-product-quote"; 6 | import { StablePoolQuoteBuilder } from "./stable-quote"; 7 | 8 | export type QuotePoolParams = PoolTokenCount & { 9 | inputToken: OrcaToken; 10 | outputToken: OrcaToken; 11 | inputTokenCount: u64; 12 | outputTokenCount: u64; 13 | feeStructure: FeeStructure; 14 | slippageTolerance: Percentage; 15 | lamportsPerSignature: number; 16 | amp?: u64; 17 | }; 18 | 19 | export interface QuoteBuilder { 20 | buildQuote(pool: QuotePoolParams, inputAmount: u64): Quote; 21 | } 22 | 23 | export class QuoteBuilderFactory { 24 | static getBuilder(curveType: CurveType): QuoteBuilder | undefined { 25 | switch (curveType) { 26 | case CurveType.ConstantProduct: 27 | return new ConstantProductPoolQuoteBuilder(); 28 | case CurveType.Stable: 29 | return new StablePoolQuoteBuilder(); 30 | default: 31 | return undefined; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/model/quote/stable-quote.ts: -------------------------------------------------------------------------------- 1 | import { u64 } from "@solana/spl-token"; 2 | import Decimal from "decimal.js"; 3 | import { computeBaseOutputAmount, computeOutputAmount } from "@orca-so/stablecurve"; 4 | import { QuotePoolParams } from "./quote-builder"; 5 | import { DecimalUtil, OrcaU64, Quote, ZERO, ONE } from "../../public"; 6 | import { solToken } from "../../constants/tokens"; 7 | 8 | function calculateFee(inputTradeAmount: u64, feeNumerator: u64, feeDenominator: u64): u64 { 9 | if (feeNumerator.eq(ZERO) || inputTradeAmount.eq(ZERO)) { 10 | return ZERO; 11 | } 12 | 13 | const fee = inputTradeAmount.mul(feeNumerator).div(feeDenominator); 14 | // minimum fee of one token 15 | return fee.eq(ZERO) ? ONE : fee; 16 | } 17 | 18 | function getInputAmountLessFees(inputTradeAmount: u64, params: QuotePoolParams): u64 { 19 | const fees = getLPFees(inputTradeAmount, params); 20 | return fees.gt(inputTradeAmount) ? new u64(0) : inputTradeAmount.sub(fees); 21 | } 22 | 23 | function getOutputAmountWithNoSlippage( 24 | inputTradeAmountLessFees: u64, 25 | params: QuotePoolParams 26 | ): u64 { 27 | const [poolInputAmount, poolOutputAmount, amp] = [ 28 | params.inputTokenCount, 29 | params.outputTokenCount, 30 | params.amp!, 31 | ]; 32 | 33 | return computeBaseOutputAmount(inputTradeAmountLessFees, poolInputAmount, poolOutputAmount, amp); 34 | } 35 | 36 | function getOutputAmount(inputTradeAmountLessFees: u64, params: QuotePoolParams): u64 { 37 | const [poolInputAmount, poolOutputAmount, amp] = [ 38 | params.inputTokenCount, 39 | params.outputTokenCount, 40 | params.amp!, 41 | ]; 42 | 43 | return computeOutputAmount(inputTradeAmountLessFees, poolInputAmount, poolOutputAmount, amp); 44 | } 45 | 46 | function getExpectedOutputAmountWithNoSlippage( 47 | inputTradeAmount: u64, 48 | params: QuotePoolParams 49 | ): u64 { 50 | const inputTradeAmountLessFees = getInputAmountLessFees(inputTradeAmount, params); 51 | 52 | return getOutputAmountWithNoSlippage(inputTradeAmountLessFees, params); 53 | } 54 | 55 | function getExpectedOutputAmount(inputTradeAmount: u64, params: QuotePoolParams): u64 { 56 | const inputTradeAmountLessFees = getInputAmountLessFees(inputTradeAmount, params); 57 | 58 | return getOutputAmount(inputTradeAmountLessFees, params); 59 | } 60 | 61 | function getRate(inputTradeAmountU64: u64, params: QuotePoolParams): Decimal { 62 | if (inputTradeAmountU64.eq(ZERO)) { 63 | return new Decimal(0); 64 | } 65 | 66 | const expectedOutputAmountU64 = getExpectedOutputAmount(inputTradeAmountU64, params); 67 | const inputTradeAmount = DecimalUtil.fromU64(inputTradeAmountU64, params.inputToken.scale); 68 | const outputTradeAmount = DecimalUtil.fromU64(expectedOutputAmountU64, params.outputToken.scale); 69 | return outputTradeAmount.div(inputTradeAmount).toDecimalPlaces(params.outputToken.scale); 70 | } 71 | 72 | function getPriceImpact(inputTradeAmount: u64, params: QuotePoolParams): Decimal { 73 | if ( 74 | inputTradeAmount.eq(ZERO) || 75 | params.inputTokenCount.eq(ZERO) || 76 | params.outputTokenCount.eq(ZERO) 77 | ) { 78 | return new Decimal(0); 79 | } 80 | 81 | const noSlippageOutputCountU64 = getExpectedOutputAmountWithNoSlippage(inputTradeAmount, params); 82 | const outputCountU64 = getExpectedOutputAmount(inputTradeAmount, params); 83 | if (noSlippageOutputCountU64.isZero()) { 84 | // The minimum fee of one token makes inputTradeLessFees zero when the input is minimal, 85 | // and the output is also zero. 86 | return new Decimal(0); 87 | } 88 | 89 | const noSlippageOutputCount = DecimalUtil.fromU64( 90 | noSlippageOutputCountU64, 91 | params.outputToken.scale 92 | ); 93 | const outputCount = DecimalUtil.fromU64(outputCountU64, params.outputToken.scale); 94 | 95 | const impact = noSlippageOutputCount.sub(outputCount).div(noSlippageOutputCount); 96 | return impact.mul(100).toDecimalPlaces(params.outputToken.scale); 97 | } 98 | 99 | function getLPFees(inputTradeAmount: u64, params: QuotePoolParams): u64 { 100 | const { feeStructure } = params; 101 | const tradingFee = calculateFee( 102 | inputTradeAmount, 103 | feeStructure.traderFee.numerator, 104 | feeStructure.traderFee.denominator 105 | ); 106 | 107 | const ownerFee = calculateFee( 108 | inputTradeAmount, 109 | feeStructure.ownerFee.numerator, 110 | feeStructure.ownerFee.denominator 111 | ); 112 | 113 | return new u64(tradingFee.add(ownerFee).toString()); 114 | } 115 | 116 | function getMinimumAmountOut(inputTradeAmount: u64, params: QuotePoolParams): u64 { 117 | const slippageTolerance = params.slippageTolerance; 118 | const expectedOutputAmount = getExpectedOutputAmount(inputTradeAmount, params); 119 | 120 | return expectedOutputAmount 121 | .mul(slippageTolerance.denominator.sub(slippageTolerance.numerator)) 122 | .div(slippageTolerance.denominator); 123 | } 124 | 125 | function getNetworkFees(params: QuotePoolParams): number { 126 | let numSigs; 127 | 128 | if (params.inputToken === solToken || params.outputToken === solToken) { 129 | numSigs = 3; 130 | } else { 131 | numSigs = 2; 132 | } 133 | 134 | return params.lamportsPerSignature * numSigs; 135 | } 136 | 137 | export class StablePoolQuoteBuilder { 138 | buildQuote(params: QuotePoolParams, inputTradeAmount: u64): Quote { 139 | if (!params.amp) { 140 | throw new Error("amp param required for stable pool"); 141 | } 142 | 143 | return { 144 | getRate: () => getRate(inputTradeAmount, params), 145 | getPriceImpact: () => getPriceImpact(inputTradeAmount, params), 146 | getLPFees: () => 147 | OrcaU64.fromU64(getLPFees(inputTradeAmount, params), params.inputToken.scale), 148 | getNetworkFees: () => OrcaU64.fromNumber(getNetworkFees(params)), 149 | getExpectedOutputAmount: () => 150 | OrcaU64.fromU64( 151 | getExpectedOutputAmount(inputTradeAmount, params), 152 | params.outputToken.scale 153 | ), 154 | getMinOutputAmount: () => 155 | OrcaU64.fromU64(getMinimumAmountOut(inputTradeAmount, params), params.outputToken.scale), 156 | }; 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /src/public/devnet/farms/config.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * The following content is auto-generated. 3 | */ 4 | 5 | /** 6 | * A list of supported Orca farms in this SDK. 7 | */ 8 | export enum OrcaFarmConfig { 9 | SOL_USDC_AQ = "4GpUivZ2jvZqQ3vJRsoq5PwnYv6gdV9fJ9BzHT2JcRr7", 10 | SOL_USDT_AQ = "2E4Mp6y2gFRteXiANnwzAJEhHwD3NX1wru3XvxJpGBq2", 11 | USDC_USDT_AQ = "EBor1PR5XNGHjRVB6JDJuKVCQbvdr1CVZTaX1hTAdvQv", 12 | ETH_SOL_AQ = "8sFnpd7mM1AWxP1LXX2FWbbkaVtAopBPmPNZ9y6172WL", 13 | ETH_USDC_AQ = "9pRnvg7ihSJDLi6DGf3PLwr6xRRRrBPXsHYEgGL5hzgA", 14 | ORCA_SOL_AQ = "CmDdQhusZWyi9fue27VSktYgkHefm3JXNdzc9kCpyvYi", 15 | ORCA_USDC_AQ = "2ZEEntzoUN7XuMs88ukLGv5HRR1byL7wFWChryF5ZHri", 16 | SOL_USDC_DD = "AtJF9fbQ1pbz76NYo2jtKjHuzzyaFToHLCizYk6UoHHL", 17 | ETH_SOL_DD = "5NH9rNaoLKbPPP5zwCJTaMPkFACtfJA8wEmqWrXzgCMa", 18 | ETH_USDC_DD = "EeqPcczEZH2cjYBnQyGXBQx1DGs7KG1pobwdPKcwALhD", 19 | } 20 | -------------------------------------------------------------------------------- /src/public/devnet/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./utils"; 2 | -------------------------------------------------------------------------------- /src/public/devnet/pools/config.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * The following content is auto-generated. 3 | */ 4 | 5 | /** 6 | * A list of supported Orca pools in this SDK. 7 | */ 8 | export enum OrcaPoolConfig { 9 | SOL_USDC = "4GpUivZ2jvZqQ3vJRsoq5PwnYv6gdV9fJ9BzHT2JcRr7", 10 | SOL_USDT = "2E4Mp6y2gFRteXiANnwzAJEhHwD3NX1wru3XvxJpGBq2", 11 | USDC_USDT = "EBor1PR5XNGHjRVB6JDJuKVCQbvdr1CVZTaX1hTAdvQv", 12 | ETH_SOL = "8sFnpd7mM1AWxP1LXX2FWbbkaVtAopBPmPNZ9y6172WL", 13 | ETH_USDC = "9pRnvg7ihSJDLi6DGf3PLwr6xRRRrBPXsHYEgGL5hzgA", 14 | ORCA_SOL = "CmDdQhusZWyi9fue27VSktYgkHefm3JXNdzc9kCpyvYi", 15 | ORCA_USDC = "2ZEEntzoUN7XuMs88ukLGv5HRR1byL7wFWChryF5ZHri", 16 | } 17 | -------------------------------------------------------------------------------- /src/public/devnet/utils.ts: -------------------------------------------------------------------------------- 1 | import { OrcaPoolConfig, OrcaFarmConfig } from ".."; 2 | import { OrcaFarmConfig as OrcaDevnetFarmConfig } from "./farms/config"; 3 | import { OrcaPoolConfig as OrcaDevnetPoolConfig } from "./pools/config"; 4 | 5 | export function getDevnetPool(config: OrcaPoolConfig): OrcaDevnetPoolConfig { 6 | const entry = Object.entries(OrcaPoolConfig).find((arr) => arr[1] === config); 7 | if (!entry) { 8 | throw new Error("Invalid OrcaPoolConfig"); 9 | } 10 | 11 | const key = entry[0]; 12 | if (!isOrcaDevnetPoolConfig(key)) { 13 | throw new Error(`${key} does not exist in devnet`); 14 | } 15 | 16 | return OrcaDevnetPoolConfig[key]; 17 | } 18 | 19 | export function getDevnetFarm(config: OrcaFarmConfig): OrcaDevnetFarmConfig { 20 | const entry = Object.entries(OrcaFarmConfig).find((arr) => arr[1] === config); 21 | if (!entry) { 22 | throw new Error("Invalid OrcaFarmConfig"); 23 | } 24 | 25 | const key = entry[0]; 26 | if (!isOrcaDevnetFarmConfig(key)) { 27 | throw new Error(`${key} does not exist in devnet`); 28 | } 29 | 30 | return OrcaDevnetFarmConfig[key]; 31 | } 32 | 33 | /*** Type guards ***/ 34 | 35 | function isOrcaDevnetPoolConfig(key: string): key is keyof typeof OrcaDevnetPoolConfig { 36 | return OrcaDevnetPoolConfig[key as keyof typeof OrcaDevnetPoolConfig] !== undefined; 37 | } 38 | 39 | function isOrcaDevnetFarmConfig(key: string): key is keyof typeof OrcaDevnetFarmConfig { 40 | return OrcaDevnetFarmConfig[key as keyof typeof OrcaDevnetFarmConfig] !== undefined; 41 | } 42 | -------------------------------------------------------------------------------- /src/public/farms/config.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * The following content is auto-generated. 3 | */ 4 | 5 | /** 6 | * A list of supported Orca farms in this SDK. 7 | */ 8 | export enum OrcaFarmConfig { 9 | SOL_USDC_AQ = "APDFRM3HMr8CAGXwKHiu2f5ePSpaiEJhaURwhsRrUUt9", 10 | SOL_USDT_AQ = "FZthQCuYHhcfiDma7QrX7buDHwrZEd7vL8SjS6LQa3Tx", 11 | ETH_SOL_AQ = "71FymgN2ZUf7VvVTLE8jYEnjP3jSK1Frp2XT1nHs8Hob", 12 | ETH_USDC_AQ = "3e1W6Aqcbuk2DfHUwRiRcyzpyYRRjg6yhZZcyEARydUX", 13 | RAY_SOL_AQ = "5kimD5W6yJpHRHCyPtnEyDsQRdiiJKivu5AqN3si82Jc", 14 | ROPE_SOL_AQ = "ADrvfPBsRcJfGsN6Bs385zYddH52nuM5FA8UaAkX9o2V", 15 | STEP_SOL_AQ = "8nTzqDXHriG2CXKbybeuEh1EqDQMtrbYMFWcP7AkiDaP", 16 | SRM_SOL_AQ = "9tf8rBSEQYG7AqL896fN2nZi1iYPqpWaLEdpbeQaC1Vy", 17 | FTT_SOL_AQ = "EsYaDKJCmcJtJHFuJYwQZwqohvVMCrFzcg8yo3i328No", 18 | COPE_SOL_AQ = "CzieDbGRdN1QGaGDNpSqzEA18bi881ccvkkGZi51pe1k", 19 | OXY_SOL_AQ = "7tYCdLN84EnTMkxM7HNamWJx7F4xgKe9KiiWvLyWjbgT", 20 | BTC_SOL_AQ = "Acxs19v6eUMTEfdvkvWkRB4bwFCHm3XV9jABCy7c1mXe", 21 | MER_SOL_AQ = "HiwRobjfHZ4zsPtqCC4oBS24pSmy4t8GGkXRbQj4yU6L", 22 | FIDA_SOL_AQ = "EYsNdtyu4gGTaGz8N5m5iQ3G1N6rDyMbR72B3CqbWW4W", 23 | MAPS_SOL_AQ = "99pfC8fWymXgbq3CvrExhx3UxQDC1fMWEWLbNT83F45e", 24 | USDC_USDT_AQ = "H2uzgruPvonVpCRhwwdukcpXK8TG17swFNzYFr2rtPxy", 25 | ORCA_SOL_AQ = "2uVjAuRXavpM6h1scGQaxqb6HVaNRn6T2X7HHXTabz25", 26 | ORCA_USDC_AQ = "n8Mpu28RjeYD7oUX3LG1tPxzhRZh3YYLRSHcHRdS3Zx", 27 | KIN_SOL_AQ = "HEvnD66WcBfTajS9adUYnGRBMDehFtLySiFHSD6kEBWs", 28 | SAMO_SOL_AQ = "D6N9j8F2DhtzDtrdpT74y3u2YmYAzcggiLc3nTjqux9M", 29 | LIQ_USDC_AQ = "3PD9SZFwXKkXr4akLf4ofo37ZUMycwML89R2P3qxcbZG", 30 | SNY_USDC_AQ = "AZpo4BJHHRetF96v6SGinFZBMXM4yWMo4RA8C4PriDLk", 31 | mSOL_USDC_AQ = "8PSfyiTVwPb6Rr2iZ8F3kNpbg65BCfJM9v8LfB916r44", 32 | SLRS_USDC_AQ = "AtB4nUmdyQfuWWJ9xAHw9xyVnJFfSjSuVWkiYan8y86w", 33 | PORT_USDC_AQ = "F8gPSpwVHj8FdAJAYULDuZBxFEJut87hUbARYYx3471w", 34 | SBR_USDC_AQ = "CS7fA5n4c2D82dUoHrYzS3gAqgqaoVSfgsr18kitp2xo", 35 | scnSOL_USDC_AQ = "Dkr8B675PGnNwEr9vTKXznjjHke5454EQdz3iaSbparB", 36 | pSOL_USDC_AQ = "C2YzN6MymD5HM2kPaH7bzcbqciyjfmpqyVaR3KA5V6z1", 37 | mSOL_SOL_AQ = "29cdoMgu6MS2VXpcMo1sqRdWEzdUR9tjvoh8fcK8Z87R", 38 | ORCA_PAI_AQ = "C7TH2jEJJaxVwwuvkbcDGfHUiZvEkkeYjyAcdTMi5ujb", 39 | ORCA_mSOL_AQ = "CVapmQn7HaU1yMDW3q6oUV4hx6XoYv54T4zfGXkuJqkA", 40 | scnSOL_SOL_AQ = "APNpzQvR91v1THbsAyG3HHrUEwvexWYeNCFLQuVnxgMc", 41 | ATLAS_USDC_AQ = "FZ8x1LCRSPDeHBDoAc3Gc6Y7ETCynuHEr5q5YWV7uRCJ", 42 | POLIS_USDC_AQ = "GteBdo9sqE7T41G8AJsaG9WHW48uXBwsLLznmu2TBdgy", 43 | BOP_USDC_AQ = "2gXDJZ7XAtQEtf4PRSQZKoq1WMuu1H44tQanbMA3YVpu", 44 | SAMO_USDC_AQ = "6VK1ksrmYGMBWUUZfygGF8tHRGpNxQEWv8pfvzQHdyyc", 45 | NINJA_SOL_AQ = "4X1oYoFWYtLebk51zuh889r1WFLe8Z9qWApj87hQMfML", 46 | SLIM_USDC_AQ = "BVWwyiHVHZQMPHsiW7dZH7bnBVKmbxdeEjWqVRciHCyo", 47 | wHAPI_USDC_AQ = "ELfBngAgvLEHVBuJQhhE7AW6eqLX7id2sfrBngVNVAUW", 48 | COPE_USDC_AQ = "HsauTv9s52Zv12eaDuSp6y7BEm4e4BHEyAsbdjyyWzPK", 49 | SUNNY_USDC_AQ = "GHuoeq9UnFBsBhMwH43eL3RWX5XVXbSRYJymmyMYpT7n", 50 | GRAPE_USDC_AQ = "EorFh8siFyLF1QTZ7cCXQaPGqyo7eb4SAgKtRH8Jcxjd", 51 | ABR_USDC_AQ = "GMzPbaCuQmeMUm1opH3oSCgKUjVgJUW14myq99RVPGX5", 52 | KURO_USDC_AQ = "DRknxb4ZFxXUTG6UJ5HupNHG1SmvBSCPzsZ1o9gAhyBi", 53 | MEDIA_USDC_AQ = "2toFgkQDoPrTJYGDEVoCasPXuL9uQnjvXJaDwa9LHyTx", 54 | TULIP_USDC_AQ = "4SBx8GXu8HhcVHWydQv1vsDdZs3G93XSL9CtMBny6hS5", 55 | MNGO_USDC_AQ = "H9yC7jDng974WwcU4kTGs7BKf7nBNswpdsP5bzbdXjib", 56 | stSOL_wstETH_AQ = "Eswigpwm3xsipkTqahGi2PEJsJcULQBwZgxhQpr6yBEa", 57 | SYP_USDC_AQ = "qJxKN9BhxbYvRNbjfK2uAVWboto6sonj8XC1ZEW5XTB", 58 | stSOL_wLDO_AQ = "74B9aMS7SA832xKngt5VLKmWAP3pa3qkUzWncTmQSsGF", 59 | whETH_SOL_AQ = "7aYnrdmdCRodDy2Czn6keUquUhjF1jPEmfwZPh488z8U", 60 | whETH_USDC_AQ = "7NPtjjAP7vhp4t5NCLyY4DY5rurvyc8cgZ2a2rYabRia", 61 | MNDE_mSOL_AQ = "5PHS5w6hQwFNnLz1jJFe7TVTxSQ98cDYC3akmiAoFMXs", 62 | WAG_USDC_AQ = "Df6XNHMF3uRVZnz7LCEGiZVax6rXgz76owtVkBHEjSb6", 63 | mSOL_USDT_AQ = "9cMWe4UYRPGAUUsTkjShJWVM7bk8DUBgxtwwH8asFJoV", 64 | mSOL_whETH_AQ = "5qoTq3qC4U7vFxo3iCzbXcaD1UEmDeCD63Dsuoct71oV", 65 | BTC_mSOL_AQ = "8nKJ4z9FSw6wrVZKASqBiS9DS1CiNsRnqwCCKVQjqdkB", 66 | IVN_SOL_AQ = "DfgCnzaiTXfPkAH1C1Z441b5MzjjTCEh134ioxqRZxYf", 67 | LARIX_USDC_AQ = "8sfThep3io4gvcGeuoAg1Rs8GDwKJjtcdAFHqQSSNAVE", 68 | PRT_USDC_AQ = "6jCERp5hKj37PCXP3VTjCDJeoPuSpnMDMz5A6jWQv3yS", 69 | JET_USDC_AQ = "GBijunwxa4Ni3JmYC6q6zgaVhSUJU6hVX5qTyJDRpNTc", 70 | stSOL_USDC_AQ = "GtQ1NT7R5aaTiST7K6ZWdMhwDdFxsSFvVFhBo8vyHGAq", 71 | wstETH_USDC_AQ = "5a6Y1ephcbKSoyLMQyD1JWbtqawCy8p2FtRL9v3zhaG5", 72 | AURY_USDC_AQ = "6mJqqT5TMgveDvxzBt3hrjGkPV5VAj7tacxFCT3GebXh", 73 | AVAX_USDC_AQ = "Hmfrtmo93DpSDmVNLQKcBS5D1ia5JatiRSok9ososubz", 74 | FTT_USDC_AQ = "FwCombynV2fTVizxPCNA2oZKoWXLZgdJThjE4Xv9sjxc", 75 | RAY_USDC_AQ = "4cXw2MYj94TFBXLL73fEpMCr8DPrW68JvrV8mzWgktbD", 76 | SLND_USDC_AQ = "F59gkD7NnsdJbFKrRZsiBC8PAooN4c56T8QmahfW1iXN", 77 | GOFX_USDC_AQ = "7vnps4VE5RTGAr5fmPZu7fSrk2VnM4Up838grZfqmxqE", 78 | WOOF_USDC_AQ = "9EjcYfHcG8f1mccpHyaAwpoxaUPiheC6KgLQjyD9aTb6", 79 | SDOGE_USDC_AQ = "CHTKUJGYRtBDqnxCFjxe5KEkZgxV98udbhuYYyzGxup5", 80 | CATO_USDC_AQ = "55r9txzQtmjTykmTXmBYZCVMg5z9squB8b5cSw2AhxA4", 81 | OOGI_USDC_AQ = "DSiHyHDn96bUQSZtizyCRLcQzrwohZeMpVu8rYJN1HzG", 82 | SONAR_USDC_AQ = "5MvQHx8eftU39JTucFsT315JFnQASuDQg3FqxTw7xcvN", 83 | APT_USDC_AQ = "HNrYngS1eoqkjWro9D3Y5Z9sWBDzPNK2tX4rfV2Up177", 84 | DFL_USDC_AQ = "AWrtTWG4Zgxw8D92bb3L3sQtGLD3zDztMPWsXSph8iBP", 85 | DFL_SOL_AQ = "9Y1vPaAsMz8X65DebMMnmBjbMo8i4jh4mcgiggZUUS3M", 86 | FRKT_USDC_AQ = "FnDxJPNk7pPmGHUbR4XUHmHevrkXHdna5D3sQKcAtjBL", 87 | TTT_USDC_AQ = "FGgP1npQTsC5Q4xBmQtNYSh51NKqNwdxBZy8JCo3igcu", 88 | UPS_USDC_AQ = "E1U63VXhNiWoUkVvjrfLDdV1oJrwE6zLde3bohr6jCqz", 89 | FANT_USDC_AQ = "GjG7JjTQfQpDxw4hWx4etP9oTaYCuCbPjsU8WaUT3xHB", 90 | BLOCK_USDC_AQ = "D8WjqtwC9CzBrQKfSf2ccCHFQuPYwyLv5KAy8WjT5vnf", 91 | RUN_USDC_AQ = "34Ppq6R8NfYBwWwPY4cBK4Afyb8hHaASQFukCzH6cV4n", 92 | UXP_USDC_AQ = "HjR8JgqNKQVMvdryqJw5RJ4PCE9WGk8sgbEF7S9S3obv", 93 | BTC_USDC_AQ = "J3kvcay3N16FBdawgnqoJ9v9p6XCvyCLE2Z9F5RLvGkj", 94 | MNDE_USDC_AQ = "12Uj74zgUUoBe4yeackwQ4qYtFMr9fk1xL6q5Nha6t2N", 95 | CHICKS_USDC_AQ = "71CBZeJ4tw38L9pSPoCz4fRsuWE64Fipyzotte7haoCS", 96 | ONESOL_USDC_AQ = "6MF5CHWAj5mS7FhpxiKz37CzR2eYTu236XpBKKMXCrGg", 97 | WMP_USDC_AQ = "HDgxKmiA8Pv82fNguhVeMkZqQkos2YksFPoP1KttWxX8", 98 | UNQ_USDC_AQ = "2VuGzaMrDnDyZfYvDwSXk38s7M2wpud7LDY3dGA1J9sy", 99 | BASIS_USDC_AQ = "GoaAiajubRgeCFEz9L6mLnSmT2QFegoJDH5tpLfivpj", 100 | GST_USDC_AQ = "E6FUnQHGHJVJg7oExVr5Moeaj1QpdpZQF5odYjHXWPZb", 101 | MEAN_USDC_AQ = "F5BTnwuMA6rxftTdbZ33VWKr2wrr6DuQHnd4guKmPSYQ", 102 | AART_USDC_AQ = "HCtyJzFUtYecXrA52s4Y9atq4J1fhT3cYsTX17XVSFag", 103 | SHDW_USDC_AQ = "DJqqvzSuPaWThfzwMjXx7H2ZmHDdwxza6NtFudtuXcpc", 104 | SHDW_SOL_AQ = "2ws7g3LBPdctfKn42Di9qxzQtUJ8ZL1aEAX2rGEQMNqh", 105 | SCY_USDC_AQ = "99ZHUQsgxL7K6PHrGNi1gSwawwPr7UA5fbWrYoHQ6qhX", 106 | SLC_USDC_AQ = "E5kSBqTDxFLbLNQaVVtPtnhEYVLMCK2fVSEKoMKL98qR", 107 | wUST_SOL_AQ = "6c13xsmyk7UaHUWZ2rm1MM3ZdrQRSBkQ9waaG25ridVs", 108 | wUST_USDC_AQ = "J1KfRtP5y2warpD7LdJhfBLPKoWwSqYuovdArSv1mpQ7", 109 | mSOL_wUST_AQ = "68YVjgPnTUPcBqZyghqvD2WPNsrLKsjYTmBKJzHRr4qd", 110 | wLUNA_wUST_AQ = "8Mh7drLbt3jFJYwp948XyvQscGLaLkChNcaH5wwaAoWA", 111 | stSOL_wUST_AQ = "HTZd53fYwYQRyAjiaPsZy9Gf41gobFdqkF4oKe3XLi95", 112 | JSOL_USDC_AQ = "AzEoVuNJyo9ByoLRZ5t6vav2Zg24vULNVJM41PgCKUqR", 113 | daoSOL_USDC_AQ = "CCyDxjdW3G7hPTthTMPTZ4bnhFF19XG6rx2fNiKeRQww", 114 | ORCA_USDT_AQ = "Gx4PoxenyQwhGGnKagAT35iVg4im1iKhJxDWqVhgu6tk", 115 | ORCA_whETH_AQ = "GsfyYHkSgC3Ta6aWR9MjB2sxoBrkGGeR2tAwXbpphf3", 116 | GENE_USDC_AQ = "7cuu94swKL5PtFQohKMAzyd1mjj65rgMW3GzLY31HCnK", 117 | CMFI_USDC_AQ = "85krvT9DxdYgoFLQDHTAGdvtNuLdAsc4xE5FkVLpN2aR", 118 | CELO_USDC_AQ = "HVLyX8mD8YvKgZJ4oB6rXJiCYMLpHKwB6iCiCjE1XwdT", 119 | FTM_USDC_AQ = "Gpzd833qSmv3kXpQmxEaqkrZTXZaRjhNAoqhf61qAhTG", 120 | BTC_ORCA_AQ = "DFpLFcQZqDKykyDePgip4r6MExVmBKWqTa12ezq6qxUY", 121 | HBB_USDC_AQ = "cL5WhffCYFRLM4We8VS2W684kM4pHyuvEDwp8Ddw48k", 122 | HBB_SOL_AQ = "FkKzu2HeMJZf4oHwoYPxLGVy3net5Jq8HAfnA5VqETgk", 123 | SB_USDC_AQ = "2Reqt4Sw9xNY8BoJ3EZLpFu5yVgNxFrbw8M3KiJpPn6o", 124 | stSOL_USDT_AQ = "4ni1nho89cDKAQ9ddbNQA9ieLYpzvJVmJpuogu5Ct5ur", 125 | SEEDED_USDC_AQ = "H7gyTmNCDXkD8MGMqnxqoD8ANszjcju4tjT6ERZ5dakf", 126 | AUDIO_USDC_AQ = "3hksYA17VxgiKSeihjnZkBbjc2CTbEBfvDCYgQhojTo5", 127 | MMA_USDC_AQ = "AaZRnJAnDyJyPD9uPJpJ8bzBGDCEi6jtBpUf92xErWPp", 128 | ONESOL_SOL_AQ = "9wPhuYapychVDSxmXqCZxy2Ka8Lmav4SHM72si8bfraV", 129 | PUFF_SOL_AQ = "Eho8h1BcoG5QWU7X9FzJafw5ErKUXtR2LobAJJZfWff4", 130 | SAO_USDC_AQ = "4iyU77yZbg8iD344vbwruAuDAf9i1EVV3FhZJDnWStBE", 131 | sRLYv2_SOL_AQ = "3dXdXg5HPyZ73GFC9LkSn3thdJUGeXWB8iSTHs5UcqiH", 132 | ZBC_USDC_AQ = "2LYgm6nGXmSSjfoEriPuYeGoNiWNxUs7n3rnTbDWN5c7", 133 | GMT_USDC_AQ = "CFxQF5kNAtbbDj298Xr47Sf4mkSyuzWpRH97hrdQ6kxi", 134 | NOVA_USDC_AQ = "DdAFNvDxtEHCgKj3JAM64zCKfMWhs4J9wEmRrjUAFiME", 135 | HBB_USDH_AQ = "7n2YW9qLkhGFArdZPLoF4hYPE2zw7xCACkVPXrUWnLuo", 136 | TAKI_sRLYv2_AQ = "6atKbS2Xz5vu7cqWBNk8KYkuakRzckZ9nvtUKf2k8Sc3", 137 | ZIG_USDC_AQ = "5vhh9ZnD9vnahRhFLP1EUEyYRSzvJwgw9U2xygsSJSrp", 138 | sRLY_SOL_AQ = "HfRgvhgscGX5GaP3rUrZAhh7gS4aJ2UQ7rNVX976rG6P", 139 | TAKI_sRLY_AQ = "3xaK5aWWLNRB73xUVX3cusLhDp65mTvP4fwW5Jwxakgs", 140 | stSOL_SOL_AQ = "4jjQSgFx33DUb1a7pgPsi3FbtZXDQ94b6QywjNK3NtZw", 141 | BTC_stSOL_AQ = "HYp9v7cY4wAxSsa6ijztQQ3GQ8iTttuG5vu8JNBDHoNh", 142 | stSOL_whETH_AQ = "FWurFWADrgmhb6Y44LEaCMnEHS2Tu3QGqd9oBcZtr8gT", 143 | LIQ_USDC_DD = "57vGdcMZLnbNr4TZ4hgrpGJZGR9vTPhu8L9bNKDrqxKT", 144 | STEP_SOL_DD = "GwrBA1F8rGummDCDd8NY9Eu1cLNuJqbT8WaGxgWpFwGL", 145 | SLRS_USDC_DD = "66xCxkffQZKBZLiHV3PDcfR8ANJTfnDRxPCaBdv4wxB7", 146 | PORT_USDC_DD = "4CGxvZdwiZgVMLXiTdJHTkJRUTpTSJCtmtCRbSkAxerE", 147 | COPE_USDC_DD = "9SDpBrfqNxjXcCzpKWM6yUKdfky975VJBD6xcu5cKf5s", 148 | BOP_USDC_DD = "A7vvbqENJj8kED3ABjphe8TvwpasQYtoWGKpjpLArMxa", 149 | SAMO_USDC_DD = "9voVuTq1S9bFZkF2Jo44HoVG63w2xDRT8eBzB23YbQud", 150 | wHAPI_USDC_DD = "Bfoi3RNnfdP5VeRGqvTA8MRN9ePGJoZgeKfe8WeBHUxE", 151 | SLIM_USDC_DD = "3K7aZhtwWJ2JS6GnbbgeDVnxd1q2hwhqasmgRsAMZ4yC", 152 | NINJA_SOL_DD = "7YyhptkxY81HPzFVfyCzA5UXxWdsNRD41ofLva3TuSpd", 153 | ATLAS_USDC_DD = "HFmY1ggCsCky1zJ1sfdkNR4zb3u5n38YNRdf4vsGu17t", 154 | POLIS_USDC_DD = "63JUKLnCAuNMPSPioEgbjjzp9Qk8qSEEM8eZqEtPqfLU", 155 | ABR_USDC_DD = "5uR5STASUmoGVHzqMeut98t26TfVkQqWU9f9dsv3NfJ6", 156 | KURO_USDC_DD = "6PGoaQdL9e463hdaFxHXsuPcjCHRK32CQ9PFKxvM7XY2", 157 | mSOL_USDC_DD = "5r3vDsNTGXXb9cGQfqyNuYD2bjhRPymGJBfDmKosR9Ev", 158 | ORCA_mSOL_DD = "3Duk5b6fLztPmS4ryV48FM1Q9WXUSMwz9jehAT4UtqpE", 159 | mSOL_SOL_DD = "3RTGL7gPF4V1ns1AeGFApT7cBEGVDfmJ77DqQi9AC6uG", 160 | stSOL_wstETH_DD = "3kT3oYuS1rCfhmqfgy6EKcbZdaJimaVEjoy25QiuEaoj", 161 | SYP_USDC_DD = "Ds4VGZhZzS2PMFzhzKeC3mwcQjdiCG21R76fTVbsSJyJ", 162 | MNDE_mSOL_DD = "2wPsMuzhEsC6GhV3qtFpmJF6atEgLGbnmQ8U43Y6fPxZ", 163 | mSOL_USDT_DD = "Afvh7TWfcT1E9eEEWJk17fPjnqk36hreTJJK5g3s4fm8", 164 | mSOL_whETH_DD = "58nifjPjF3CutGz2xMxvAMk7R9YgbVEc8Cstj4rCcs8j", 165 | BTC_mSOL_DD = "DzpLz78wuwyFsQToin8iDv6YK6aBEymRqQq82swiFh7r", 166 | IVN_SOL_DD = "HqajzzbGMST3yCCVBJuXvNVsWkY2DXqiBz9cTRmmyBMy", 167 | LARIX_USDC_DD = "DNAGfa7tK8csprRQmiDUwDaFfhw6ueHhVFHTCgTJ8HGs", 168 | GOFX_USDC_DD = "B95rdqSY4dqPwmt295XwBZZqZJYLmqDNXU6NvBpT4ep4", 169 | WOOF_USDC_DD = "4HaQXDz9gdLgKUjvNVtnLyNZoWNYKjh3XxH1TpLgiwmi", 170 | SDOGE_USDC_DD = "4kXYyZAMBdvgDaBKUGvRWJnHw9af7sCUPvpQ68PEdP8b", 171 | CATO_USDC_DD = "BHtZnTBMeY4EBEW5egGnuK5bdW12v6Dod6wFav79AyYx", 172 | OOGI_USDC_DD = "FiwSk36yi1DNWcuQUeNipAc1VKxa9Wv9AR2xFvyKUxAE", 173 | SONAR_USDC_DD = "GWmwwMGYBG4NqYdnsYrudzBnbgDC49MkBxdzhfLA9kVY", 174 | UPS_USDC_DD = "9fuv3emLQXECrTWqm2HaKT3wQhmvmgqmReZSMcu8PfpH", 175 | FANT_USDC_DD = "C2EcthTMaC5eATXVaXg5ctvMfUYYgFyNibybHes5D3S6", 176 | stSOL_USDC_DD = "3u2dNfGuU6C3vmSg5EvLPUpX57b3niqhWBV5Gc3WDEf5", 177 | WMP_USDC_DD = "Ce3VXSQGFEHqrQSEzcVb2Ro88Mcn56cYBUAXFx5tL9bo", 178 | CHICKS_USDC_DD = "GTcxXu3yw7yotq2UtAMvpEbx84ozJyrBwy77Cmem7m4X", 179 | UNQ_USDC_DD = "CsGTrgJ6oLx9UQow9aLjuAacjXTY53zT8B2FnAbfVZAS", 180 | MEAN_USDC_DD = "3h2VBX8533NB8eEH8rPXMdayodFDbgTHpbav6JqLZAQq", 181 | WAG_USDC_DD = "8Wu5sJpERA1J5iWcT8aMpt9cTAfKDLPbLpGjNsJoPgLc", 182 | SHDW_USDC_DD = "7WWHfufv8vuBC1x7GXA3pu7kgNhEQkXoq3CtbaQihAJ9", 183 | SHDW_SOL_DD = "BDStVBt4NS5bfda25ubK51kVRioV4yjKKCPbe96jeEms", 184 | AART_USDC_DD = "Bg7pZq7KdsQsnCQBeNpa4XVnrWfjUJNu3ViHoNB7YUZU", 185 | BASIS_USDC_DD = "4yx2aHMa7N4m1uUaBRy9QPtpstw3HFPtvcCPJQaGFHKL", 186 | SLC_USDC_DD = "X8GnAvxq942xXjNzqYPFQQ9JstJQNEA81uPeNoQpgrN", 187 | wUST_SOL_DD = "F49Cm3srGucQCBanA2xL7nSKHfH1QZd9vLdFtkg4LKnq", 188 | wUST_USDC_DD = "2mhVUMsG7eb3XhHjAbKpRZgWNyGZNCiWU7dRxauzZaGL", 189 | mSOL_wUST_DD = "6wqME6zPQzGDLugpnwZnVBKBbATC5nTaEa781Vj98yvM", 190 | wLUNA_wUST_DD = "3ZGKT28NXAqb2YtUAMvKixQvHNHT31Q5mK8AC2iBMs29", 191 | stSOL_wUST_DD = "3Q44iV4URXdbS4Tk1PGs5VdWQoCxHB7zdcdMnemo8jfH", 192 | CMFI_USDC_DD = "E8RVjS24pBuF3oCCeJVAgC4RQ7mVa5P3FGXqGbiczzvD", 193 | HBB_USDC_DD = "BxPd4x7gm6WQF6jsDCRQuQVZ2bopQ4KegMrqyQgdkPDk", 194 | CELO_USDC_DD = "9RRBDWZGWGVnHgazCpb9R1XApmHLBDya8Tq1yrzoMsKY", 195 | SB_USDC_DD = "3Wppx86xN7Dg7GLUTD9C7AqCt68qZkWzNYUdCS7t1pCk", 196 | FTM_USDC_DD = "E7Af9Fa2U1YqEkQpAYjXwDB5TJUou9VcN3ot33Gj6UY9", 197 | stSOL_USDT_DD = "CtvKaRLzCzRZCcYPwai7NCYBK4ArBj2oD6BfvMgJoiCN", 198 | SEEDED_USDC_DD = "H15WptGntFQifZmJHUzYBV9Mv7P27ofavEsF6yqpLTdX", 199 | ONESOL_SOL_DD = "Hva9oLa2GjoKdB45WoHujsX7MTpehByPshMrQpNDmkFq", 200 | MMA_USDC_DD = "H9qkbU2XYSQTk6JJJ2TMuZBthfkeCHigmuxB5jiQaamn", 201 | PUFF_SOL_DD = "Ge5kuYg5PekrPUeKzngw97Cnfngj8j6NCX5q1jTBkWSW", 202 | SAO_USDC_DD = "A9BeGSRJJYXPrMs81rVZxvkk16fopzgG5YkngntgTu7p", 203 | sRLYv2_SOL_DD = "6gkZ7QUmxmwPLS2NK3Dr6YHtTPZs6GQrkA595WSx5iLe", 204 | ZBC_USDC_DD = "7Hoi4adCSBzERdvSiUXtVDz79tiDxMD5HpDv7m9rs3Sb", 205 | NOVA_USDC_DD = "H2jZrZKx1fLY9LPi2ad5G2DVBWzMmUwPQLjRFERUroEH", 206 | HBB_USDH_DD = "DUGuXcpHX9y6WdTKgDm8XsECbf7pApA7ZvAsjUqHUoYn", 207 | ZIG_USDC_DD = "9nKbvVW9TjdnKt2NbfMaf9PHcg8zWWFgGTBfzUXdFcke", 208 | sRLY_SOL_DD = "HfkZkoPqZzd7S1F3BhkJN2Es1C5vabVYqfCecXG2MGHP", 209 | TAKI_sRLY_DD = "13HwDUH7yREGAwHSWnx4Kgnn6huL8yfCCBqaBr6NGVH6", 210 | stSOL_SOL_DD = "7ZvhrqdnP2NrQi2YCjQNd8jKJpLDMUuZg4wP7XJPjnVX", 211 | BTC_stSOL_DD = "GjBW6751wNJ99zYkr9QwSi98bvj1NgyAcYHfQDpemJfq", 212 | stSOL_whETH_DD = "9V9CavjccKJH66m4MJHzVBYzY2ZM3U3D5xUCP7HSyAUz", 213 | } 214 | -------------------------------------------------------------------------------- /src/public/farms/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./config"; 2 | export * from "./types"; 3 | -------------------------------------------------------------------------------- /src/public/farms/types.ts: -------------------------------------------------------------------------------- 1 | import { Keypair, PublicKey } from "@solana/web3.js"; 2 | import Decimal from "decimal.js"; 3 | import { OrcaU64, TransactionPayload } from ".."; 4 | 5 | export type OrcaFarm = { 6 | /** 7 | * Query the balance for an user address 8 | * @param wallet The public key for the user. 9 | * @return Returns the amount of farm token the user owns for this pool. 10 | */ 11 | getFarmBalance: (owner: PublicKey) => Promise; 12 | 13 | /** 14 | * Query the supply of farm tokens for this pool. 15 | * @return Returns the supply of farm tokens for this pool. 16 | */ 17 | getFarmSupply: () => Promise; 18 | 19 | /** 20 | * Perfrom a deposit: send baseToken, and receive farmToken in return. 21 | * Fee for the transaction will be paid by the owner's wallet. 22 | * 23 | * NOTE: 24 | * 1. Associated Token Address initialization instructions will be appended if the ATA of the specified token does not exist in the user's wallet 25 | * 2. OrcaU64 must have the same scale as the corresponding token scale value 26 | * 27 | * @param owner The keypair for the user's wallet or just the user's public key 28 | * @param baseTokenAmount The amount of baseToken to deposit 29 | * @return The transaction signature of the deposit instruction 30 | */ 31 | deposit: ( 32 | owner: Keypair | PublicKey, 33 | baseTokenAmount: Decimal | OrcaU64 34 | ) => Promise; 35 | 36 | /** 37 | * Perfrom a withdraw: send farmToken, and receive baseToken in return. 38 | * Fee for the transaction will be paid by the owner's wallet. 39 | * 40 | * WARNING: 41 | * 1. Withdraw is only supported from the public key that initiated the deposit. 42 | * 43 | * NOTE: 44 | * 1. Associated Token Address initialization instructions will be appended if the ATA of the specified token does not exist in the user's wallet 45 | * 2. OrcaU64 must have the same scale as the corresponding token scale value 46 | * 47 | * @param owner The keypair for the user's wallet or just the user's public key 48 | * @param baseTokenAmount The amount of baseToken to receive 49 | * @return The transaction signature of the deposit instruction 50 | */ 51 | withdraw: ( 52 | owner: Keypair | PublicKey, 53 | baseTokenAmount: Decimal | OrcaU64 54 | ) => Promise; 55 | 56 | /** 57 | * Get the total amount of rewards that has accumulated in the user's farm. 58 | * 59 | * Returns 0 if: 60 | * 1. the user does not have a farm initialized (by calling deposit) 61 | * 2. the user's farm balance is empty 62 | * 63 | * @param ownerPublicKey The public key of the user 64 | * @return The amount of reward that can be harvestable by the user 65 | */ 66 | getHarvestableAmount: (ownerPublicKey: PublicKey) => Promise; 67 | 68 | /** 69 | * Harvest all of the rewards that has accumulated in the user's farm. 70 | * 71 | * Throws error if the user does not have a farm initialized (by calling deposit) 72 | * 73 | * @param owner The keypair for the user's wallet or just the user's public key 74 | * @return The transaction signature of the harvest instruction 75 | */ 76 | harvest: (owner: Keypair | PublicKey) => Promise; 77 | 78 | /** 79 | * Get amount of reward tokens emitted to all liquidity per day. 80 | */ 81 | getDailyEmissions: () => Promise; 82 | }; 83 | -------------------------------------------------------------------------------- /src/public/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./utils"; 2 | export * from "./pools"; 3 | export * from "./main"; 4 | export * from "./farms"; 5 | -------------------------------------------------------------------------------- /src/public/main/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./orca"; 2 | export * from "./types"; 3 | -------------------------------------------------------------------------------- /src/public/main/orca.ts: -------------------------------------------------------------------------------- 1 | import { Connection } from "@solana/web3.js"; 2 | import { Network } from ".."; 3 | import { OrcaImpl } from "../../model/orca/orca-impl"; 4 | import { Orca } from "./types"; 5 | 6 | /** 7 | * Retrieve an instance of the Orca SDK 8 | * @param connection Solana connection class 9 | * @returns An instance of Orca SDK 10 | */ 11 | export function getOrca(connection: Connection, network = Network.MAINNET): Orca { 12 | return new OrcaImpl(connection, network); 13 | } 14 | -------------------------------------------------------------------------------- /src/public/main/types.ts: -------------------------------------------------------------------------------- 1 | import { OrcaFarm, OrcaPool, OrcaPoolConfig, OrcaFarmConfig } from ".."; 2 | 3 | export type Orca = { 4 | /** 5 | * Get an instance of an Orca pool. 6 | * @param pool a pool config targeting an Orca pool 7 | */ 8 | getPool: (pool: OrcaPoolConfig) => OrcaPool; 9 | 10 | /** 11 | * Get an instance of an Orca farm. 12 | * @param farm a farm config targeting an Orca farm 13 | */ 14 | getFarm: (farm: OrcaFarmConfig) => OrcaFarm; 15 | }; 16 | -------------------------------------------------------------------------------- /src/public/pools/config.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * The following content is auto-generated. 3 | */ 4 | 5 | /** 6 | * A list of supported Orca pools in this SDK. 7 | */ 8 | export enum OrcaPoolConfig { 9 | SOL_USDC = "APDFRM3HMr8CAGXwKHiu2f5ePSpaiEJhaURwhsRrUUt9", 10 | SOL_USDT = "FZthQCuYHhcfiDma7QrX7buDHwrZEd7vL8SjS6LQa3Tx", 11 | ETH_SOL = "71FymgN2ZUf7VvVTLE8jYEnjP3jSK1Frp2XT1nHs8Hob", 12 | ETH_USDC = "3e1W6Aqcbuk2DfHUwRiRcyzpyYRRjg6yhZZcyEARydUX", 13 | RAY_SOL = "5kimD5W6yJpHRHCyPtnEyDsQRdiiJKivu5AqN3si82Jc", 14 | ROPE_SOL = "ADrvfPBsRcJfGsN6Bs385zYddH52nuM5FA8UaAkX9o2V", 15 | STEP_SOL = "8nTzqDXHriG2CXKbybeuEh1EqDQMtrbYMFWcP7AkiDaP", 16 | SRM_SOL = "9tf8rBSEQYG7AqL896fN2nZi1iYPqpWaLEdpbeQaC1Vy", 17 | FTT_SOL = "EsYaDKJCmcJtJHFuJYwQZwqohvVMCrFzcg8yo3i328No", 18 | COPE_SOL = "CzieDbGRdN1QGaGDNpSqzEA18bi881ccvkkGZi51pe1k", 19 | OXY_SOL = "7tYCdLN84EnTMkxM7HNamWJx7F4xgKe9KiiWvLyWjbgT", 20 | BTC_SOL = "Acxs19v6eUMTEfdvkvWkRB4bwFCHm3XV9jABCy7c1mXe", 21 | MER_SOL = "HiwRobjfHZ4zsPtqCC4oBS24pSmy4t8GGkXRbQj4yU6L", 22 | FIDA_SOL = "EYsNdtyu4gGTaGz8N5m5iQ3G1N6rDyMbR72B3CqbWW4W", 23 | MAPS_SOL = "99pfC8fWymXgbq3CvrExhx3UxQDC1fMWEWLbNT83F45e", 24 | USDC_USDT = "H2uzgruPvonVpCRhwwdukcpXK8TG17swFNzYFr2rtPxy", 25 | ORCA_SOL = "2uVjAuRXavpM6h1scGQaxqb6HVaNRn6T2X7HHXTabz25", 26 | ORCA_USDC = "n8Mpu28RjeYD7oUX3LG1tPxzhRZh3YYLRSHcHRdS3Zx", 27 | KIN_SOL = "HEvnD66WcBfTajS9adUYnGRBMDehFtLySiFHSD6kEBWs", 28 | SAMO_SOL = "D6N9j8F2DhtzDtrdpT74y3u2YmYAzcggiLc3nTjqux9M", 29 | LIQ_USDC = "3PD9SZFwXKkXr4akLf4ofo37ZUMycwML89R2P3qxcbZG", 30 | SNY_USDC = "AZpo4BJHHRetF96v6SGinFZBMXM4yWMo4RA8C4PriDLk", 31 | mSOL_USDC = "8PSfyiTVwPb6Rr2iZ8F3kNpbg65BCfJM9v8LfB916r44", 32 | SLRS_USDC = "AtB4nUmdyQfuWWJ9xAHw9xyVnJFfSjSuVWkiYan8y86w", 33 | PORT_USDC = "F8gPSpwVHj8FdAJAYULDuZBxFEJut87hUbARYYx3471w", 34 | SBR_USDC = "CS7fA5n4c2D82dUoHrYzS3gAqgqaoVSfgsr18kitp2xo", 35 | scnSOL_USDC = "Dkr8B675PGnNwEr9vTKXznjjHke5454EQdz3iaSbparB", 36 | pSOL_USDC = "C2YzN6MymD5HM2kPaH7bzcbqciyjfmpqyVaR3KA5V6z1", 37 | mSOL_SOL = "29cdoMgu6MS2VXpcMo1sqRdWEzdUR9tjvoh8fcK8Z87R", 38 | ORCA_PAI = "C7TH2jEJJaxVwwuvkbcDGfHUiZvEkkeYjyAcdTMi5ujb", 39 | ORCA_mSOL = "CVapmQn7HaU1yMDW3q6oUV4hx6XoYv54T4zfGXkuJqkA", 40 | scnSOL_SOL = "APNpzQvR91v1THbsAyG3HHrUEwvexWYeNCFLQuVnxgMc", 41 | ATLAS_USDC = "FZ8x1LCRSPDeHBDoAc3Gc6Y7ETCynuHEr5q5YWV7uRCJ", 42 | POLIS_USDC = "GteBdo9sqE7T41G8AJsaG9WHW48uXBwsLLznmu2TBdgy", 43 | BOP_USDC = "2gXDJZ7XAtQEtf4PRSQZKoq1WMuu1H44tQanbMA3YVpu", 44 | SAMO_USDC = "6VK1ksrmYGMBWUUZfygGF8tHRGpNxQEWv8pfvzQHdyyc", 45 | NINJA_SOL = "4X1oYoFWYtLebk51zuh889r1WFLe8Z9qWApj87hQMfML", 46 | SLIM_USDC = "BVWwyiHVHZQMPHsiW7dZH7bnBVKmbxdeEjWqVRciHCyo", 47 | wHAPI_USDC = "ELfBngAgvLEHVBuJQhhE7AW6eqLX7id2sfrBngVNVAUW", 48 | COPE_USDC = "HsauTv9s52Zv12eaDuSp6y7BEm4e4BHEyAsbdjyyWzPK", 49 | SUNNY_USDC = "GHuoeq9UnFBsBhMwH43eL3RWX5XVXbSRYJymmyMYpT7n", 50 | GRAPE_USDC = "EorFh8siFyLF1QTZ7cCXQaPGqyo7eb4SAgKtRH8Jcxjd", 51 | ABR_USDC = "GMzPbaCuQmeMUm1opH3oSCgKUjVgJUW14myq99RVPGX5", 52 | KURO_USDC = "DRknxb4ZFxXUTG6UJ5HupNHG1SmvBSCPzsZ1o9gAhyBi", 53 | MEDIA_USDC = "2toFgkQDoPrTJYGDEVoCasPXuL9uQnjvXJaDwa9LHyTx", 54 | TULIP_USDC = "4SBx8GXu8HhcVHWydQv1vsDdZs3G93XSL9CtMBny6hS5", 55 | MNGO_USDC = "H9yC7jDng974WwcU4kTGs7BKf7nBNswpdsP5bzbdXjib", 56 | stSOL_wstETH = "Eswigpwm3xsipkTqahGi2PEJsJcULQBwZgxhQpr6yBEa", 57 | SYP_USDC = "qJxKN9BhxbYvRNbjfK2uAVWboto6sonj8XC1ZEW5XTB", 58 | stSOL_wLDO = "74B9aMS7SA832xKngt5VLKmWAP3pa3qkUzWncTmQSsGF", 59 | whETH_SOL = "7aYnrdmdCRodDy2Czn6keUquUhjF1jPEmfwZPh488z8U", 60 | whETH_USDC = "7NPtjjAP7vhp4t5NCLyY4DY5rurvyc8cgZ2a2rYabRia", 61 | MNDE_mSOL = "5PHS5w6hQwFNnLz1jJFe7TVTxSQ98cDYC3akmiAoFMXs", 62 | WAG_USDC = "Df6XNHMF3uRVZnz7LCEGiZVax6rXgz76owtVkBHEjSb6", 63 | mSOL_USDT = "9cMWe4UYRPGAUUsTkjShJWVM7bk8DUBgxtwwH8asFJoV", 64 | mSOL_whETH = "5qoTq3qC4U7vFxo3iCzbXcaD1UEmDeCD63Dsuoct71oV", 65 | BTC_mSOL = "8nKJ4z9FSw6wrVZKASqBiS9DS1CiNsRnqwCCKVQjqdkB", 66 | IVN_SOL = "DfgCnzaiTXfPkAH1C1Z441b5MzjjTCEh134ioxqRZxYf", 67 | LARIX_USDC = "8sfThep3io4gvcGeuoAg1Rs8GDwKJjtcdAFHqQSSNAVE", 68 | PRT_USDC = "6jCERp5hKj37PCXP3VTjCDJeoPuSpnMDMz5A6jWQv3yS", 69 | JET_USDC = "GBijunwxa4Ni3JmYC6q6zgaVhSUJU6hVX5qTyJDRpNTc", 70 | stSOL_USDC = "GtQ1NT7R5aaTiST7K6ZWdMhwDdFxsSFvVFhBo8vyHGAq", 71 | wstETH_USDC = "5a6Y1ephcbKSoyLMQyD1JWbtqawCy8p2FtRL9v3zhaG5", 72 | AURY_USDC = "6mJqqT5TMgveDvxzBt3hrjGkPV5VAj7tacxFCT3GebXh", 73 | AVAX_USDC = "Hmfrtmo93DpSDmVNLQKcBS5D1ia5JatiRSok9ososubz", 74 | FTT_USDC = "FwCombynV2fTVizxPCNA2oZKoWXLZgdJThjE4Xv9sjxc", 75 | RAY_USDC = "4cXw2MYj94TFBXLL73fEpMCr8DPrW68JvrV8mzWgktbD", 76 | SLND_USDC = "F59gkD7NnsdJbFKrRZsiBC8PAooN4c56T8QmahfW1iXN", 77 | GOFX_USDC = "7vnps4VE5RTGAr5fmPZu7fSrk2VnM4Up838grZfqmxqE", 78 | WOOF_USDC = "9EjcYfHcG8f1mccpHyaAwpoxaUPiheC6KgLQjyD9aTb6", 79 | SDOGE_USDC = "CHTKUJGYRtBDqnxCFjxe5KEkZgxV98udbhuYYyzGxup5", 80 | CATO_USDC = "55r9txzQtmjTykmTXmBYZCVMg5z9squB8b5cSw2AhxA4", 81 | OOGI_USDC = "DSiHyHDn96bUQSZtizyCRLcQzrwohZeMpVu8rYJN1HzG", 82 | SONAR_USDC = "5MvQHx8eftU39JTucFsT315JFnQASuDQg3FqxTw7xcvN", 83 | APT_USDC = "HNrYngS1eoqkjWro9D3Y5Z9sWBDzPNK2tX4rfV2Up177", 84 | DFL_USDC = "AWrtTWG4Zgxw8D92bb3L3sQtGLD3zDztMPWsXSph8iBP", 85 | DFL_SOL = "9Y1vPaAsMz8X65DebMMnmBjbMo8i4jh4mcgiggZUUS3M", 86 | FRKT_USDC = "FnDxJPNk7pPmGHUbR4XUHmHevrkXHdna5D3sQKcAtjBL", 87 | TTT_USDC = "FGgP1npQTsC5Q4xBmQtNYSh51NKqNwdxBZy8JCo3igcu", 88 | UPS_USDC = "E1U63VXhNiWoUkVvjrfLDdV1oJrwE6zLde3bohr6jCqz", 89 | FANT_USDC = "GjG7JjTQfQpDxw4hWx4etP9oTaYCuCbPjsU8WaUT3xHB", 90 | BLOCK_USDC = "D8WjqtwC9CzBrQKfSf2ccCHFQuPYwyLv5KAy8WjT5vnf", 91 | RUN_USDC = "34Ppq6R8NfYBwWwPY4cBK4Afyb8hHaASQFukCzH6cV4n", 92 | UXP_USDC = "HjR8JgqNKQVMvdryqJw5RJ4PCE9WGk8sgbEF7S9S3obv", 93 | BTC_USDC = "J3kvcay3N16FBdawgnqoJ9v9p6XCvyCLE2Z9F5RLvGkj", 94 | MNDE_USDC = "12Uj74zgUUoBe4yeackwQ4qYtFMr9fk1xL6q5Nha6t2N", 95 | CHICKS_USDC = "71CBZeJ4tw38L9pSPoCz4fRsuWE64Fipyzotte7haoCS", 96 | ONESOL_USDC = "6MF5CHWAj5mS7FhpxiKz37CzR2eYTu236XpBKKMXCrGg", 97 | WMP_USDC = "HDgxKmiA8Pv82fNguhVeMkZqQkos2YksFPoP1KttWxX8", 98 | UNQ_USDC = "2VuGzaMrDnDyZfYvDwSXk38s7M2wpud7LDY3dGA1J9sy", 99 | BASIS_USDC = "GoaAiajubRgeCFEz9L6mLnSmT2QFegoJDH5tpLfivpj", 100 | GST_USDC = "E6FUnQHGHJVJg7oExVr5Moeaj1QpdpZQF5odYjHXWPZb", 101 | MEAN_USDC = "F5BTnwuMA6rxftTdbZ33VWKr2wrr6DuQHnd4guKmPSYQ", 102 | AART_USDC = "HCtyJzFUtYecXrA52s4Y9atq4J1fhT3cYsTX17XVSFag", 103 | SHDW_USDC = "DJqqvzSuPaWThfzwMjXx7H2ZmHDdwxza6NtFudtuXcpc", 104 | SHDW_SOL = "2ws7g3LBPdctfKn42Di9qxzQtUJ8ZL1aEAX2rGEQMNqh", 105 | SCY_USDC = "99ZHUQsgxL7K6PHrGNi1gSwawwPr7UA5fbWrYoHQ6qhX", 106 | SLC_USDC = "E5kSBqTDxFLbLNQaVVtPtnhEYVLMCK2fVSEKoMKL98qR", 107 | wUST_SOL = "6c13xsmyk7UaHUWZ2rm1MM3ZdrQRSBkQ9waaG25ridVs", 108 | wUST_USDC = "J1KfRtP5y2warpD7LdJhfBLPKoWwSqYuovdArSv1mpQ7", 109 | mSOL_wUST = "68YVjgPnTUPcBqZyghqvD2WPNsrLKsjYTmBKJzHRr4qd", 110 | wLUNA_wUST = "8Mh7drLbt3jFJYwp948XyvQscGLaLkChNcaH5wwaAoWA", 111 | stSOL_wUST = "HTZd53fYwYQRyAjiaPsZy9Gf41gobFdqkF4oKe3XLi95", 112 | JSOL_USDC = "AzEoVuNJyo9ByoLRZ5t6vav2Zg24vULNVJM41PgCKUqR", 113 | daoSOL_USDC = "CCyDxjdW3G7hPTthTMPTZ4bnhFF19XG6rx2fNiKeRQww", 114 | ORCA_USDT = "Gx4PoxenyQwhGGnKagAT35iVg4im1iKhJxDWqVhgu6tk", 115 | ORCA_whETH = "GsfyYHkSgC3Ta6aWR9MjB2sxoBrkGGeR2tAwXbpphf3", 116 | GENE_USDC = "7cuu94swKL5PtFQohKMAzyd1mjj65rgMW3GzLY31HCnK", 117 | CMFI_USDC = "85krvT9DxdYgoFLQDHTAGdvtNuLdAsc4xE5FkVLpN2aR", 118 | CELO_USDC = "HVLyX8mD8YvKgZJ4oB6rXJiCYMLpHKwB6iCiCjE1XwdT", 119 | FTM_USDC = "Gpzd833qSmv3kXpQmxEaqkrZTXZaRjhNAoqhf61qAhTG", 120 | BTC_ORCA = "DFpLFcQZqDKykyDePgip4r6MExVmBKWqTa12ezq6qxUY", 121 | HBB_USDC = "cL5WhffCYFRLM4We8VS2W684kM4pHyuvEDwp8Ddw48k", 122 | HBB_SOL = "FkKzu2HeMJZf4oHwoYPxLGVy3net5Jq8HAfnA5VqETgk", 123 | SB_USDC = "2Reqt4Sw9xNY8BoJ3EZLpFu5yVgNxFrbw8M3KiJpPn6o", 124 | stSOL_USDT = "4ni1nho89cDKAQ9ddbNQA9ieLYpzvJVmJpuogu5Ct5ur", 125 | SEEDED_USDC = "H7gyTmNCDXkD8MGMqnxqoD8ANszjcju4tjT6ERZ5dakf", 126 | AUDIO_USDC = "3hksYA17VxgiKSeihjnZkBbjc2CTbEBfvDCYgQhojTo5", 127 | MMA_USDC = "AaZRnJAnDyJyPD9uPJpJ8bzBGDCEi6jtBpUf92xErWPp", 128 | ONESOL_SOL = "9wPhuYapychVDSxmXqCZxy2Ka8Lmav4SHM72si8bfraV", 129 | PUFF_SOL = "Eho8h1BcoG5QWU7X9FzJafw5ErKUXtR2LobAJJZfWff4", 130 | SAO_USDC = "4iyU77yZbg8iD344vbwruAuDAf9i1EVV3FhZJDnWStBE", 131 | sRLYv2_SOL = "3dXdXg5HPyZ73GFC9LkSn3thdJUGeXWB8iSTHs5UcqiH", 132 | ZBC_USDC = "2LYgm6nGXmSSjfoEriPuYeGoNiWNxUs7n3rnTbDWN5c7", 133 | GMT_USDC = "CFxQF5kNAtbbDj298Xr47Sf4mkSyuzWpRH97hrdQ6kxi", 134 | NOVA_USDC = "DdAFNvDxtEHCgKj3JAM64zCKfMWhs4J9wEmRrjUAFiME", 135 | HBB_USDH = "7n2YW9qLkhGFArdZPLoF4hYPE2zw7xCACkVPXrUWnLuo", 136 | TAKI_sRLYv2 = "6atKbS2Xz5vu7cqWBNk8KYkuakRzckZ9nvtUKf2k8Sc3", 137 | ZIG_USDC = "5vhh9ZnD9vnahRhFLP1EUEyYRSzvJwgw9U2xygsSJSrp", 138 | sRLY_SOL = "HfRgvhgscGX5GaP3rUrZAhh7gS4aJ2UQ7rNVX976rG6P", 139 | TAKI_sRLY = "3xaK5aWWLNRB73xUVX3cusLhDp65mTvP4fwW5Jwxakgs", 140 | stSOL_SOL = "4jjQSgFx33DUb1a7pgPsi3FbtZXDQ94b6QywjNK3NtZw", 141 | BTC_stSOL = "HYp9v7cY4wAxSsa6ijztQQ3GQ8iTttuG5vu8JNBDHoNh", 142 | stSOL_whETH = "FWurFWADrgmhb6Y44LEaCMnEHS2Tu3QGqd9oBcZtr8gT", 143 | } 144 | -------------------------------------------------------------------------------- /src/public/pools/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./config"; 2 | export * from "./types"; 3 | -------------------------------------------------------------------------------- /src/public/pools/types.ts: -------------------------------------------------------------------------------- 1 | import { u64 } from "@solana/spl-token"; 2 | import { Keypair, PublicKey } from "@solana/web3.js"; 3 | import Decimal from "decimal.js"; 4 | import { OrcaU64 } from ".."; 5 | import { TransactionPayload } from "../utils"; 6 | 7 | export type DepositQuote = { 8 | minPoolTokenAmountOut: OrcaU64; // MISNOMER - this value represents the exact poolTokenAmountOut 9 | maxTokenAIn: OrcaU64; 10 | maxTokenBIn: OrcaU64; 11 | }; 12 | 13 | export type WithdrawQuote = { 14 | minTokenAOut: OrcaU64; 15 | minTokenBOut: OrcaU64; 16 | maxPoolTokenAmountIn: OrcaU64; // MISNOMER - this value represents the exact poolTokenAmountIn 17 | }; 18 | 19 | /** 20 | * Allows interactions with an Orca liquidity pool. 21 | */ 22 | export type OrcaPool = { 23 | /** 24 | * Query the token of tokenA in this pool. 25 | * @returns Returns the token id of tokenA in this pool 26 | */ 27 | getTokenA: () => OrcaPoolToken; 28 | 29 | /** 30 | * Query the token of tokenB in this pool. 31 | * @returns Returns the token id of tokenB in this pool 32 | */ 33 | getTokenB: () => OrcaPoolToken; 34 | 35 | /** 36 | * Query the mint public key for the pool token of this pool. 37 | * @returns Returns the tokenMint public key of this pool 38 | */ 39 | getPoolTokenMint: () => PublicKey; 40 | 41 | /** 42 | * Query the balance for an user address 43 | * @param wallet The public key for the user. 44 | * @return Returns the amount of LP token the user owns for this pool. 45 | */ 46 | getLPBalance: (owner: PublicKey) => Promise; 47 | 48 | /** 49 | * Query the supply of LP tokens for this pool. 50 | * @return Returns the supply of LP tokens for this pool 51 | */ 52 | getLPSupply: () => Promise; 53 | 54 | /** 55 | * Get the latest quote to trade one token to another in this pool 56 | * 57 | * Note: slippage supports a maximum scale of 1 (ex. 0.1%). Additional decimal places will be floored. 58 | * 59 | * @param inputTokenId The token you want to trade from 60 | * @param inputAmount The amount of token you would to trade 61 | * @param slippage An optional slippage in percentage you are willing to take in this trade (default: 0.1%) 62 | * @return Returns a quote on the exchanged token based on the input token amount 63 | */ 64 | getQuote: ( 65 | inputToken: OrcaToken, 66 | inputAmount: Decimal | OrcaU64, 67 | slippage?: Decimal 68 | ) => Promise; 69 | 70 | /** 71 | * Get the latest quote to trade on token to another in this pool using user provided pool amounts 72 | * 73 | * Note: slippage supports a maximum scale of 1 (ex. 0.1%). Additional decimal places will be floored. 74 | * 75 | * @param inputTokenId The token you want to trade from 76 | * @param inputAmount The amount of token you would to trade 77 | * @param inputTokenPoolAmount The amount of input tokens in the pool 78 | * @param outputTokenPoolAmount The amount of output tokens in the pool 79 | * @param slippage An optional slippage in percentage you are willing to take in this trade (default: 0.1%) 80 | * @return Returns a quote on the exchanged token based on the input token amount 81 | */ 82 | getQuoteWithPoolAmounts: ( 83 | inputToken: OrcaToken, 84 | inputAmount: Decimal | OrcaU64, 85 | inputTokenPoolAmount: u64, 86 | outputTokenPoolAmount: u64, 87 | slippage?: Decimal 88 | ) => Promise; 89 | 90 | /** 91 | * Perform a swap from the input type to the other token in the pool. 92 | * Fee for the transaction will be paid by the owner's wallet. 93 | * 94 | * NOTE: 95 | * 1. Associated Token Address initialization instructions will be appended if the ATA of the specified token does not exist in the user's wallet 96 | * 2. OrcaU64 must have the same scale as the corresponding token scale value 97 | * 98 | * @param owner The keypair for the user's wallet or just the user's public key 99 | * @param inputToken An Orca supported token in the user's wallet to swap from 100 | * @param amountIn The amount of inputToken to swap from 101 | * @param minimumAmountOut The minimum amount of outputToken to receive from this swap 102 | * @return The transaction signature of the swap instruction 103 | */ 104 | swap: ( 105 | owner: Keypair | PublicKey, 106 | inputToken: OrcaToken, 107 | amountIn: Decimal | OrcaU64, 108 | minimumAmountOut: Decimal | OrcaU64 109 | ) => Promise; 110 | 111 | /** 112 | * Get suggested pool token deposit amount based on required constraints on maximum tokenA amount and maximum tokenB amount 113 | * 114 | * Note: 115 | * 1. minPoolTokenAmountOut in the output type is a misnomer, and it represents the _exact_ poolTokenAmountOut value 116 | * 117 | * @param maxTokenAIn The maximum amount of tokenA to deposit in exchange for pool token 118 | * @param maxTokenBIn The maximum amount of tokenB to deposit in exchange for pool token 119 | * @param slippage An optional slippage in percentage you are willing to take in deposit (default: 0.1%) 120 | * @return Returns the input for deposit 121 | */ 122 | getDepositQuote: ( 123 | maxTokenAIn: Decimal | OrcaU64, 124 | maxTokenBIn: Decimal | OrcaU64, 125 | slippage?: Decimal 126 | ) => Promise; 127 | 128 | /** 129 | * Perform a deposit: send tokenA and tokenB, and receive a poolToken in return. 130 | * Fee for the transaction will be paid by the owner's wallet. 131 | * 132 | * NOTE: 133 | * 1. Associated Token Address initialization instructions will be appended if the ATA of the specified token does not exist in the user's wallet 134 | * 2. OrcaU64 must have the same scale as the corresponding token scale value 135 | * 136 | * @param owner The keypair for the user's wallet or just the user's public key 137 | * @param maxTokenAIn The maximum amount of tokenA to send 138 | * @param maxTokenBIn The maximum amount of tokenB to send 139 | * @param minPoolTokenAmountOut The amount of poolToken to receive 140 | * @return The transaction signature of the deposit instruction 141 | */ 142 | deposit: ( 143 | owner: Keypair | PublicKey, 144 | maxTokenAIn: Decimal | OrcaU64, 145 | maxTokenBIn: Decimal | OrcaU64, 146 | minPoolTokenAmountOut: Decimal | OrcaU64 147 | ) => Promise; 148 | 149 | /** 150 | * Get suggested withdraw token amounts based on required withdraw amount of the pool token / one of the paired tokens 151 | * 152 | * Throws error if withdrawTokenMint does not equal tokenMint of tokenA, tokenB, or poolToken of this pool 153 | * 154 | * Note: 155 | * 1. maxPoolTokenAmountIn in the output type is a misnomer, and it represents the _exact_ poolTokenAmountIn value 156 | * 157 | * @param withdrawTokenAmount The amount of tokens to withdraw in terms of tokenA amount, tokenB amount, or poolToken amount 158 | * @param withdrawTokenMint The token mint public key of tied to withdrawTokenAmount. It should be the mint of tokenA, tokenB, or poolToken 159 | * @param slippage An optional slippage in percentage you are willing to take in withdraw (default: 0.1%) 160 | * @return Returns the input for withdraw 161 | */ 162 | getWithdrawQuote: ( 163 | withdrawTokenAmount: Decimal | OrcaU64, 164 | withdrawTokenMint: PublicKey, 165 | slippage?: Decimal 166 | ) => Promise; 167 | 168 | /** 169 | * Perform a withdraw: send poolToken, and receive tokenA and tokenB in return. 170 | * Fee for the transaction will be paid by the owner's wallet. 171 | * 172 | * NOTE: 173 | * 1. Associated Token Address initialization instructions will be appended if the ATA of the specified token does not exist in the user's wallet 174 | * 2. OrcaU64 must have the same scale as the corresponding token scale value 175 | * 176 | * @param owner The keypair for the user's wallet or just the user's public key 177 | * @param poolTokenAmountIn The amount of poolToken to send 178 | * @param minTokenAOut The minimum amount of tokenA to receive 179 | * @param minTokenBOut The minimum amount of tokenB to receive 180 | * @return The transaction signature of the withdraw instruction 181 | */ 182 | withdraw: ( 183 | owner: Keypair | PublicKey, 184 | poolTokenAmountIn: Decimal | OrcaU64, 185 | minTokenAOut: Decimal | OrcaU64, 186 | minTokenBOut: Decimal | OrcaU64 187 | ) => Promise; 188 | }; 189 | 190 | /** 191 | * An Orca Token 192 | * @param tag The tag of the token 193 | * @param name The presentable name of the token 194 | * @param mint The mint public key for the token 195 | * @param scale The scale of the u64 return type 196 | */ 197 | export type OrcaToken = { 198 | tag: string; 199 | name: string; 200 | mint: PublicKey; 201 | scale: number; 202 | }; 203 | 204 | /** 205 | * An Orca Token within an OrcaPool 206 | * @param addr The public key for this token for this Orca Pool 207 | */ 208 | export type OrcaPoolToken = OrcaToken & { 209 | addr: PublicKey; 210 | }; 211 | 212 | export type Quote = { 213 | /** 214 | * Returns the rate of exchange given the trade amount. Fees are included. 215 | * Rate is zero if the input trade amount, input or output token balance in pool is zero. 216 | * @returns a function that returns the rate of exchange when the quote was built (denominated by output token) 217 | */ 218 | getRate: () => Decimal; 219 | 220 | /** 221 | * Returns the fee that will be charged in this exchange. 222 | * @return a function that returns the fee (denominated by input token) that will be charged in this exchange. 223 | */ 224 | getLPFees: () => OrcaU64; 225 | 226 | /** 227 | * Return the network fee that will be charged to submit the transaction. 228 | * @return a function that returns the network fee in lamports that will be charged to submit the transaction. 229 | */ 230 | getNetworkFees: () => OrcaU64; 231 | 232 | /** 233 | * Returns the % impact to the rate if this transaction goes through. 234 | * @return a function to return the % impact to the rate if this transaction goes through. Zero if input or output token balance in pool is zero. 235 | */ 236 | getPriceImpact: () => Decimal; 237 | 238 | /** 239 | * Returns the expected amount of output tokens returned if this exchange is transacted. Fees applied. 240 | * @return a function to return the expected amount of output tokens returned if this exchange is transacted 241 | */ 242 | getExpectedOutputAmount: () => OrcaU64; 243 | 244 | /** 245 | * Returns the minimum amount of output tokens returned if this exchange is transacted. Fees & maximum slippage applied. 246 | * @return a function to return the minimum amount of output tokens returned if this exchange is transacted 247 | */ 248 | getMinOutputAmount: () => OrcaU64; 249 | }; 250 | -------------------------------------------------------------------------------- /src/public/utils/constants.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey } from "@solana/web3.js"; 2 | 3 | export const ORCA_TOKEN_SWAP_ID: PublicKey = new PublicKey( 4 | "9W959DqEETiGZocYWCQPaJ6sBmUzgfxXfqGeTEdp3aQP" 5 | ); 6 | 7 | export const ORCA_TOKEN_SWAP_ID_DEVNET: PublicKey = new PublicKey( 8 | "3xQ8SWv2GaFXXpHZNqkXsdxq5DZciHBz6ZFoPPfbFd7U" 9 | ); 10 | 11 | export const SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID: PublicKey = new PublicKey( 12 | "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" 13 | ); 14 | 15 | export const ORCA_FARM_ID: PublicKey = new PublicKey( 16 | "82yxjeMsvaURa4MbZZ7WZZHfobirZYkH1zF8fmeGtyaQ" 17 | ); 18 | -------------------------------------------------------------------------------- /src/public/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./constants"; 2 | export * from "./models"; 3 | export * from "./numbers"; 4 | export * from "./pool-utils"; 5 | export * from "./time-utils"; 6 | export * from "./web3"; 7 | export * from "./types"; 8 | -------------------------------------------------------------------------------- /src/public/utils/models/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./instruction"; 2 | export * from "./percentage"; 3 | -------------------------------------------------------------------------------- /src/public/utils/models/instruction.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Keypair, 3 | PublicKey, 4 | Signer, 5 | Transaction, 6 | TransactionInstruction, 7 | TransactionSignature, 8 | } from "@solana/web3.js"; 9 | 10 | export const emptyInstruction: Instruction = { 11 | instructions: [], 12 | cleanupInstructions: [], 13 | signers: [], 14 | }; 15 | 16 | export type Instruction = { 17 | instructions: TransactionInstruction[]; 18 | cleanupInstructions: TransactionInstruction[]; 19 | signers: Signer[]; 20 | }; 21 | 22 | export type TransactionPayload = { 23 | transaction: Transaction; 24 | signers: Signer[]; 25 | execute: () => Promise; 26 | }; 27 | -------------------------------------------------------------------------------- /src/public/utils/models/percentage.ts: -------------------------------------------------------------------------------- 1 | import { u64 } from "@solana/spl-token"; 2 | import Decimal from "decimal.js"; 3 | import { ZERO } from ".."; 4 | 5 | export class Percentage { 6 | readonly numerator: u64; 7 | readonly denominator: u64; 8 | 9 | constructor(numerator: u64, denominator: u64) { 10 | this.numerator = numerator; 11 | this.denominator = denominator; 12 | } 13 | 14 | public static fromDecimal(number: Decimal): Percentage { 15 | return Percentage.fromFraction(number.toDecimalPlaces(1).mul(10).toNumber(), 1000); 16 | } 17 | 18 | public static fromFraction(numerator: u64 | number, denominator: u64 | number): Percentage { 19 | const num = typeof numerator === "number" ? new u64(numerator.toString()) : numerator; 20 | const denom = typeof denominator === "number" ? new u64(denominator.toString()) : denominator; 21 | return new Percentage(num, denom); 22 | } 23 | 24 | public toString = (): string => { 25 | return `${this.numerator.toString()}/${this.denominator.toString()}`; 26 | }; 27 | 28 | public toDecimal() { 29 | if (this.denominator.eq(ZERO)) { 30 | return new Decimal(0); 31 | } 32 | return new Decimal(this.numerator.toString()).div(new Decimal(this.denominator.toString())); 33 | } 34 | 35 | public add(p2: Percentage): Percentage { 36 | const denomGcd = this.denominator.gcd(p2.denominator); 37 | const denomLcm = this.denominator.div(denomGcd).mul(p2.denominator); 38 | 39 | const p1DenomAdjustment = denomLcm.div(this.denominator); 40 | const p2DenomAdjustment = denomLcm.div(p2.denominator); 41 | 42 | const p1NumeratorAdjusted = this.numerator.mul(p1DenomAdjustment); 43 | const p2NumeratorAdjusted = p2.numerator.mul(p2DenomAdjustment); 44 | 45 | const newNumerator = p1NumeratorAdjusted.add(p2NumeratorAdjusted); 46 | 47 | return new Percentage(new u64(newNumerator.toString()), new u64(denomLcm.toString())); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/public/utils/numbers/decimal-utils.ts: -------------------------------------------------------------------------------- 1 | import { u64 } from "@solana/spl-token"; 2 | import Decimal from "decimal.js"; 3 | 4 | export class DecimalUtil { 5 | public static fromU64(input: u64, shift = 0): Decimal { 6 | return new Decimal(input.toString()).div(new Decimal(10).pow(shift)); 7 | } 8 | 9 | public static toU64(input: Decimal, shift = 0): u64 { 10 | if (input.isNeg()) { 11 | throw new Error("Negative decimal value ${input} cannot be converted to u64."); 12 | } 13 | 14 | const shiftedValue = input.mul(new Decimal(10).pow(shift)); 15 | const zeroDecimalValue = shiftedValue.trunc(); 16 | return new u64(zeroDecimalValue.toString()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/public/utils/numbers/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./decimal-utils"; 2 | export * from "./orca-u64"; 3 | export * from "./u64-utils"; 4 | -------------------------------------------------------------------------------- /src/public/utils/numbers/orca-u64.ts: -------------------------------------------------------------------------------- 1 | import { u64 } from "@solana/spl-token"; 2 | import Decimal from "decimal.js"; 3 | import { DecimalUtil } from "../../utils/numbers/decimal-utils"; 4 | 5 | /** 6 | * Orca's U64 wrapper class to help users convert to/from regular javascript number types 7 | * 8 | * 9 | * Examples: 10 | * OrcaU64(value: 99999, decimal: 0) -> 99999 11 | * OrcaU64(value: 99999, decimal: 5) -> 0.99999 12 | */ 13 | export class OrcaU64 { 14 | readonly value: u64; 15 | readonly scale: number; 16 | 17 | constructor(value: u64, scale = 0) { 18 | this.value = value; 19 | this.scale = Math.floor(scale); 20 | } 21 | 22 | /** 23 | * Create an OrcaU64 from a Decimal 24 | * @param value - an object representing the value of the u64 in Decimal form 25 | * @param scale - the number of digits after the decimal point to keep account for in this u64 26 | * @returns OrcaU64 hosting a u64 representing the input value adjusted to the provided scale 27 | */ 28 | static fromDecimal(value: Decimal, scale = 0) { 29 | const dec = Math.floor(scale); 30 | return new OrcaU64(DecimalUtil.toU64(value, dec), dec); 31 | } 32 | 33 | /** 34 | * Create an OrcaU64 from a number 35 | * @param value - an object representing the value of the u64 in number form 36 | * @param scale - the number of digits after the decimal point to keep account for in this u64 37 | * @returns OrcaU64 hosting a u64 representing the input value adjusted to the provided scale 38 | */ 39 | static fromNumber(value: number, scale = 0) { 40 | const dec = Math.floor(scale); 41 | return new OrcaU64(DecimalUtil.toU64(new Decimal(value), dec), dec); 42 | } 43 | 44 | /** 45 | * Create an OrcaU64 from a u64 46 | * @param value - an object representing the value of the u64 47 | * @param scale - the number of digits after the decimal point represented in this u64 48 | * @returns OrcaU64 hosting the input u64 with the provided scale 49 | */ 50 | static fromU64(value: u64, scale = 0) { 51 | const dec = Math.floor(scale); 52 | return new OrcaU64(value, dec); 53 | } 54 | 55 | /** 56 | * Convert this OrcaU64 to Decimal. 57 | * @returns Decimal object that equals to the OrcaU64's value & scale 58 | */ 59 | public toDecimal() { 60 | return DecimalUtil.fromU64(this.value, this.scale); 61 | } 62 | 63 | /** 64 | * Convert this OrcaU64 to number. 65 | * @returns number that equals to the OrcaU64's value & scale 66 | */ 67 | public toNumber() { 68 | return DecimalUtil.fromU64(this.value, this.scale).toNumber(); 69 | } 70 | 71 | /** 72 | * Convert this OrcaU64 to u64. 73 | * @returns u64 that equals to the OrcaU64 value 74 | */ 75 | public toU64() { 76 | return new u64(this.value.toString()); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/public/utils/numbers/u64-utils.ts: -------------------------------------------------------------------------------- 1 | import { u64 } from "@solana/spl-token"; 2 | import Decimal from "decimal.js"; 3 | import { OrcaToken, OrcaU64 } from "../.."; 4 | import { OrcaFarmParams } from "../../../model/orca/farm/farm-types"; 5 | import { OrcaPoolParams } from "../../../model/orca/pool/pool-types"; 6 | import { DecimalUtil } from "./decimal-utils"; 7 | 8 | export const ZERO = new u64(0); 9 | export const ONE = new u64(1); 10 | 11 | export class U64Utils { 12 | public static toTokenU64(input: Decimal | OrcaU64, token: OrcaToken, varName: string) { 13 | if (input instanceof OrcaU64) { 14 | if (input.scale !== token.scale) { 15 | throw new Error( 16 | `${varName}'s scale of ${input.scale} does not match token's decimal of ${token.scale}` 17 | ); 18 | } 19 | return input.toU64(); 20 | } 21 | 22 | return DecimalUtil.toU64(input, token.scale); 23 | } 24 | 25 | public static toPoolU64(input: Decimal | OrcaU64, pool: OrcaPoolParams, varName: string) { 26 | if (input instanceof OrcaU64) { 27 | if (input.scale !== pool.poolTokenDecimals) { 28 | throw new Error( 29 | `${varName}'s scale of ${input.scale} does not match pool's decimal of ${pool.poolTokenDecimals}` 30 | ); 31 | } 32 | return input.toU64(); 33 | } 34 | 35 | return DecimalUtil.toU64(input, pool.poolTokenDecimals); 36 | } 37 | 38 | public static toFarmU64(input: Decimal | OrcaU64, farm: OrcaFarmParams, varName: string) { 39 | if (input instanceof OrcaU64) { 40 | if (input.scale !== farm.baseTokenDecimals) { 41 | throw new Error( 42 | `${varName}'s scale of ${input.scale} does not match baseToken's decimal of ${farm.baseTokenDecimals}` 43 | ); 44 | } 45 | return input.toU64(); 46 | } 47 | 48 | return DecimalUtil.toU64(input, farm.baseTokenDecimals); 49 | } 50 | 51 | // Note: divisor input variable modified in place 52 | // https://github.com/solana-labs/solana-program-library/blob/master/libraries/math/src/checked_ceil_div.rs#L5-L22 53 | public static ceilingDivision(dividend: u64, divisor: u64): [u64, u64] { 54 | let quotient = dividend.div(divisor); 55 | if (quotient.eq(ZERO)) { 56 | return [ZERO, divisor]; 57 | } 58 | 59 | let remainder = dividend.mod(divisor); 60 | if (remainder.gt(ZERO)) { 61 | quotient = quotient.add(ONE); 62 | divisor = dividend.div(quotient); 63 | remainder = dividend.mod(quotient); 64 | if (remainder.gt(ZERO)) { 65 | divisor = divisor.add(ONE); 66 | } 67 | } 68 | 69 | return [quotient, divisor]; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/public/utils/pool-utils.ts: -------------------------------------------------------------------------------- 1 | import { OrcaPoolParams } from "../../model/orca/pool/pool-types"; 2 | 3 | export function getTokens(poolParams: OrcaPoolParams, inputTokenId: string) { 4 | if (poolParams.tokens[inputTokenId] == undefined) { 5 | throw new Error("Input token not part of pool"); 6 | } 7 | 8 | const tokenAId = poolParams.tokenIds[0]; 9 | const tokenBId = poolParams.tokenIds[1]; 10 | 11 | const forward = tokenAId == inputTokenId; 12 | 13 | const inputOrcaToken = forward ? poolParams.tokens[tokenAId] : poolParams.tokens[tokenBId]; 14 | const outputOrcaToken = forward ? poolParams.tokens[tokenBId] : poolParams.tokens[tokenAId]; 15 | return { inputPoolToken: inputOrcaToken, outputPoolToken: outputOrcaToken }; 16 | } 17 | -------------------------------------------------------------------------------- /src/public/utils/time-utils.ts: -------------------------------------------------------------------------------- 1 | export function nowMS() { 2 | return new Date().getTime(); 3 | } 4 | -------------------------------------------------------------------------------- /src/public/utils/types.ts: -------------------------------------------------------------------------------- 1 | export enum Network { 2 | MAINNET = "mainnet-beta", 3 | DEVNET = "devnet", 4 | } 5 | -------------------------------------------------------------------------------- /src/public/utils/web3/ata-utils.ts: -------------------------------------------------------------------------------- 1 | import { AccountLayout, TOKEN_PROGRAM_ID, u64 } from "@solana/spl-token"; 2 | import { Connection, Keypair, PublicKey } from "@solana/web3.js"; 3 | import { solToken } from "../../../constants/tokens"; 4 | import { SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID } from "../constants"; 5 | import { emptyInstruction, Instruction } from "../models/instruction"; 6 | import { deserializeAccount } from "./deserialize-account"; 7 | import { 8 | createAssociatedTokenAccountInstruction, 9 | createWSOLAccountInstructions, 10 | } from "./instructions/token-instructions"; 11 | import { Owner } from "./key-utils"; 12 | 13 | export type ResolvedTokenAddressInstruction = { address: PublicKey } & Instruction; 14 | 15 | /** 16 | * IMPORTANT: wrappedSolAmountIn should only be used for input/source token that 17 | * could be SOL. This is because when SOL is the output, it is the end 18 | * destination, and thus does not need to be wrapped with an amount. 19 | * 20 | * @param connection Solana connection class 21 | * @param owner The keypair for the user's wallet or just the user's public key 22 | * @param tokenMint Token mint address 23 | * @param wrappedSolAmountIn Optional. Only use for input/source token that could be SOL 24 | * @returns 25 | */ 26 | export async function resolveOrCreateAssociatedTokenAddress( 27 | connection: Connection, 28 | owner: Owner, 29 | tokenMint: PublicKey, 30 | wrappedSolAmountIn = new u64(0) 31 | ): Promise { 32 | if (!tokenMint.equals(solToken.mint)) { 33 | const derivedAddress = await deriveAssociatedTokenAddress(owner.publicKey, tokenMint); 34 | 35 | // Check if current wallet has an ATA for this spl-token mint. If not, create one. 36 | let resolveAtaInstruction = emptyInstruction; 37 | await connection.getAccountInfo(derivedAddress).then((info) => { 38 | const tokenAccountInfo = deserializeAccount(info?.data); 39 | 40 | if (!tokenAccountInfo) { 41 | resolveAtaInstruction = createAssociatedTokenAccountInstruction( 42 | derivedAddress, 43 | owner.publicKey, 44 | owner.publicKey, 45 | tokenMint, 46 | owner 47 | ); 48 | } 49 | }); 50 | 51 | return { 52 | address: derivedAddress, 53 | instructions: resolveAtaInstruction.instructions, 54 | cleanupInstructions: resolveAtaInstruction.cleanupInstructions, 55 | signers: resolveAtaInstruction.signers, 56 | }; 57 | } else { 58 | // TODO: Is there a way to store this cleaner? 59 | const accountRentExempt = await connection.getMinimumBalanceForRentExemption( 60 | AccountLayout.span 61 | ); 62 | // Create a temp-account to transfer SOL in the form of WSOL 63 | return createWSOLAccountInstructions( 64 | owner.publicKey, 65 | solToken.mint, 66 | wrappedSolAmountIn, 67 | accountRentExempt 68 | ); 69 | } 70 | } 71 | 72 | export async function deriveAssociatedTokenAddress( 73 | walletAddress: PublicKey, 74 | tokenMint: PublicKey 75 | ): Promise { 76 | return ( 77 | await PublicKey.findProgramAddress( 78 | [walletAddress.toBuffer(), TOKEN_PROGRAM_ID.toBuffer(), tokenMint.toBuffer()], 79 | SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID 80 | ) 81 | )[0]; 82 | } 83 | -------------------------------------------------------------------------------- /src/public/utils/web3/deserialize-account.ts: -------------------------------------------------------------------------------- 1 | import { AccountInfo, AccountLayout, u64 } from "@solana/spl-token"; 2 | import { PublicKey } from "@solana/web3.js"; 3 | 4 | export const deserializeAccount = (data: Buffer | undefined): AccountInfo | undefined => { 5 | if (data == undefined || data.length == 0) { 6 | return undefined; 7 | } 8 | 9 | const accountInfo = AccountLayout.decode(data); 10 | accountInfo.mint = new PublicKey(accountInfo.mint); 11 | accountInfo.owner = new PublicKey(accountInfo.owner); 12 | accountInfo.amount = u64.fromBuffer(accountInfo.amount); 13 | 14 | if (accountInfo.delegateOption === 0) { 15 | accountInfo.delegate = null; 16 | accountInfo.delegatedAmount = new u64(0); 17 | } else { 18 | accountInfo.delegate = new PublicKey(accountInfo.delegate); 19 | accountInfo.delegatedAmount = u64.fromBuffer(accountInfo.delegatedAmount); 20 | } 21 | 22 | accountInfo.isInitialized = accountInfo.state !== 0; 23 | accountInfo.isFrozen = accountInfo.state === 2; 24 | 25 | if (accountInfo.isNativeOption === 1) { 26 | accountInfo.rentExemptReserve = u64.fromBuffer(accountInfo.isNative); 27 | accountInfo.isNative = true; 28 | } else { 29 | accountInfo.rentExemptReserve = null; 30 | accountInfo.isNative = false; 31 | } 32 | 33 | if (accountInfo.closeAuthorityOption === 0) { 34 | accountInfo.closeAuthority = null; 35 | } else { 36 | accountInfo.closeAuthority = new PublicKey(accountInfo.closeAuthority); 37 | } 38 | 39 | return accountInfo; 40 | }; 41 | -------------------------------------------------------------------------------- /src/public/utils/web3/get-token-count.ts: -------------------------------------------------------------------------------- 1 | import { u64 } from "@solana/spl-token"; 2 | import { Connection } from "@solana/web3.js"; 3 | import { OrcaPoolToken } from "../.."; 4 | import { OrcaPoolParams } from "../../../model/orca/pool/pool-types"; 5 | import { deserializeAccount } from "./deserialize-account"; 6 | 7 | export type PoolTokenCount = { 8 | inputTokenCount: u64; 9 | outputTokenCount: u64; 10 | }; 11 | 12 | export async function getTokenCount( 13 | connection: Connection, 14 | poolParams: OrcaPoolParams, 15 | inputPoolToken: OrcaPoolToken, 16 | outputPoolToken: OrcaPoolToken 17 | ): Promise { 18 | if (poolParams.tokens[inputPoolToken.mint.toString()] == undefined) { 19 | throw new Error("Input token not part of pool"); 20 | } 21 | 22 | if (poolParams.tokens[outputPoolToken.mint.toString()] == undefined) { 23 | throw new Error("Output token not part of pool"); 24 | } 25 | 26 | const accountInfos = await connection.getMultipleAccountsInfo([ 27 | inputPoolToken.addr, 28 | outputPoolToken.addr, 29 | ]); 30 | 31 | const tokens = accountInfos.map((info) => 32 | info != undefined ? deserializeAccount(info.data) : undefined 33 | ); 34 | const inputTokenAccount = tokens[0], 35 | outputTokenAccount = tokens[1]; 36 | 37 | if (inputTokenAccount === undefined || outputTokenAccount === undefined) { 38 | throw new Error("Unable to fetch accounts for specified tokens."); 39 | } 40 | 41 | return { 42 | inputTokenCount: new u64(inputTokenAccount.amount), 43 | outputTokenCount: new u64(outputTokenAccount.amount), 44 | }; 45 | } 46 | -------------------------------------------------------------------------------- /src/public/utils/web3/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./ata-utils"; 2 | export * from "./deserialize-account"; 3 | export * from "./get-token-count"; 4 | export * from "./transactions"; 5 | -------------------------------------------------------------------------------- /src/public/utils/web3/instructions/farm-instructions.ts: -------------------------------------------------------------------------------- 1 | import { Aquafarm } from "@orca-so/aquafarm"; 2 | import { u64 } from "@solana/spl-token"; 3 | import { PublicKey } from "@solana/web3.js"; 4 | import { Instruction, emptyInstruction } from "../.."; 5 | import { Owner } from "../key-utils"; 6 | 7 | export const createInitUserFarmInstruction = async ( 8 | farm: Aquafarm, 9 | userFarmPublicKey: PublicKey, 10 | owner: Owner 11 | ): Promise => { 12 | if (farm.isUserFarmInitialized()) { 13 | return emptyInstruction; 14 | } 15 | 16 | const initUserFarmIx = farm.constructInitUserFarmIx(owner.publicKey, userFarmPublicKey); 17 | 18 | return { 19 | instructions: [initUserFarmIx], 20 | cleanupInstructions: [], 21 | signers: owner.signer ? [owner.signer] : [], 22 | }; 23 | }; 24 | 25 | export const createFarmConvertTokensInstruction = async ( 26 | farm: Aquafarm, 27 | userTransferAuthorityPublicKey: PublicKey, 28 | userBaseTokenPublicKey: PublicKey, 29 | userFarmTokenPublicKey: PublicKey, 30 | userRewardTokenPublicKey: PublicKey, 31 | baseTokenAmount: u64, 32 | userFarmPublicKey: PublicKey, 33 | owner: Owner 34 | ): Promise => { 35 | let convertIx; 36 | if (!farm.userFarm) { 37 | convertIx = farm.constructConvertTokensIx( 38 | userTransferAuthorityPublicKey, 39 | userBaseTokenPublicKey, 40 | userFarmTokenPublicKey, 41 | userRewardTokenPublicKey, 42 | baseTokenAmount, 43 | userFarmPublicKey, 44 | owner.publicKey 45 | ); 46 | } else { 47 | convertIx = farm.constructConvertTokensIx( 48 | userTransferAuthorityPublicKey, 49 | userBaseTokenPublicKey, 50 | userFarmTokenPublicKey, 51 | userRewardTokenPublicKey, 52 | baseTokenAmount 53 | ); 54 | } 55 | 56 | if (!convertIx) { 57 | throw new Error("constructConvertTokensIx returned null"); 58 | } 59 | 60 | return { 61 | instructions: [convertIx], 62 | cleanupInstructions: [], 63 | signers: owner.signer ? [owner.signer] : [], 64 | }; 65 | }; 66 | 67 | export const createFarmRevertTokensInstruction = async ( 68 | farm: Aquafarm, 69 | userBurnAuthorityPublicKey: PublicKey, 70 | userBaseTokenPublicKey: PublicKey, 71 | userFarmTokenPublicKey: PublicKey, 72 | userRewardTokenPublicKey: PublicKey, 73 | baseTokenAmount: u64, 74 | owner: Owner 75 | ): Promise => { 76 | const revertIx = farm.constructRevertTokensIx( 77 | userBurnAuthorityPublicKey, 78 | userBaseTokenPublicKey, 79 | userFarmTokenPublicKey, 80 | userRewardTokenPublicKey, 81 | baseTokenAmount 82 | ); 83 | 84 | if (!revertIx) { 85 | throw new Error("constructRevertTokensIx returned null"); 86 | } 87 | 88 | return { 89 | instructions: [revertIx], 90 | cleanupInstructions: [], 91 | signers: owner.signer ? [owner.signer] : [], 92 | }; 93 | }; 94 | 95 | export const createFarmHarvestRewardInstruction = async ( 96 | farm: Aquafarm, 97 | userRewardTokenPublicKey: PublicKey, 98 | owner: Owner 99 | ): Promise => { 100 | const harvestIx = farm.constructHarvestIx(userRewardTokenPublicKey); 101 | 102 | return { 103 | instructions: [harvestIx], 104 | cleanupInstructions: [], 105 | signers: owner.signer ? [owner.signer] : [], 106 | }; 107 | }; 108 | -------------------------------------------------------------------------------- /src/public/utils/web3/instructions/pool-instructions.ts: -------------------------------------------------------------------------------- 1 | import { Token, TOKEN_PROGRAM_ID, u64 } from "@solana/spl-token"; 2 | import { TokenSwap } from "@solana/spl-token-swap"; 3 | import { Keypair, PublicKey } from "@solana/web3.js"; 4 | import { OrcaPoolParams } from "../../../../model/orca/pool/pool-types"; 5 | import { OrcaPoolToken } from "../../../pools"; 6 | import { Instruction } from "../../models"; 7 | import { Owner } from "../key-utils"; 8 | 9 | export const createApprovalInstruction = ( 10 | ownerAddress: PublicKey, 11 | approveAmount: u64, 12 | tokenUserAddress: PublicKey, 13 | userTransferAuthority?: Keypair 14 | ): { userTransferAuthority: Keypair } & Instruction => { 15 | userTransferAuthority = userTransferAuthority || new Keypair(); 16 | 17 | const approvalInstruction = Token.createApproveInstruction( 18 | TOKEN_PROGRAM_ID, 19 | tokenUserAddress, 20 | userTransferAuthority.publicKey, 21 | ownerAddress, 22 | [], 23 | approveAmount 24 | ); 25 | 26 | const revokeInstruction = Token.createRevokeInstruction( 27 | TOKEN_PROGRAM_ID, 28 | tokenUserAddress, 29 | ownerAddress, 30 | [] 31 | ); 32 | 33 | return { 34 | userTransferAuthority: userTransferAuthority, 35 | instructions: [approvalInstruction], 36 | cleanupInstructions: [revokeInstruction], 37 | signers: [userTransferAuthority], 38 | }; 39 | }; 40 | 41 | export const createSwapInstruction = async ( 42 | poolParams: OrcaPoolParams, 43 | owner: Owner, 44 | inputToken: OrcaPoolToken, 45 | inputTokenUserAddress: PublicKey, 46 | outputToken: OrcaPoolToken, 47 | outputTokenUserAddress: PublicKey, 48 | amountIn: u64, 49 | minimumAmountOut: u64, 50 | userTransferAuthority: PublicKey, 51 | orcaTokenSwapId: PublicKey 52 | ): Promise => { 53 | const amountInU64 = amountIn; 54 | const minimumAmountOutU64 = minimumAmountOut; 55 | 56 | const [authorityForPoolAddress] = await PublicKey.findProgramAddress( 57 | [poolParams.address.toBuffer()], 58 | orcaTokenSwapId 59 | ); 60 | 61 | const swapInstruction = TokenSwap.swapInstruction( 62 | poolParams.address, 63 | authorityForPoolAddress, 64 | userTransferAuthority, 65 | inputTokenUserAddress, 66 | inputToken.addr, 67 | outputToken.addr, 68 | outputTokenUserAddress, 69 | poolParams.poolTokenMint, 70 | poolParams.feeAccount, 71 | null, 72 | orcaTokenSwapId, 73 | TOKEN_PROGRAM_ID, 74 | amountInU64, 75 | minimumAmountOutU64 76 | ); 77 | 78 | return { 79 | instructions: [swapInstruction], 80 | cleanupInstructions: [], 81 | signers: owner.signer ? [owner.signer] : [], 82 | }; 83 | }; 84 | 85 | export const createDepositInstruction = async ( 86 | poolParams: OrcaPoolParams, 87 | userTransferAuthorityPublicKey: PublicKey, 88 | userTokenAPublicKey: PublicKey, 89 | userTokenBPublicKey: PublicKey, 90 | userPoolTokenPublicKey: PublicKey, 91 | poolTokenAmount: u64, 92 | maximumTokenA: u64, 93 | maximumTokenB: u64, 94 | tokenAPublicKey: PublicKey, 95 | tokenBPublicKey: PublicKey, 96 | orcaTokenSwapId: PublicKey, 97 | owner: Owner 98 | ): Promise => { 99 | const depositInstruction = TokenSwap.depositAllTokenTypesInstruction( 100 | poolParams.address, 101 | poolParams.authority, 102 | userTransferAuthorityPublicKey, 103 | userTokenAPublicKey, 104 | userTokenBPublicKey, 105 | tokenAPublicKey, 106 | tokenBPublicKey, 107 | poolParams.poolTokenMint, 108 | userPoolTokenPublicKey, 109 | orcaTokenSwapId, 110 | TOKEN_PROGRAM_ID, 111 | poolTokenAmount, 112 | maximumTokenA, 113 | maximumTokenB 114 | ); 115 | 116 | return { 117 | instructions: [depositInstruction], 118 | cleanupInstructions: [], 119 | signers: owner.signer ? [owner.signer] : [], 120 | }; 121 | }; 122 | 123 | export const createWithdrawInstruction = async ( 124 | poolParams: OrcaPoolParams, 125 | userTransferAuthorityPublicKey: PublicKey, 126 | userTokenAPublicKey: PublicKey, 127 | userTokenBPublicKey: PublicKey, 128 | userPoolTokenPublicKey: PublicKey, 129 | poolTokenAmount: u64, 130 | minimumTokenA: u64, 131 | minimumTokenB: u64, 132 | tokenAPublicKey: PublicKey, 133 | tokenBPublicKey: PublicKey, 134 | orcaTokenSwapId: PublicKey, 135 | owner: Owner 136 | ): Promise => { 137 | const withdrawInstruction = TokenSwap.withdrawAllTokenTypesInstruction( 138 | poolParams.address, 139 | poolParams.authority, 140 | userTransferAuthorityPublicKey, 141 | poolParams.poolTokenMint, 142 | poolParams.feeAccount, 143 | userPoolTokenPublicKey, 144 | tokenAPublicKey, 145 | tokenBPublicKey, 146 | userTokenAPublicKey, 147 | userTokenBPublicKey, 148 | orcaTokenSwapId, 149 | TOKEN_PROGRAM_ID, 150 | poolTokenAmount, 151 | minimumTokenA, 152 | minimumTokenB 153 | ); 154 | 155 | return { 156 | instructions: [withdrawInstruction], 157 | cleanupInstructions: [], 158 | signers: owner.signer ? [owner.signer] : [], 159 | }; 160 | }; 161 | -------------------------------------------------------------------------------- /src/public/utils/web3/instructions/token-instructions.ts: -------------------------------------------------------------------------------- 1 | import { AccountLayout, Token, TOKEN_PROGRAM_ID, u64 } from "@solana/spl-token"; 2 | import { 3 | Keypair, 4 | PublicKey, 5 | SystemProgram, 6 | SYSVAR_RENT_PUBKEY, 7 | TransactionInstruction, 8 | } from "@solana/web3.js"; 9 | import { Instruction, SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID } from "../.."; 10 | import { ResolvedTokenAddressInstruction } from "../ata-utils"; 11 | import { Owner } from "../key-utils"; 12 | 13 | export const createWSOLAccountInstructions = ( 14 | owner: PublicKey, 15 | solMint: PublicKey, 16 | amountIn: u64, 17 | rentExemptLamports: number 18 | ): ResolvedTokenAddressInstruction => { 19 | const tempAccount = new Keypair(); 20 | 21 | const createAccountInstruction = SystemProgram.createAccount({ 22 | fromPubkey: owner, 23 | newAccountPubkey: tempAccount.publicKey, 24 | lamports: amountIn.toNumber() + rentExemptLamports, 25 | space: AccountLayout.span, 26 | programId: TOKEN_PROGRAM_ID, 27 | }); 28 | 29 | const initAccountInstruction = Token.createInitAccountInstruction( 30 | TOKEN_PROGRAM_ID, 31 | solMint, 32 | tempAccount.publicKey, 33 | owner 34 | ); 35 | 36 | const closeWSOLAccountInstruction = Token.createCloseAccountInstruction( 37 | TOKEN_PROGRAM_ID, 38 | tempAccount.publicKey, 39 | owner, 40 | owner, 41 | [] 42 | ); 43 | 44 | return { 45 | address: tempAccount.publicKey, 46 | instructions: [createAccountInstruction, initAccountInstruction], 47 | cleanupInstructions: [closeWSOLAccountInstruction], 48 | signers: [tempAccount], 49 | }; 50 | }; 51 | 52 | export function createAssociatedTokenAccountInstruction( 53 | associatedTokenAddress: PublicKey, 54 | fundSource: PublicKey, 55 | destination: PublicKey, 56 | tokenMint: PublicKey, 57 | fundAddressOwner: Owner 58 | ): Instruction { 59 | const systemProgramId = new PublicKey("11111111111111111111111111111111"); 60 | const keys = [ 61 | { 62 | pubkey: fundSource, 63 | isSigner: true, 64 | isWritable: true, 65 | }, 66 | { 67 | pubkey: associatedTokenAddress, 68 | isSigner: false, 69 | isWritable: true, 70 | }, 71 | { 72 | pubkey: destination, 73 | isSigner: false, 74 | isWritable: false, 75 | }, 76 | { 77 | pubkey: tokenMint, 78 | isSigner: false, 79 | isWritable: false, 80 | }, 81 | { 82 | pubkey: systemProgramId, 83 | isSigner: false, 84 | isWritable: false, 85 | }, 86 | { 87 | pubkey: TOKEN_PROGRAM_ID, 88 | isSigner: false, 89 | isWritable: false, 90 | }, 91 | { 92 | pubkey: SYSVAR_RENT_PUBKEY, 93 | isSigner: false, 94 | isWritable: false, 95 | }, 96 | ]; 97 | const createATAInstruction = new TransactionInstruction({ 98 | keys, 99 | programId: SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID, 100 | data: Buffer.from([]), 101 | }); 102 | return { 103 | instructions: [createATAInstruction], 104 | cleanupInstructions: [], 105 | signers: fundAddressOwner.signer ? [fundAddressOwner.signer] : [], 106 | }; 107 | } 108 | -------------------------------------------------------------------------------- /src/public/utils/web3/key-utils.ts: -------------------------------------------------------------------------------- 1 | import { Keypair, PublicKey, Signer } from "@solana/web3.js"; 2 | 3 | type _Owner = Keypair | PublicKey; 4 | 5 | export class Owner { 6 | private readonly _owner: _Owner; 7 | 8 | constructor(owner: _Owner) { 9 | this._owner = owner; 10 | } 11 | 12 | get publicKey(): PublicKey { 13 | if (Owner.isKeyPair(this._owner)) { 14 | return this._owner.publicKey; 15 | } 16 | 17 | return this._owner; 18 | } 19 | 20 | get signer(): Signer | undefined { 21 | return Owner.isKeyPair(this._owner) ? this._owner : undefined; 22 | } 23 | 24 | get isKeyPair(): boolean { 25 | return Owner.isKeyPair(this._owner); 26 | } 27 | 28 | get isPublicKey(): boolean { 29 | return Owner.isPublicKey(this._owner); 30 | } 31 | 32 | static isKeyPair(owner: _Owner): owner is Keypair { 33 | return (owner as Keypair).secretKey !== undefined; 34 | } 35 | 36 | static isPublicKey(owner: _Owner): owner is PublicKey { 37 | return !Owner.isKeyPair(owner); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/public/utils/web3/transactions/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./transaction-builder"; 2 | -------------------------------------------------------------------------------- /src/public/utils/web3/transactions/transaction-builder.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Connection, 3 | PublicKey, 4 | sendAndConfirmTransaction, 5 | Transaction, 6 | TransactionCtorFields, 7 | Signer, 8 | Keypair, 9 | TransactionInstruction, 10 | } from "@solana/web3.js"; 11 | import { Instruction } from "../.."; 12 | import { TransactionPayload } from "../../models"; 13 | import { Owner } from "../key-utils"; 14 | 15 | export class TransactionBuilder { 16 | private connection: Connection; 17 | private feePayer: PublicKey; 18 | private instructions: Instruction[]; 19 | private owner: Owner; 20 | 21 | constructor(connection: Connection, feePayer: PublicKey, owner: Owner) { 22 | this.connection = connection; 23 | this.feePayer = feePayer; 24 | this.instructions = []; 25 | this.owner = owner; 26 | } 27 | 28 | addInstruction(instruction: Instruction): TransactionBuilder { 29 | this.instructions.push(instruction); 30 | return this; 31 | } 32 | 33 | async build(): Promise { 34 | const recentBlockHash = (await this.connection.getRecentBlockhash("singleGossip")).blockhash; 35 | const txFields: TransactionCtorFields = { 36 | recentBlockhash: recentBlockHash, 37 | feePayer: this.feePayer, 38 | }; 39 | 40 | let instructions: TransactionInstruction[] = []; 41 | let cleanupInstructions: TransactionInstruction[] = []; 42 | let signers: Signer[] = []; 43 | this.instructions.forEach((curr) => { 44 | instructions = instructions.concat(curr.instructions); 45 | cleanupInstructions = curr.cleanupInstructions.concat(cleanupInstructions); 46 | signers = signers.concat(curr.signers); 47 | }); 48 | 49 | const transaction = new Transaction(txFields); 50 | transaction.add(...instructions.concat(cleanupInstructions)); 51 | transaction.feePayer = this.feePayer; 52 | 53 | return { 54 | transaction: transaction, 55 | signers: signers, 56 | execute: this.owner.isKeyPair 57 | ? async () => { 58 | return sendAndConfirmTransaction(this.connection, transaction, signers); 59 | } 60 | : async () => { 61 | throw new Error( 62 | "Please use a Keypair for the owner parameter to enable the execute function" 63 | ); 64 | }, 65 | }; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig-base.json", 3 | "compilerOptions": { 4 | "composite": true, 5 | }, 6 | } -------------------------------------------------------------------------------- /test/model/orca/quote/constant-product-quote.test.ts: -------------------------------------------------------------------------------- 1 | import { u64 } from "@solana/spl-token"; 2 | import Decimal from "decimal.js"; 3 | import { OrcaToken } from "../../../../src"; 4 | import * as Token from "../../../../src/constants/tokens"; 5 | import { CurveType } from "../../../../src/model/orca/pool/pool-types"; 6 | import { 7 | QuoteBuilder, 8 | QuoteBuilderFactory, 9 | QuotePoolParams, 10 | } from "../../../../src/model/quote/quote-builder"; 11 | import { DecimalUtil, OrcaU64, Percentage } from "../../../../src/public"; 12 | import { defaultQuotePoolParams, defaultSOLToken, defaultUsdcToken } from "../../../test-utils"; 13 | import { Builder } from "builder-pattern"; 14 | 15 | const builder: QuoteBuilder = QuoteBuilderFactory.getBuilder( 16 | CurveType.ConstantProduct 17 | ) as QuoteBuilder; 18 | 19 | test("Input & Output tokens have different scale", () => { 20 | const params = Builder(defaultQuotePoolParams).build(); 21 | 22 | const quote = builder.buildQuote( 23 | params, 24 | DecimalUtil.toU64(new Decimal(10), params.inputToken.scale) 25 | ); 26 | 27 | expect(quote.getRate()).toEqual(new Decimal(24.175536)); 28 | expect(quote.getPriceImpact()).toEqual(new Decimal(0.036059)); 29 | expect(quote.getLPFees()).toEqual(new OrcaU64(new u64("30000000"), params.inputToken.scale)); 30 | expect(quote.getNetworkFees()).toEqual(new OrcaU64(new u64("10000"))); 31 | expect(quote.getMinOutputAmount()).toEqual( 32 | new OrcaU64(new u64("241513608"), params.outputToken.scale) 33 | ); 34 | expect(quote.getExpectedOutputAmount()).toEqual( 35 | new OrcaU64(new u64("241755364"), params.outputToken.scale) 36 | ); 37 | }); 38 | 39 | test("Input & Output tokens have the same scale", () => { 40 | const usdcTokenWithSameScale = Builder(Token.usdcToken) 41 | .scale(Token.solToken.scale) 42 | .build(); 43 | const params = Builder(defaultQuotePoolParams) 44 | .outputTokenCount(new u64("670432580208000")) 45 | .outputToken(usdcTokenWithSameScale) 46 | .build(); 47 | 48 | const quote = builder.buildQuote( 49 | params, 50 | DecimalUtil.toU64(new Decimal(10), params.inputToken.scale) 51 | ); 52 | 53 | expect(quote.getRate()).toEqual(new Decimal(24.175536404)); 54 | expect(quote.getPriceImpact()).toEqual(new Decimal(0.036059609)); 55 | expect(quote.getLPFees()).toEqual(new OrcaU64(new u64("30000000"), params.inputToken.scale)); 56 | expect(quote.getNetworkFees()).toEqual(new OrcaU64(new u64("10000"))); 57 | expect(quote.getMinOutputAmount()).toEqual( 58 | new OrcaU64(new u64("241513608677"), params.outputToken.scale) 59 | ); 60 | expect(quote.getExpectedOutputAmount()).toEqual( 61 | new OrcaU64(new u64("241755364042"), params.outputToken.scale) 62 | ); 63 | }); 64 | 65 | test("Input trade amount equal 0 ", () => { 66 | const params = Builder(defaultQuotePoolParams).build(); 67 | 68 | const quote = builder.buildQuote( 69 | params, 70 | DecimalUtil.toU64(new Decimal(0), params.inputToken.scale) 71 | ); 72 | 73 | expect(quote.getRate()).toEqual(new Decimal(0)); 74 | expect(quote.getPriceImpact()).toEqual(new Decimal(0)); 75 | expect(quote.getLPFees()).toEqual(new OrcaU64(new u64("0"), params.inputToken.scale)); 76 | expect(quote.getNetworkFees()).toEqual(new OrcaU64(new u64("10000"))); 77 | expect(quote.getMinOutputAmount()).toEqual(new OrcaU64(new u64("0"), params.outputToken.scale)); 78 | expect(quote.getExpectedOutputAmount()).toEqual( 79 | new OrcaU64(new u64("0"), params.outputToken.scale) 80 | ); 81 | }); 82 | 83 | test("Input Token Count is zero", () => { 84 | const params = Builder(defaultQuotePoolParams) 85 | .inputTokenCount(new u64("0")) 86 | .build(); 87 | 88 | const quote = builder.buildQuote( 89 | params, 90 | DecimalUtil.toU64(new Decimal(10), params.inputToken.scale) 91 | ); 92 | 93 | expect(quote.getRate()).toEqual(new Decimal(67043.258021)); 94 | expect(quote.getPriceImpact()).toEqual(new Decimal(0)); 95 | expect(quote.getLPFees()).toEqual(new OrcaU64(new u64("30000000"), params.inputToken.scale)); 96 | expect(quote.getNetworkFees()).toEqual(new OrcaU64(new u64("10000"))); 97 | expect(quote.getMinOutputAmount()).toEqual( 98 | new OrcaU64(new u64("669762147627"), params.outputToken.scale) 99 | ); 100 | expect(quote.getExpectedOutputAmount()).toEqual( 101 | new OrcaU64(new u64("670432580208"), params.outputToken.scale) 102 | ); 103 | }); 104 | 105 | test("Output Token Count is zero", () => { 106 | const params = Builder(defaultQuotePoolParams) 107 | .outputTokenCount(new u64("0")) 108 | .build(); 109 | 110 | const quote = builder.buildQuote( 111 | params, 112 | DecimalUtil.toU64(new Decimal(10), params.inputToken.scale) 113 | ); 114 | 115 | expect(quote.getRate()).toEqual(new Decimal(0)); 116 | expect(quote.getPriceImpact()).toEqual(new Decimal(0)); 117 | expect(quote.getLPFees()).toEqual(new OrcaU64(new u64("30000000"), params.inputToken.scale)); 118 | expect(quote.getNetworkFees()).toEqual(new OrcaU64(new u64("10000"))); 119 | expect(quote.getMinOutputAmount()).toEqual(new OrcaU64(new u64("0"), params.outputToken.scale)); 120 | expect(quote.getExpectedOutputAmount()).toEqual( 121 | new OrcaU64(new u64("0"), params.outputToken.scale) 122 | ); 123 | }); 124 | 125 | test("Minimum fee of one token", () => { 126 | const params = Builder(defaultQuotePoolParams) 127 | // 1,000,000 defaultUSDCToken = 10,000 defaultSOLToken 128 | .inputToken(defaultUsdcToken) 129 | .inputTokenCount(new u64("1000000000000")) 130 | .outputToken(defaultSOLToken) 131 | .outputTokenCount(new u64("10000000000000")) 132 | .build(); 133 | 134 | const quote = builder.buildQuote( 135 | params, 136 | DecimalUtil.toU64(new Decimal("0.0001"), params.inputToken.scale) 137 | ); 138 | 139 | expect(quote.getRate()).toEqual(new Decimal(0.00979)); 140 | expect(quote.getPriceImpact()).toEqual(new Decimal(0.102040816)); 141 | expect(quote.getLPFees()).toEqual(new OrcaU64(new u64("2"), params.inputToken.scale)); 142 | expect(quote.getNetworkFees()).toEqual(new OrcaU64(new u64("10000"))); 143 | expect(quote.getMinOutputAmount()).toEqual(new OrcaU64(new u64("978"), params.outputToken.scale)); 144 | expect(quote.getExpectedOutputAmount()).toEqual( 145 | new OrcaU64(new u64("979"), params.outputToken.scale) 146 | ); 147 | }); 148 | 149 | describe("Too small inputTradeAmount", () => { 150 | test("Too small inputTradeAmount (1 unit)", () => { 151 | const params = Builder(defaultQuotePoolParams) 152 | // 1,000,000 defaultUSDCToken = 10,000 defaultSOLToken 153 | .inputToken(defaultUsdcToken) 154 | .inputTokenCount(new u64("1000000000000")) 155 | .outputToken(defaultSOLToken) 156 | .outputTokenCount(new u64("10000000000000")) 157 | .build(); 158 | 159 | const quote = builder.buildQuote( 160 | params, 161 | DecimalUtil.toU64(new Decimal("0.000001"), params.inputToken.scale) 162 | ); 163 | 164 | expect(quote.getRate()).toEqual(new Decimal(0)); 165 | expect(quote.getPriceImpact()).toEqual(new Decimal(0)); 166 | expect(quote.getLPFees()).toEqual(new OrcaU64(new u64("2"), params.inputToken.scale)); 167 | expect(quote.getNetworkFees()).toEqual(new OrcaU64(new u64("10000"))); 168 | expect(quote.getMinOutputAmount()).toEqual(new OrcaU64(new u64("0"), params.outputToken.scale)); 169 | expect(quote.getExpectedOutputAmount()).toEqual( 170 | new OrcaU64(new u64("0"), params.outputToken.scale) 171 | ); 172 | }); 173 | 174 | test("Too small inputTradeAmount (2 unit)", () => { 175 | const params = Builder(defaultQuotePoolParams) 176 | // 1,000,000 defaultUSDCToken = 10,000 defaultSOLToken 177 | .inputToken(defaultUsdcToken) 178 | .inputTokenCount(new u64("1000000000000")) 179 | .outputToken(defaultSOLToken) 180 | .outputTokenCount(new u64("10000000000000")) 181 | .build(); 182 | 183 | const quote = builder.buildQuote( 184 | params, 185 | DecimalUtil.toU64(new Decimal("0.000002"), params.inputToken.scale) 186 | ); 187 | 188 | expect(quote.getRate()).toEqual(new Decimal(0)); 189 | expect(quote.getPriceImpact()).toEqual(new Decimal(0)); 190 | expect(quote.getLPFees()).toEqual(new OrcaU64(new u64("2"), params.inputToken.scale)); 191 | expect(quote.getNetworkFees()).toEqual(new OrcaU64(new u64("10000"))); 192 | expect(quote.getMinOutputAmount()).toEqual(new OrcaU64(new u64("0"), params.outputToken.scale)); 193 | expect(quote.getExpectedOutputAmount()).toEqual( 194 | new OrcaU64(new u64("0"), params.outputToken.scale) 195 | ); 196 | }); 197 | 198 | test("Too small inputTradeAmount (3 unit)", () => { 199 | const params = Builder(defaultQuotePoolParams) 200 | // 1,000,000 defaultUSDCToken = 10,000 defaultSOLToken 201 | .inputToken(defaultUsdcToken) 202 | .inputTokenCount(new u64("1000000000000")) 203 | .outputToken(defaultSOLToken) 204 | .outputTokenCount(new u64("10000000000000")) 205 | .build(); 206 | 207 | const quote = builder.buildQuote( 208 | params, 209 | DecimalUtil.toU64(new Decimal("0.000003"), params.inputToken.scale) 210 | ); 211 | 212 | expect(quote.getRate()).toEqual(new Decimal(0.003)); 213 | expect(quote.getPriceImpact()).toEqual(new Decimal(10.0)); 214 | expect(quote.getLPFees()).toEqual(new OrcaU64(new u64("2"), params.inputToken.scale)); 215 | expect(quote.getNetworkFees()).toEqual(new OrcaU64(new u64("10000"))); 216 | expect(quote.getMinOutputAmount()).toEqual(new OrcaU64(new u64("8"), params.outputToken.scale)); 217 | expect(quote.getExpectedOutputAmount()).toEqual( 218 | new OrcaU64(new u64("9"), params.outputToken.scale) 219 | ); 220 | }); 221 | }); 222 | 223 | describe("Slippage tolerance", () => { 224 | test("tolerance equal 0", () => { 225 | const params = Builder(defaultQuotePoolParams) 226 | .slippageTolerance(Percentage.fromDecimal(new Decimal(0))) 227 | .build(); 228 | const quote = builder.buildQuote( 229 | params, 230 | DecimalUtil.toU64(new Decimal(10), params.inputToken.scale) 231 | ); 232 | 233 | expect(quote.getRate()).toEqual(new Decimal(24.175536)); 234 | expect(quote.getPriceImpact()).toEqual(new Decimal(0.036059)); 235 | expect(quote.getLPFees()).toEqual(new OrcaU64(new u64("30000000"), params.inputToken.scale)); 236 | expect(quote.getNetworkFees()).toEqual(new OrcaU64(new u64("10000"))); 237 | expect(quote.getMinOutputAmount()).toEqual( 238 | new OrcaU64(new u64("241755364"), params.outputToken.scale) 239 | ); 240 | expect(quote.getExpectedOutputAmount()).toEqual( 241 | new OrcaU64(new u64("241755364"), params.outputToken.scale) 242 | ); 243 | }); 244 | 245 | test("tolerance equals 0.1", () => { 246 | const params = Builder(defaultQuotePoolParams) 247 | .slippageTolerance(Percentage.fromDecimal(new Decimal(0.1))) 248 | .build(); 249 | const quote = builder.buildQuote( 250 | params, 251 | DecimalUtil.toU64(new Decimal(10), params.inputToken.scale) 252 | ); 253 | 254 | expect(quote.getRate()).toEqual(new Decimal(24.175536)); 255 | expect(quote.getPriceImpact()).toEqual(new Decimal(0.036059)); 256 | expect(quote.getLPFees()).toEqual(new OrcaU64(new u64("30000000"), params.inputToken.scale)); 257 | expect(quote.getNetworkFees()).toEqual(new OrcaU64(new u64("10000"))); 258 | expect(quote.getMinOutputAmount()).toEqual( 259 | new OrcaU64(new u64("241513608"), params.outputToken.scale) 260 | ); 261 | expect(quote.getExpectedOutputAmount()).toEqual( 262 | new OrcaU64(new u64("241755364"), params.outputToken.scale) 263 | ); 264 | }); 265 | 266 | test("tolerance equals 1 ", () => { 267 | const params = Builder(defaultQuotePoolParams) 268 | .slippageTolerance(Percentage.fromDecimal(new Decimal(1))) 269 | .build(); 270 | const quote = builder.buildQuote( 271 | params, 272 | DecimalUtil.toU64(new Decimal(10), params.inputToken.scale) 273 | ); 274 | 275 | expect(quote.getRate()).toEqual(new Decimal(24.175536)); 276 | expect(quote.getPriceImpact()).toEqual(new Decimal(0.036059)); 277 | expect(quote.getLPFees()).toEqual(new OrcaU64(new u64("30000000"), params.inputToken.scale)); 278 | expect(quote.getNetworkFees()).toEqual(new OrcaU64(new u64("10000"))); 279 | expect(quote.getMinOutputAmount()).toEqual( 280 | new OrcaU64(new u64("239337810"), params.outputToken.scale) 281 | ); 282 | expect(quote.getExpectedOutputAmount()).toEqual( 283 | new OrcaU64(new u64("241755364"), params.outputToken.scale) 284 | ); 285 | }); 286 | }); 287 | -------------------------------------------------------------------------------- /test/model/orca/quote/stable-quote.test.ts: -------------------------------------------------------------------------------- 1 | import { u64 } from "@solana/spl-token"; 2 | import Decimal from "decimal.js"; 3 | import { CurveType } from "../../../../src/model/orca/pool/pool-types"; 4 | import { 5 | QuoteBuilder, 6 | QuoteBuilderFactory, 7 | QuotePoolParams, 8 | } from "../../../../src/model/quote/quote-builder"; 9 | import { DecimalUtil, OrcaU64, Percentage } from "../../../../src/public"; 10 | import { stableQuotePoolParams } from "../../../test-utils"; 11 | import { Builder } from "builder-pattern"; 12 | 13 | const builder: QuoteBuilder = QuoteBuilderFactory.getBuilder(CurveType.Stable) as QuoteBuilder; 14 | 15 | test("Input & Output tokens have same scale", () => { 16 | const params = Builder(stableQuotePoolParams).build(); 17 | 18 | const quote = builder.buildQuote( 19 | params, 20 | DecimalUtil.toU64(new Decimal(1e6), params.inputToken.scale) 21 | ); 22 | 23 | expect(quote.getRate()).toEqual(new Decimal(0.9987)); 24 | expect(quote.getPriceImpact()).toEqual(new Decimal(0.055222)); 25 | expect(quote.getLPFees()).toEqual(new OrcaU64(new u64("700000000"), params.inputToken.scale)); 26 | expect(quote.getNetworkFees()).toEqual(new OrcaU64(new u64("10000"))); 27 | expect(quote.getMinOutputAmount()).toEqual( 28 | new OrcaU64(new u64("997701271318"), params.outputToken.scale) 29 | ); 30 | expect(quote.getExpectedOutputAmount()).toEqual( 31 | new OrcaU64(new u64("998699971290"), params.outputToken.scale) 32 | ); 33 | }); 34 | 35 | test("Input trade amount equal 0 ", () => { 36 | const params = Builder(stableQuotePoolParams).build(); 37 | 38 | const quote = builder.buildQuote( 39 | params, 40 | DecimalUtil.toU64(new Decimal(0), params.inputToken.scale) 41 | ); 42 | 43 | expect(quote.getRate()).toEqual(new Decimal(0)); 44 | expect(quote.getPriceImpact()).toEqual(new Decimal(0)); 45 | expect(quote.getLPFees()).toEqual(new OrcaU64(new u64("0"), params.inputToken.scale)); 46 | expect(quote.getNetworkFees()).toEqual(new OrcaU64(new u64("10000"))); 47 | expect(quote.getMinOutputAmount()).toEqual(new OrcaU64(new u64("0"), params.outputToken.scale)); 48 | expect(quote.getExpectedOutputAmount()).toEqual( 49 | new OrcaU64(new u64("0"), params.outputToken.scale) 50 | ); 51 | }); 52 | 53 | test("Input Token Count is zero", () => { 54 | const params = Builder(stableQuotePoolParams) 55 | .inputTokenCount(new u64("0")) 56 | .build(); 57 | 58 | const quote = builder.buildQuote( 59 | params, 60 | DecimalUtil.toU64(new Decimal(1e6), params.inputToken.scale) 61 | ); 62 | 63 | expect(quote.getRate()).toEqual(new Decimal(19.577821)); 64 | expect(quote.getPriceImpact()).toEqual(new Decimal(0)); 65 | expect(quote.getLPFees()).toEqual(new OrcaU64(new u64("700000000"), params.inputToken.scale)); 66 | expect(quote.getNetworkFees()).toEqual(new OrcaU64(new u64("10000"))); 67 | 68 | // Recreating `OrcaU64` objects for the following checks to prevent the BN vs u64 mismatch error 69 | const minOutputAmount = quote.getMinOutputAmount(); 70 | expect(new OrcaU64(minOutputAmount.toU64(), minOutputAmount.scale)).toEqual( 71 | new OrcaU64(new u64("19558243405204"), params.outputToken.scale) 72 | ); 73 | 74 | const expectedOutputAmount = quote.getExpectedOutputAmount(); 75 | expect(new OrcaU64(expectedOutputAmount.toU64(), expectedOutputAmount.scale)).toEqual( 76 | new OrcaU64(new u64("19577821226431"), params.outputToken.scale) 77 | ); 78 | }); 79 | 80 | test("Output Token Count is zero", () => { 81 | const params = Builder(stableQuotePoolParams) 82 | .outputTokenCount(new u64("0")) 83 | .build(); 84 | 85 | const quote = builder.buildQuote( 86 | params, 87 | DecimalUtil.toU64(new Decimal(1e6), params.inputToken.scale) 88 | ); 89 | 90 | expect(quote.getRate()).toEqual(new Decimal(0)); 91 | expect(quote.getPriceImpact()).toEqual(new Decimal(0)); 92 | expect(quote.getLPFees()).toEqual(new OrcaU64(new u64("700000000"), params.inputToken.scale)); 93 | expect(quote.getNetworkFees()).toEqual(new OrcaU64(new u64("10000"))); 94 | expect(quote.getMinOutputAmount()).toEqual(new OrcaU64(new u64("0"), params.outputToken.scale)); 95 | expect(quote.getExpectedOutputAmount()).toEqual( 96 | new OrcaU64(new u64("0"), params.outputToken.scale) 97 | ); 98 | }); 99 | 100 | describe("Slippage tolerance", () => { 101 | test("tolerance equal 0%", () => { 102 | const params = Builder(stableQuotePoolParams) 103 | .slippageTolerance(Percentage.fromDecimal(new Decimal(0))) 104 | .build(); 105 | const quote = builder.buildQuote( 106 | params, 107 | DecimalUtil.toU64(new Decimal(1e6), params.inputToken.scale) 108 | ); 109 | 110 | expect(quote.getRate()).toEqual(new Decimal(0.9987)); 111 | expect(quote.getPriceImpact()).toEqual(new Decimal(0.055222)); 112 | expect(quote.getLPFees()).toEqual(new OrcaU64(new u64("700000000"), params.inputToken.scale)); 113 | expect(quote.getNetworkFees()).toEqual(new OrcaU64(new u64("10000"))); 114 | expect(quote.getMinOutputAmount()).toEqual( 115 | new OrcaU64(new u64("998699971290"), params.outputToken.scale) 116 | ); 117 | expect(quote.getExpectedOutputAmount()).toEqual( 118 | new OrcaU64(new u64("998699971290"), params.outputToken.scale) 119 | ); 120 | }); 121 | 122 | test("tolerance equals 0.1%", () => { 123 | const params = Builder(stableQuotePoolParams) 124 | .slippageTolerance(Percentage.fromDecimal(new Decimal(0.1))) 125 | .build(); 126 | const quote = builder.buildQuote( 127 | params, 128 | DecimalUtil.toU64(new Decimal(1e6), params.inputToken.scale) 129 | ); 130 | 131 | expect(quote.getRate()).toEqual(new Decimal(0.9987)); 132 | expect(quote.getPriceImpact()).toEqual(new Decimal(0.055222)); 133 | expect(quote.getLPFees()).toEqual(new OrcaU64(new u64("700000000"), params.inputToken.scale)); 134 | expect(quote.getNetworkFees()).toEqual(new OrcaU64(new u64("10000"))); 135 | expect(quote.getMinOutputAmount()).toEqual( 136 | new OrcaU64(new u64("997701271318"), params.outputToken.scale) 137 | ); 138 | expect(quote.getExpectedOutputAmount()).toEqual( 139 | new OrcaU64(new u64("998699971290"), params.outputToken.scale) 140 | ); 141 | }); 142 | 143 | test("tolerance equals 1%", () => { 144 | const params = Builder(stableQuotePoolParams) 145 | .slippageTolerance(Percentage.fromDecimal(new Decimal(1))) 146 | .build(); 147 | const quote = builder.buildQuote( 148 | params, 149 | DecimalUtil.toU64(new Decimal(1e6), params.inputToken.scale) 150 | ); 151 | 152 | expect(quote.getRate()).toEqual(new Decimal(0.9987)); 153 | expect(quote.getPriceImpact()).toEqual(new Decimal(0.055222)); 154 | expect(quote.getLPFees()).toEqual(new OrcaU64(new u64("700000000"), params.inputToken.scale)); 155 | expect(quote.getNetworkFees()).toEqual(new OrcaU64(new u64("10000"))); 156 | expect(quote.getMinOutputAmount()).toEqual( 157 | new OrcaU64(new u64("988712971577"), params.outputToken.scale) 158 | ); 159 | expect(quote.getExpectedOutputAmount()).toEqual( 160 | new OrcaU64(new u64("998699971290"), params.outputToken.scale) 161 | ); 162 | }); 163 | }); 164 | 165 | // Make sure that as amp goes up, a better price is quoted and price impact is lower 166 | describe("Amplification Coefficient", () => { 167 | test("amp is undefined", () => { 168 | const params = Builder(stableQuotePoolParams).amp(undefined).build(); 169 | 170 | expect(() => 171 | builder.buildQuote(params, DecimalUtil.toU64(new Decimal(1e6), params.inputToken.scale)) 172 | ).toThrow("amp param required for stable pool"); 173 | }); 174 | 175 | test("amp equals 10", () => { 176 | const params = Builder(stableQuotePoolParams).amp(new u64(10)).build(); 177 | 178 | const quote = builder.buildQuote( 179 | params, 180 | DecimalUtil.toU64(new Decimal(1e6), params.inputToken.scale) 181 | ); 182 | 183 | expect(quote.getRate()).toEqual(new Decimal(0.993818)); 184 | expect(quote.getPriceImpact()).toEqual(new Decimal(0.502629)); 185 | expect(quote.getLPFees()).toEqual(new OrcaU64(new u64("700000000"), params.inputToken.scale)); 186 | expect(quote.getNetworkFees()).toEqual(new OrcaU64(new u64("10000"))); 187 | expect(quote.getMinOutputAmount()).toEqual( 188 | new OrcaU64(new u64("992824297062"), params.outputToken.scale) 189 | ); 190 | expect(quote.getExpectedOutputAmount()).toEqual( 191 | new OrcaU64(new u64("993818115178"), params.outputToken.scale) 192 | ); 193 | }); 194 | 195 | test("amp equals 100", () => { 196 | const params = Builder(stableQuotePoolParams).amp(new u64(100)).build(); 197 | 198 | const quote = builder.buildQuote( 199 | params, 200 | DecimalUtil.toU64(new Decimal(1e6), params.inputToken.scale) 201 | ); 202 | 203 | expect(quote.getRate()).toEqual(new Decimal(0.9987)); 204 | expect(quote.getPriceImpact()).toEqual(new Decimal(0.055222)); 205 | expect(quote.getLPFees()).toEqual(new OrcaU64(new u64("700000000"), params.inputToken.scale)); 206 | expect(quote.getNetworkFees()).toEqual(new OrcaU64(new u64("10000"))); 207 | expect(quote.getMinOutputAmount()).toEqual( 208 | new OrcaU64(new u64("997701271318"), params.outputToken.scale) 209 | ); 210 | expect(quote.getExpectedOutputAmount()).toEqual( 211 | new OrcaU64(new u64("998699971290"), params.outputToken.scale) 212 | ); 213 | }); 214 | }); 215 | 216 | describe("Fee Structure", () => { 217 | test("both owner and trader fees are non-zero", () => { 218 | const params = Builder(stableQuotePoolParams) 219 | .feeStructure({ 220 | traderFee: Percentage.fromFraction(6, 10000), 221 | ownerFee: Percentage.fromFraction(1, 10000), 222 | }) 223 | .build(); 224 | 225 | const quote = builder.buildQuote( 226 | params, 227 | DecimalUtil.toU64(new Decimal(1e6), params.inputToken.scale) 228 | ); 229 | 230 | expect(quote.getRate()).toEqual(new Decimal(0.9987)); 231 | expect(quote.getPriceImpact()).toEqual(new Decimal(0.055222)); 232 | expect(quote.getLPFees()).toEqual(new OrcaU64(new u64("700000000"), params.inputToken.scale)); 233 | expect(quote.getNetworkFees()).toEqual(new OrcaU64(new u64("10000"))); 234 | expect(quote.getMinOutputAmount()).toEqual( 235 | new OrcaU64(new u64("997701271318"), params.outputToken.scale) 236 | ); 237 | expect(quote.getExpectedOutputAmount()).toEqual( 238 | new OrcaU64(new u64("998699971290"), params.outputToken.scale) 239 | ); 240 | }); 241 | 242 | test("owner fee is non-zero, trader fee is 0", () => { 243 | const params = Builder(stableQuotePoolParams) 244 | .feeStructure({ 245 | traderFee: Percentage.fromFraction(0, 10000), 246 | ownerFee: Percentage.fromFraction(1, 10000), 247 | }) 248 | .build(); 249 | 250 | const quote = builder.buildQuote( 251 | params, 252 | DecimalUtil.toU64(new Decimal(1e6), params.inputToken.scale) 253 | ); 254 | 255 | expect(quote.getRate()).toEqual(new Decimal(0.999299)); 256 | expect(quote.getPriceImpact()).toEqual(new Decimal(0.055253)); 257 | expect(quote.getLPFees()).toEqual(new OrcaU64(new u64("100000000"), params.inputToken.scale)); 258 | expect(quote.getNetworkFees()).toEqual(new OrcaU64(new u64("10000"))); 259 | expect(quote.getMinOutputAmount()).toEqual( 260 | new OrcaU64(new u64("998300007201"), params.outputToken.scale) 261 | ); 262 | expect(quote.getExpectedOutputAmount()).toEqual( 263 | new OrcaU64(new u64("999299306508"), params.outputToken.scale) 264 | ); 265 | }); 266 | 267 | test("trader fee is non-zero, owner fee is 0", () => { 268 | const params = Builder(stableQuotePoolParams) 269 | .feeStructure({ 270 | traderFee: Percentage.fromFraction(6, 10000), 271 | ownerFee: Percentage.fromFraction(0, 10000), 272 | }) 273 | .build(); 274 | 275 | const quote = builder.buildQuote( 276 | params, 277 | DecimalUtil.toU64(new Decimal(1e6), params.inputToken.scale) 278 | ); 279 | 280 | expect(quote.getRate()).toEqual(new Decimal(0.9988)); 281 | expect(quote.getPriceImpact()).toEqual(new Decimal(0.055227)); 282 | expect(quote.getLPFees()).toEqual(new OrcaU64(new u64("600000000"), params.inputToken.scale)); 283 | expect(quote.getNetworkFees()).toEqual(new OrcaU64(new u64("10000"))); 284 | expect(quote.getMinOutputAmount()).toEqual( 285 | new OrcaU64(new u64("997801060657"), params.outputToken.scale) 286 | ); 287 | expect(quote.getExpectedOutputAmount()).toEqual( 288 | new OrcaU64(new u64("998799860518"), params.outputToken.scale) 289 | ); 290 | }); 291 | 292 | test("both owner and trader fees are 0", () => { 293 | const params = Builder(stableQuotePoolParams) 294 | .feeStructure({ 295 | traderFee: Percentage.fromFraction(0, 10000), 296 | ownerFee: Percentage.fromFraction(0, 10000), 297 | }) 298 | .build(); 299 | 300 | const quote = builder.buildQuote( 301 | params, 302 | DecimalUtil.toU64(new Decimal(1e6), params.inputToken.scale) 303 | ); 304 | 305 | expect(quote.getRate()).toEqual(new Decimal(0.999399)); 306 | expect(quote.getPriceImpact()).toEqual(new Decimal(0.055258)); 307 | expect(quote.getLPFees()).toEqual(new OrcaU64(new u64(0), params.inputToken.scale)); 308 | expect(quote.getNetworkFees()).toEqual(new OrcaU64(new u64("10000"))); 309 | expect(quote.getMinOutputAmount()).toEqual( 310 | new OrcaU64(new u64("998399796479"), params.outputToken.scale) 311 | ); 312 | expect(quote.getExpectedOutputAmount()).toEqual( 313 | new OrcaU64(new u64("999399195675"), params.outputToken.scale) 314 | ); 315 | }); 316 | 317 | test("Minimum fee of one token", () => { 318 | const params = Builder(stableQuotePoolParams).build(); 319 | 320 | const quote = builder.buildQuote( 321 | params, 322 | DecimalUtil.toU64(new Decimal("0.0001"), params.inputToken.scale) 323 | ); 324 | 325 | expect(quote.getRate()).toEqual(new Decimal(0.98)); 326 | expect(quote.getPriceImpact()).toEqual(new Decimal(-1.030928)); 327 | expect(quote.getLPFees()).toEqual(new OrcaU64(new u64("2"), params.inputToken.scale)); 328 | expect(quote.getNetworkFees()).toEqual(new OrcaU64(new u64("10000"))); 329 | expect(quote.getMinOutputAmount()).toEqual( 330 | new OrcaU64(new u64("97"), params.outputToken.scale) 331 | ); 332 | expect(quote.getExpectedOutputAmount()).toEqual( 333 | new OrcaU64(new u64("98"), params.outputToken.scale) 334 | ); 335 | }); 336 | }); 337 | 338 | describe("Too small inputTradeAmount", () => { 339 | test("Too small inputTradeAmount (1 unit)", () => { 340 | const params = Builder(stableQuotePoolParams).build(); 341 | 342 | const quote = builder.buildQuote( 343 | params, 344 | DecimalUtil.toU64(new Decimal("0.000001"), params.inputToken.scale) 345 | ); 346 | 347 | expect(quote.getRate()).toEqual(new Decimal(0)); 348 | expect(quote.getPriceImpact()).toEqual(new Decimal(0)); 349 | expect(quote.getLPFees()).toEqual(new OrcaU64(new u64("2"), params.inputToken.scale)); 350 | expect(quote.getNetworkFees()).toEqual(new OrcaU64(new u64("10000"))); 351 | expect(quote.getMinOutputAmount()).toEqual(new OrcaU64(new u64("0"), params.outputToken.scale)); 352 | expect(quote.getExpectedOutputAmount()).toEqual( 353 | new OrcaU64(new u64("0"), params.outputToken.scale) 354 | ); 355 | }); 356 | 357 | test("Too small inputTradeAmount (2 unit)", () => { 358 | const params = Builder(stableQuotePoolParams).build(); 359 | 360 | const quote = builder.buildQuote( 361 | params, 362 | DecimalUtil.toU64(new Decimal("0.000002"), params.inputToken.scale) 363 | ); 364 | 365 | expect(quote.getRate()).toEqual(new Decimal(0)); 366 | expect(quote.getPriceImpact()).toEqual(new Decimal(0)); 367 | expect(quote.getLPFees()).toEqual(new OrcaU64(new u64("2"), params.inputToken.scale)); 368 | expect(quote.getNetworkFees()).toEqual(new OrcaU64(new u64("10000"))); 369 | expect(quote.getMinOutputAmount()).toEqual(new OrcaU64(new u64("0"), params.outputToken.scale)); 370 | expect(quote.getExpectedOutputAmount()).toEqual( 371 | new OrcaU64(new u64("0"), params.outputToken.scale) 372 | ); 373 | }); 374 | 375 | test("Too small inputTradeAmount (3 unit)", () => { 376 | const params = Builder(stableQuotePoolParams).build(); 377 | 378 | const quote = builder.buildQuote( 379 | params, 380 | DecimalUtil.toU64(new Decimal("0.000003"), params.inputToken.scale) 381 | ); 382 | 383 | expect(quote.getRate()).toEqual(new Decimal(0.333333)); 384 | expect(quote.getPriceImpact()).toEqual(new Decimal(0)); 385 | expect(quote.getLPFees()).toEqual(new OrcaU64(new u64("2"), params.inputToken.scale)); 386 | expect(quote.getNetworkFees()).toEqual(new OrcaU64(new u64("10000"))); 387 | expect(quote.getMinOutputAmount()).toEqual(new OrcaU64(new u64("0"), params.outputToken.scale)); 388 | expect(quote.getExpectedOutputAmount()).toEqual( 389 | new OrcaU64(new u64("1"), params.outputToken.scale) 390 | ); 391 | }); 392 | }); 393 | -------------------------------------------------------------------------------- /test/public/utils/orca-u64.test.ts: -------------------------------------------------------------------------------- 1 | import { u64 } from "@solana/spl-token"; 2 | import Decimal from "decimal.js"; 3 | import { OrcaU64 } from "../../../src/public"; 4 | 5 | // OrcaU64.fromDecimal 6 | describe.each([ 7 | { value: 0, scale: 9, expectedValue: new u64("0"), expectedScale: 9 }, 8 | { value: 25000, scale: 5, expectedValue: new u64("2500000000"), expectedScale: 5 }, 9 | { value: 15.58942, scale: 6, expectedValue: new u64("15589420"), expectedScale: 6 }, 10 | { value: 15.58942, scale: 6.7, expectedValue: new u64("15589420"), expectedScale: 6 }, 11 | ])("fromDecimal($value, $decimals)", ({ value, scale: decimals, expectedValue, expectedScale }) => { 12 | test(`returns {${expectedValue}, ${expectedScale}}`, () => { 13 | expect(OrcaU64.fromDecimal(new Decimal(value), decimals)).toEqual( 14 | new OrcaU64(expectedValue, expectedScale) 15 | ); 16 | }); 17 | }); 18 | 19 | // OrcaU64.fromNumber 20 | describe.each([ 21 | { value: 0, scale: 9, expectedValue: new u64("0"), expectedScale: 9 }, 22 | { value: 25000, scale: 5, expectedValue: new u64("2500000000"), expectedScale: 5 }, 23 | { value: 15.58942, scale: 6, expectedValue: new u64("15589420"), expectedScale: 6 }, 24 | { value: 15.58942, scale: 6.7, expectedValue: new u64("15589420"), expectedScale: 6 }, 25 | ])("fromNumber($value, $decimals)", ({ value, scale: decimals, expectedValue, expectedScale }) => { 26 | test(`returns {${expectedValue}, ${expectedScale}}`, () => { 27 | expect(OrcaU64.fromNumber(value, decimals)).toEqual(new OrcaU64(expectedValue, expectedScale)); 28 | }); 29 | }); 30 | 31 | // OrcaU64.fromU64 32 | describe.each([ 33 | { value: new u64(0), scale: 9, expectedValue: new u64("0"), expectedScale: 9 }, 34 | { value: new u64(25000), scale: 5, expectedValue: new u64("25000"), expectedScale: 5 }, 35 | { value: new u64(15589420), scale: 6, expectedValue: new u64("15589420"), expectedScale: 6 }, 36 | { 37 | value: new u64(1), 38 | scale: 6.7, 39 | expectedValue: new u64("1"), 40 | expectedScale: 6, 41 | }, 42 | ])("fromU64($value, $decimals)", ({ value, scale: decimals, expectedValue, expectedScale }) => { 43 | test(`returns {${expectedValue}, ${expectedScale}}`, () => { 44 | expect(OrcaU64.fromU64(value, decimals)).toEqual(new OrcaU64(expectedValue, expectedScale)); 45 | }); 46 | }); 47 | 48 | // OrcaU64.toDecimal 49 | describe.each([ 50 | { value: OrcaU64.fromNumber(0, 9), expectedValue: 0 }, 51 | { value: OrcaU64.fromNumber(25000, 5), expectedValue: 25000 }, 52 | { value: OrcaU64.fromNumber(15.58942, 6), expectedValue: 15.58942 }, 53 | ])("toDecimal($value)", ({ value, expectedValue }) => { 54 | test(`returns {${expectedValue}}`, () => { 55 | expect(value.toDecimal()).toEqual(new Decimal(expectedValue)); 56 | }); 57 | }); 58 | 59 | // OrcaU64.toNumber 60 | describe.each([ 61 | { value: OrcaU64.fromNumber(0, 9), expectedValue: 0 }, 62 | { value: OrcaU64.fromNumber(25000, 5), expectedValue: 25000 }, 63 | { value: OrcaU64.fromNumber(15.58942, 6), expectedValue: 15.58942 }, 64 | ])("toNumber($value)", ({ value, expectedValue }) => { 65 | test(`returns {${expectedValue}}`, () => { 66 | expect(value.toNumber()).toEqual(expectedValue); 67 | }); 68 | }); 69 | 70 | // OrcaU64.toU64 71 | describe.each([ 72 | { value: OrcaU64.fromU64(new u64(0), 5), expectedValue: new u64(0) }, 73 | { value: OrcaU64.fromU64(new u64(25000), 5), expectedValue: new u64(25000) }, 74 | { value: OrcaU64.fromU64(new u64(15589420), 6), expectedValue: new u64(15589420) }, 75 | ])("toU64($value)", ({ value, expectedValue }) => { 76 | test(`returns {${expectedValue}}`, () => { 77 | expect(value.toU64()).toEqual(expectedValue); 78 | }); 79 | }); 80 | -------------------------------------------------------------------------------- /test/test-utils.ts: -------------------------------------------------------------------------------- 1 | import { u64 } from "@solana/spl-token"; 2 | import { PublicKey } from "@solana/web3.js"; 3 | import Decimal from "decimal.js"; 4 | import { OrcaToken } from "../src"; 5 | import { FeeStructure } from "../src/model/orca/pool/pool-types"; 6 | import { QuotePoolParams } from "../src/model/quote/quote-builder"; 7 | import { Percentage } from "../src/public"; 8 | 9 | export const defaultSOLToken: OrcaToken = { 10 | tag: "SOL", 11 | name: "Solana", 12 | mint: new PublicKey("So11111111111111111111111111111111111111112"), 13 | scale: 9, 14 | }; 15 | 16 | export const defaultUsdcToken: OrcaToken = { 17 | tag: "USDC", 18 | name: "USD Coin", 19 | mint: new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"), 20 | scale: 6, 21 | }; 22 | 23 | export const defaultUsdtToken: OrcaToken = { 24 | tag: "USDT", 25 | name: "Tether USD", 26 | mint: new PublicKey("Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB"), 27 | scale: 6, 28 | }; 29 | 30 | export const defaultEthToken: OrcaToken = { 31 | tag: "ETH", 32 | name: "Ethereum", 33 | mint: new PublicKey("2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk"), 34 | scale: 6, 35 | }; 36 | 37 | export const defaultFeeStructure: FeeStructure = { 38 | traderFee: Percentage.fromDecimal(new Decimal(0.2)), 39 | ownerFee: Percentage.fromDecimal(new Decimal(0.1)), 40 | }; 41 | 42 | export const defaultLamportsPerSignature: number = 5000; 43 | 44 | export const defaultQuotePoolParams: QuotePoolParams = { 45 | inputTokenCount: new u64("27638693975460"), 46 | outputTokenCount: new u64("670432580208"), 47 | inputToken: defaultSOLToken, 48 | outputToken: defaultUsdcToken, 49 | feeStructure: defaultFeeStructure, 50 | slippageTolerance: Percentage.fromDecimal(new Decimal(0.1)), 51 | lamportsPerSignature: defaultLamportsPerSignature, 52 | }; 53 | 54 | export const stableQuotePoolParams: QuotePoolParams = { 55 | inputTokenCount: new u64("19768621149413"), 56 | outputTokenCount: new u64("19577821226623"), 57 | inputToken: defaultUsdcToken, 58 | outputToken: defaultUsdtToken, 59 | feeStructure: { 60 | traderFee: Percentage.fromFraction(6, 10000), 61 | ownerFee: Percentage.fromFraction(1, 10000), 62 | }, 63 | slippageTolerance: Percentage.fromDecimal(new Decimal(0.1)), 64 | lamportsPerSignature: defaultLamportsPerSignature, 65 | amp: new u64(100), 66 | }; 67 | -------------------------------------------------------------------------------- /test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig-base.json", 3 | "references": [ 4 | { 5 | "path": "../src" 6 | } 7 | ] 8 | } -------------------------------------------------------------------------------- /test/utils/models/percentage.test.ts: -------------------------------------------------------------------------------- 1 | import Decimal from "decimal.js"; 2 | import { Percentage } from "../../../src"; 3 | 4 | const oneOverThousand: Percentage = Percentage.fromFraction(1, 1000); 5 | const tenOverTenThousand: Percentage = Percentage.fromFraction(1, 10000); 6 | 7 | describe.each([ 8 | { 9 | p1: Percentage.fromFraction(1, 1000), 10 | p2: Percentage.fromFraction(1, 10000), 11 | expected: Percentage.fromFraction(11, 10000), 12 | }, 13 | { 14 | p1: Percentage.fromFraction(1, 3), 15 | p2: Percentage.fromFraction(1, 7), 16 | expected: Percentage.fromFraction(10, 21), 17 | }, 18 | { 19 | p1: Percentage.fromFraction(5, 10000), 20 | p2: Percentage.fromFraction(7, 10000), 21 | expected: Percentage.fromFraction(12, 10000), 22 | }, 23 | { 24 | p1: Percentage.fromFraction(0, 1000), 25 | p2: Percentage.fromFraction(0, 10000), 26 | expected: Percentage.fromFraction(0, 10000), 27 | }, 28 | { 29 | p1: Percentage.fromFraction(30, 10000), 30 | p2: Percentage.fromFraction(5, 10000), 31 | expected: Percentage.fromFraction(35, 10000), 32 | }, 33 | ])("Percentage.add", ({ p1, p2, expected }) => { 34 | test(`add(${p1.toString()}, ${p2.toString()}}) returns {${expected.toString()}}`, () => { 35 | expect(p1.add(p2).toString()).toEqual(expected.toString()); 36 | }); 37 | }); 38 | 39 | describe.each([ 40 | { 41 | p1: Percentage.fromFraction(1, 1000), 42 | expected: new Decimal(1).div(new Decimal(1000)), 43 | }, 44 | { 45 | p1: Percentage.fromFraction(1, 3), 46 | expected: new Decimal(1).div(new Decimal(3)), 47 | }, 48 | { 49 | p1: Percentage.fromFraction(5, 10000), 50 | expected: new Decimal(5).div(new Decimal(10000)), 51 | }, 52 | { 53 | p1: Percentage.fromFraction(0, 1000), 54 | expected: new Decimal(0).div(new Decimal(1000)), 55 | }, 56 | { 57 | p1: Percentage.fromFraction(30, 0), 58 | expected: new Decimal(0), 59 | }, 60 | ])("Percentage.toDecimal", ({ p1, expected }) => { 61 | test(`toDecimal(${p1.toString()}) returns {${expected.toString()}}`, () => { 62 | expect(p1.toDecimal()).toEqual(expected); 63 | }); 64 | }); 65 | -------------------------------------------------------------------------------- /test/utils/numbers/decimal-utils.test.ts: -------------------------------------------------------------------------------- 1 | import { u64 } from "@solana/spl-token"; 2 | import Decimal from "decimal.js"; 3 | import { DecimalUtil } from "../../../src/public"; 4 | 5 | /** 6 | * DecimalUtil.fromU64 7 | */ 8 | describe.each([ 9 | { input: new u64("10"), shift: 1, expectedValue: new Decimal(1) }, 10 | { input: new u64("14250748290"), shift: 9, expectedValue: new Decimal(14.25074829) }, 11 | { input: new u64("5"), shift: 3, expectedValue: new Decimal(0.005) }, 12 | { input: new u64("0"), shift: 9, expectedValue: new Decimal(0) }, 13 | { input: new u64("10"), shift: -1, expectedValue: new Decimal(100) }, 14 | ])("DecimalUtil.fromU64", ({ input, shift, expectedValue }) => { 15 | test(`fromU64(${input.toString()}, ${shift}) returns {${expectedValue}}`, () => { 16 | expect(DecimalUtil.fromU64(input, shift)).toEqual(expectedValue); 17 | }); 18 | }); 19 | 20 | describe.each([ 21 | { input: new u64("10"), expectedValue: new Decimal(10) }, 22 | { input: new u64("0"), expectedValue: new Decimal(0) }, 23 | { input: new u64("5"), expectedValue: new Decimal(5) }, 24 | ])("DecimalUtil.fromU64", ({ input, expectedValue }) => { 25 | test(`fromU64(${input.toString()}) returns {${expectedValue}}`, () => { 26 | expect(DecimalUtil.fromU64(input)).toEqual(expectedValue); 27 | }); 28 | }); 29 | 30 | /** 31 | * DecimalUtil.toU64 32 | */ 33 | describe.each([ 34 | { input: new Decimal(10), shift: 0, expectedValue: new u64("10") }, 35 | { input: new Decimal(10), shift: 1, expectedValue: new u64("100") }, 36 | { input: new Decimal(10.5), shift: 1, expectedValue: new u64("105") }, 37 | { input: new Decimal(10.5242425252), shift: 6, expectedValue: new u64("10524242") }, 38 | ])("DecimalUtil.toU64", ({ input, shift, expectedValue }) => { 39 | test(`toU64(${input}, ${shift}) returns {${expectedValue.toString()}}`, () => { 40 | expect(DecimalUtil.toU64(input, shift)).toEqual(expectedValue); 41 | }); 42 | }); 43 | 44 | describe.each([ 45 | { input: new Decimal(10), expectedValue: new u64("10") }, 46 | { input: new Decimal(10.5), expectedValue: new u64("10") }, 47 | ])("DecimalUtil.toU64", ({ input, expectedValue }) => { 48 | test(`toU64(${input}) returns {${expectedValue.toString()}}`, () => { 49 | expect(DecimalUtil.toU64(input)).toEqual(expectedValue); 50 | }); 51 | }); 52 | 53 | describe.each([{ input: new Decimal(-15) }])("DecimalUtil.toU64", ({ input }) => { 54 | test(`toU64(${input}) throws error }`, () => { 55 | expect(() => DecimalUtil.toU64(input)).toThrow(); 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /test/utils/numbers/u64-utils.test.ts: -------------------------------------------------------------------------------- 1 | import { u64 } from "@solana/spl-token"; 2 | import { PublicKey } from "@solana/web3.js"; 3 | import Decimal from "decimal.js"; 4 | import { OrcaToken } from "../../../src"; 5 | import { OrcaU64, U64Utils } from "../../../src/public"; 6 | 7 | const tokenWithScale6: OrcaToken = { 8 | tag: "tag5", 9 | scale: 6, 10 | name: "name", 11 | mint: new PublicKey("Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB"), 12 | }; 13 | 14 | const tokenWithScale8: OrcaToken = { 15 | ...tokenWithScale6, 16 | scale: 8, 17 | }; 18 | 19 | /** 20 | * U64Utils.toTokenU64 21 | */ 22 | describe.each([ 23 | { input: new Decimal(10), token: tokenWithScale6, expectedValue: new u64("10000000") }, 24 | { input: new Decimal(10.5233), token: tokenWithScale6, expectedValue: new u64("10523300") }, 25 | { 26 | input: new OrcaU64(new u64("105234058"), 8), 27 | token: tokenWithScale8, 28 | expectedValue: new u64("105234058"), 29 | }, 30 | ])("U64Utils.toTokenU64", ({ input, token, expectedValue }) => { 31 | test(`toTokenU64(${input.toString()}, ${token.tag} with dec ${ 32 | token.scale 33 | }) returns {${expectedValue}}`, () => { 34 | expect(U64Utils.toTokenU64(input, token, "someVarName")).toEqual(expectedValue); 35 | }); 36 | }); 37 | 38 | describe.each([ 39 | { input: new Decimal(-15), token: tokenWithScale6 }, 40 | { input: new OrcaU64(new u64("15"), 4), token: tokenWithScale6 }, 41 | ])("U64Utils.toTokenU64", ({ input, token }) => { 42 | test(`toTokenU64(${input}) throws error }`, () => { 43 | expect(() => U64Utils.toTokenU64(input, token, "someVarName")).toThrow(); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /tsconfig-base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */ 4 | 5 | /* Basic Options */ 6 | // "incremental": true, /* Enable incremental compilation */ 7 | "target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ 8 | "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ 9 | // "lib": [], /* Specify library files to be included in the compilation. */ 10 | "allowJs": true, /* Allow javascript files to be compiled. */ 11 | // "checkJs": true, /* Report errors in .js files. */ 12 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */ 13 | "declaration": true, /* Generates corresponding '.d.ts' file. */ 14 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 15 | // "sourceMap": true, /* Generates corresponding '.map' file. */ 16 | // "outFile": "./", /* Concatenate and emit output to single file. */ 17 | "outDir": "./dist", /* Redirect output structure to the directory. */ 18 | // "rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 19 | // "composite": true, /* Enable project compilation */ 20 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ 21 | // "removeComments": true, /* Do not emit comments to output. */ 22 | // "noEmit": true, /* Do not emit outputs. */ 23 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 24 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 25 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 26 | 27 | /* Strict Type-Checking Options */ 28 | "strict": true, /* Enable all strict type-checking options. */ 29 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 30 | // "strictNullChecks": true, /* Enable strict null checks. */ 31 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 32 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 33 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 34 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 35 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 36 | 37 | /* Additional Checks */ 38 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 39 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 40 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 41 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 42 | // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ 43 | // "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */ 44 | 45 | /* Module Resolution Options */ 46 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 47 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 48 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 49 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 50 | // "types": [], /* Type declaration files to be included in compilation. */ 51 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 52 | "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 53 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 54 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 55 | 56 | /* Source Map Options */ 57 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 58 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 59 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 60 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 61 | 62 | /* Experimental Options */ 63 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 64 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 65 | 66 | /* Advanced Options */ 67 | "skipLibCheck": true, /* Skip type checking of declaration files. */ 68 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ 69 | } 70 | } 71 | --------------------------------------------------------------------------------