Add function to create single sided Whirlpool

This commit is contained in:
calintje
2024-12-18 05:43:52 +01:00
parent 9dc8d1682c
commit aae026650e
3 changed files with 419 additions and 0 deletions

View File

@@ -15,6 +15,7 @@
"license": "ISC",
"dependencies": {
"@bonfida/spl-name-service": "^3.0.7",
"@coral-xyz/anchor": "0.29",
"@langchain/core": "^0.3.18",
"@langchain/groq": "^0.1.2",
"@langchain/langgraph": "^0.2.27",
@@ -24,9 +25,12 @@
"@metaplex-foundation/umi": "^0.9.2",
"@metaplex-foundation/umi-bundle-defaults": "^0.9.2",
"@metaplex-foundation/umi-web3js-adapters": "^0.9.2",
"@orca-so/common-sdk": "0.6.4",
"@orca-so/whirlpools-sdk": "^0.13.12",
"@solana/spl-token": "^0.4.9",
"@solana/web3.js": "^1.95.4",
"bs58": "^6.0.0",
"decimal.js": "^10.4.3",
"dotenv": "^16.4.5",
"form-data": "^4.0.1",
"langchain": "^0.3.6",

158
pnpm-lock.yaml generated
View File

@@ -11,6 +11,9 @@ importers:
'@bonfida/spl-name-service':
specifier: ^3.0.7
version: 3.0.7(@solana/web3.js@1.95.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10)
'@coral-xyz/anchor':
specifier: '0.29'
version: 0.29.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)
'@langchain/core':
specifier: ^0.3.18
version: 0.3.18(openai@4.75.0(zod@3.23.8))
@@ -38,6 +41,12 @@ importers:
'@metaplex-foundation/umi-web3js-adapters':
specifier: ^0.9.2
version: 0.9.2(@metaplex-foundation/umi@0.9.2)(@solana/web3.js@1.95.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))
'@orca-so/common-sdk':
specifier: 0.6.4
version: 0.6.4(@solana/spl-token@0.4.9(@solana/web3.js@1.95.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10))(@solana/web3.js@1.95.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(decimal.js@10.4.3)
'@orca-so/whirlpools-sdk':
specifier: ^0.13.12
version: 0.13.12(@coral-xyz/anchor@0.29.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@orca-so/common-sdk@0.6.4(@solana/spl-token@0.4.9(@solana/web3.js@1.95.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10))(@solana/web3.js@1.95.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(decimal.js@10.4.3))(@solana/spl-token@0.4.9(@solana/web3.js@1.95.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10))(@solana/web3.js@1.95.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(decimal.js@10.4.3)
'@solana/spl-token':
specifier: ^0.4.9
version: 0.4.9(@solana/web3.js@1.95.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10)
@@ -47,6 +56,9 @@ importers:
bs58:
specifier: ^6.0.0
version: 6.0.0
decimal.js:
specifier: ^10.4.3
version: 10.4.3
dotenv:
specifier: ^16.4.5
version: 16.4.5
@@ -86,6 +98,16 @@ packages:
peerDependencies:
'@solana/web3.js': ^1.87.3
'@coral-xyz/anchor@0.29.0':
resolution: {integrity: sha512-eny6QNG0WOwqV0zQ7cs/b1tIuzZGmP7U7EcH+ogt4Gdbl8HDmIYVMh/9aTmYZPaFWjtUaI8qSn73uYEXWfATdA==}
engines: {node: '>=11'}
'@coral-xyz/borsh@0.29.0':
resolution: {integrity: sha512-s7VFVa3a0oqpkuRloWVPdCK7hMbAMY270geZOGfCnaqexrP5dTIpbEHL33req6IYPPJ0hYa71cdvJ1h6V55/oQ==}
engines: {node: '>=10'}
peerDependencies:
'@solana/web3.js': ^1.68.0
'@cspotcode/source-map-support@0.8.1':
resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
engines: {node: '>=12'}
@@ -241,6 +263,22 @@ packages:
resolution: {integrity: sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==}
engines: {node: ^14.21.3 || >=16}
'@orca-so/common-sdk@0.6.4':
resolution: {integrity: sha512-iOiC6exTA9t2CEOaUPoWlNP3soN/1yZFjoz1mSf7NvOqo/PJZeIdWpB7BRXwU0mGGatjxU4SFgMGQ8NrSx+ONw==}
peerDependencies:
'@solana/spl-token': ^0.4.1
'@solana/web3.js': ^1.90.0
decimal.js: ^10.4.3
'@orca-so/whirlpools-sdk@0.13.12':
resolution: {integrity: sha512-+LOqGTe0DYUsYwemltOU4WQIviqoICQlIcAmmEX/WnBh6wntpcLDcXkPV6dBHW7NA2/J8WEVAZ50biLJb4subg==}
peerDependencies:
'@coral-xyz/anchor': ~0.29.0
'@orca-so/common-sdk': 0.6.4
'@solana/spl-token': ^0.4.8
'@solana/web3.js': ^1.90.0
decimal.js: ^10.4.3
'@scure/base@1.1.9':
resolution: {integrity: sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==}
@@ -511,6 +549,10 @@ packages:
bs58@6.0.0:
resolution: {integrity: sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==}
buffer-layout@1.2.2:
resolution: {integrity: sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA==}
engines: {node: '>=4.5'}
buffer@6.0.3:
resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
@@ -556,10 +598,20 @@ packages:
create-require@1.1.1:
resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==}
cross-fetch@3.1.8:
resolution: {integrity: sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==}
crypto-hash@1.3.0:
resolution: {integrity: sha512-lyAZ0EMyjDkVvz8WOeVnuCPvKVBXcMv1l5SVqO1yC7PzTwrD/pPje/BIRbWhMoPe436U+Y2nD7f5bFx0kt+Sbg==}
engines: {node: '>=8'}
decamelize@1.2.0:
resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==}
engines: {node: '>=0.10.0'}
decimal.js@10.4.3:
resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==}
delay@5.0.0:
resolution: {integrity: sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==}
engines: {node: '>=10'}
@@ -579,6 +631,9 @@ packages:
resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==}
engines: {node: '>=0.3.1'}
dot-case@3.0.4:
resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==}
dotenv@16.4.5:
resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==}
engines: {node: '>=12'}
@@ -752,6 +807,9 @@ packages:
linkify-it@5.0.0:
resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==}
lower-case@2.0.2:
resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==}
lunr@2.3.9:
resolution: {integrity: sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==}
@@ -802,6 +860,9 @@ packages:
resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==}
hasBin: true
no-case@3.0.4:
resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==}
node-domexception@1.0.0:
resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
engines: {node: '>=10.5.0'}
@@ -853,6 +914,9 @@ packages:
pako@0.2.9:
resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==}
pako@2.1.0:
resolution: {integrity: sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==}
property-information@6.5.0:
resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==}
@@ -897,12 +961,18 @@ packages:
shiki@1.23.0:
resolution: {integrity: sha512-xfdu9DqPkIpExH29cmiTlgo0/jBki5la1Tkfhsv+Wu5TT3APLNHslR1acxuKJOCWqVdSc+pIbs/2ozjVRGppdg==}
snake-case@3.0.4:
resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==}
space-separated-tokens@2.0.2:
resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==}
stringify-entities@4.0.4:
resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==}
superstruct@0.15.5:
resolution: {integrity: sha512-4AOeU+P5UuE/4nOUkmcQdW5y7i9ndt1cQd/3iUe+LTz3RxESf/W/5lg4B74HbDMMv8PHnPnGCQFH45kBcrQYoQ==}
superstruct@2.0.2:
resolution: {integrity: sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==}
engines: {node: '>=14.0.0'}
@@ -916,6 +986,12 @@ packages:
tiny-inflate@1.0.3:
resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==}
tiny-invariant@1.3.3:
resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==}
toml@3.0.0:
resolution: {integrity: sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==}
tr46@0.0.3:
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
@@ -1093,6 +1169,33 @@ snapshots:
- typescript
- utf-8-validate
'@coral-xyz/anchor@0.29.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)':
dependencies:
'@coral-xyz/borsh': 0.29.0(@solana/web3.js@1.95.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))
'@noble/hashes': 1.5.0
'@solana/web3.js': 1.95.4(bufferutil@4.0.8)(utf-8-validate@5.0.10)
bn.js: 5.2.1
bs58: 4.0.1
buffer-layout: 1.2.2
camelcase: 6.3.0
cross-fetch: 3.1.8
crypto-hash: 1.3.0
eventemitter3: 4.0.7
pako: 2.1.0
snake-case: 3.0.4
superstruct: 0.15.5
toml: 3.0.0
transitivePeerDependencies:
- bufferutil
- encoding
- utf-8-validate
'@coral-xyz/borsh@0.29.0(@solana/web3.js@1.95.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))':
dependencies:
'@solana/web3.js': 1.95.4(bufferutil@4.0.8)(utf-8-validate@5.0.10)
bn.js: 5.2.1
buffer-layout: 1.2.2
'@cspotcode/source-map-support@0.8.1':
dependencies:
'@jridgewell/trace-mapping': 0.3.9
@@ -1283,6 +1386,22 @@ snapshots:
'@noble/hashes@1.5.0': {}
'@orca-so/common-sdk@0.6.4(@solana/spl-token@0.4.9(@solana/web3.js@1.95.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10))(@solana/web3.js@1.95.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(decimal.js@10.4.3)':
dependencies:
'@solana/spl-token': 0.4.9(@solana/web3.js@1.95.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10)
'@solana/web3.js': 1.95.4(bufferutil@4.0.8)(utf-8-validate@5.0.10)
decimal.js: 10.4.3
tiny-invariant: 1.3.3
'@orca-so/whirlpools-sdk@0.13.12(@coral-xyz/anchor@0.29.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@orca-so/common-sdk@0.6.4(@solana/spl-token@0.4.9(@solana/web3.js@1.95.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10))(@solana/web3.js@1.95.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(decimal.js@10.4.3))(@solana/spl-token@0.4.9(@solana/web3.js@1.95.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10))(@solana/web3.js@1.95.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(decimal.js@10.4.3)':
dependencies:
'@coral-xyz/anchor': 0.29.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)
'@orca-so/common-sdk': 0.6.4(@solana/spl-token@0.4.9(@solana/web3.js@1.95.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10))(@solana/web3.js@1.95.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(decimal.js@10.4.3)
'@solana/spl-token': 0.4.9(@solana/web3.js@1.95.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10)
'@solana/web3.js': 1.95.4(bufferutil@4.0.8)(utf-8-validate@5.0.10)
decimal.js: 10.4.3
tiny-invariant: 1.3.3
'@scure/base@1.1.9': {}
'@shikijs/core@1.23.0':
@@ -1648,6 +1767,8 @@ snapshots:
dependencies:
base-x: 5.0.0
buffer-layout@1.2.2: {}
buffer@6.0.3:
dependencies:
base64-js: 1.5.1
@@ -1682,8 +1803,18 @@ snapshots:
create-require@1.1.1: {}
cross-fetch@3.1.8:
dependencies:
node-fetch: 2.7.0
transitivePeerDependencies:
- encoding
crypto-hash@1.3.0: {}
decamelize@1.2.0: {}
decimal.js@10.4.3: {}
delay@5.0.0: {}
delayed-stream@1.0.0: {}
@@ -1696,6 +1827,11 @@ snapshots:
diff@4.0.2: {}
dot-case@3.0.4:
dependencies:
no-case: 3.0.4
tslib: 2.8.1
dotenv@16.4.5: {}
emoji-regex-xs@1.0.0: {}
@@ -1859,6 +1995,10 @@ snapshots:
dependencies:
uc.micro: 2.1.0
lower-case@2.0.2:
dependencies:
tslib: 2.8.1
lunr@2.3.9: {}
make-error@1.3.6: {}
@@ -1917,6 +2057,11 @@ snapshots:
mustache@4.2.0: {}
no-case@3.0.4:
dependencies:
lower-case: 2.0.2
tslib: 2.8.1
node-domexception@1.0.0: {}
node-fetch@2.7.0:
@@ -1966,6 +2111,8 @@ snapshots:
pako@0.2.9: {}
pako@2.1.0: {}
property-information@6.5.0: {}
proxy-from-env@1.1.0:
@@ -2013,6 +2160,11 @@ snapshots:
'@shikijs/vscode-textmate': 9.3.0
'@types/hast': 3.0.4
snake-case@3.0.4:
dependencies:
dot-case: 3.0.4
tslib: 2.8.1
space-separated-tokens@2.0.2: {}
stringify-entities@4.0.4:
@@ -2020,6 +2172,8 @@ snapshots:
character-entities-html4: 2.1.0
character-entities-legacy: 3.0.0
superstruct@0.15.5: {}
superstruct@2.0.2: {}
text-encoding-utf-8@1.0.2: {}
@@ -2028,6 +2182,10 @@ snapshots:
tiny-inflate@1.0.3: {}
tiny-invariant@1.3.3: {}
toml@3.0.0: {}
tr46@0.0.3: {}
trim-lines@3.0.1: {}

View File

@@ -0,0 +1,257 @@
import { Keypair, PublicKey } from "@solana/web3.js";
import { SolanaAgentKit } from "../agent";
import { BN, Wallet } from "@coral-xyz/anchor";
import { Decimal } from "decimal.js";
import { PDAUtil, ORCA_WHIRLPOOL_PROGRAM_ID, ORCA_WHIRLPOOLS_CONFIG, WhirlpoolContext, TickUtil, PriceMath, PoolUtil, TokenExtensionContextForPool, NO_TOKEN_EXTENSION_CONTEXT, TokenExtensionUtil, WhirlpoolIx, IncreaseLiquidityQuoteParam, increaseLiquidityQuoteByInputTokenWithParams } from "@orca-so/whirlpools-sdk";
import { Percentage, resolveOrCreateATAs, TransactionBuilder } from "@orca-so/common-sdk";
import { increaseLiquidityIx, increaseLiquidityV2Ix, initTickArrayIx, openPositionWithTokenExtensionsIx } from "@orca-so/whirlpools-sdk/dist/instructions";
import { getAssociatedTokenAddressSync, TOKEN_2022_PROGRAM_ID } from "@solana/spl-token";
const FEE_TIERS = {
0.01: 1,
0.02: 2,
0.04: 4,
0.05: 8,
0.16: 16,
0.30: 64,
0.65: 96,
1.00: 128,
2.00: 256,
} as const;
type FeeTierPercentage = keyof typeof FEE_TIERS;
export async function createOrcaSingleSidedWhirlpool(
agent: SolanaAgentKit,
depositTokenAmount: Decimal,
depositTokenMint: PublicKey,
otherTokenMint: PublicKey,
initialPrice: Decimal,
upperPrice: Decimal,
feeTier: FeeTierPercentage,
): Promise<string> {
const wallet = new Wallet(agent.wallet);
const ctx = WhirlpoolContext.from(agent.connection, wallet, ORCA_WHIRLPOOL_PROGRAM_ID);
const fetcher = ctx.fetcher;
const correctTokenOrder = PoolUtil.orderMints(otherTokenMint, depositTokenMint).map(
(addr) => addr.toString(),
);
const inverseOrder = correctTokenOrder[0] !== otherTokenMint.toString();
let mintA, mintB;
if (!inverseOrder) {
[mintA, mintB] = [otherTokenMint, depositTokenMint];
} else {
[mintA, mintB] = [depositTokenMint, otherTokenMint];
initialPrice = new Decimal(1 / initialPrice.toNumber());
upperPrice = new Decimal(1 / upperPrice.toNumber());
}
const mintAAccount = await fetcher.getMintInfo(otherTokenMint);
const mintBAccount = await fetcher.getMintInfo(depositTokenMint);
if (mintAAccount === null || mintBAccount === null) throw Error('Mint account not found');
const tickSpacing = FEE_TIERS[feeTier];
const tickIndex = PriceMath.priceToTickIndex(initialPrice, mintAAccount.decimals, mintBAccount.decimals);
const initialTick = TickUtil.getInitializableTickIndex(tickIndex, tickSpacing);
if (!TickUtil.checkTickInBounds(initialTick)) throw Error('Initial tick is out of bounds');
const tokenExtensionCtx: TokenExtensionContextForPool = {
...NO_TOKEN_EXTENSION_CONTEXT,
tokenMintWithProgramA: mintAAccount,
tokenMintWithProgramB: mintBAccount,
};
const feeTierKey = PDAUtil.getFeeTier(
ORCA_WHIRLPOOL_PROGRAM_ID,
ORCA_WHIRLPOOLS_CONFIG,
tickSpacing,
).publicKey;
const initSqrtPrice = PriceMath.tickIndexToSqrtPriceX64(initialTick);
const tokenVaultAKeypair = Keypair.generate();
const tokenVaultBKeypair = Keypair.generate();
const whirlpoolPda = PDAUtil.getWhirlpool(
ORCA_WHIRLPOOL_PROGRAM_ID,
ORCA_WHIRLPOOLS_CONFIG,
mintA,
mintB,
FEE_TIERS[feeTier],
);
const txBuilder = new TransactionBuilder(
ctx.provider.connection,
ctx.provider.wallet,
ctx.txBuilderOpts,
);
const tokenBadgeA = PDAUtil.getTokenBadge(
ORCA_WHIRLPOOL_PROGRAM_ID,
ORCA_WHIRLPOOLS_CONFIG,
mintA,
).publicKey;
const tokenBadgeB = PDAUtil.getTokenBadge(
ORCA_WHIRLPOOL_PROGRAM_ID,
ORCA_WHIRLPOOLS_CONFIG,
mintB,
).publicKey;
const baseParamsPool = {
initSqrtPrice,
whirlpoolsConfig: ORCA_WHIRLPOOLS_CONFIG,
whirlpoolPda,
tokenMintA: mintA,
tokenMintB: mintB,
tokenVaultAKeypair,
tokenVaultBKeypair,
feeTierKey,
tickSpacing: tickSpacing,
funder: wallet.publicKey
};
const initPoolIx = !TokenExtensionUtil.isV2IxRequiredPool(tokenExtensionCtx)
? WhirlpoolIx.initializePoolIx(ctx.program, baseParamsPool)
: WhirlpoolIx.initializePoolV2Ix(ctx.program, {
...baseParamsPool,
tokenProgramA: tokenExtensionCtx.tokenMintWithProgramA.tokenProgram,
tokenProgramB: tokenExtensionCtx.tokenMintWithProgramB.tokenProgram,
tokenBadgeA,
tokenBadgeB,
});
const initialTickArrayStartTick = TickUtil.getStartTickIndex(
initialTick,
tickSpacing,
);
const initialTickArrayPda = PDAUtil.getTickArray(
ctx.program.programId,
whirlpoolPda.publicKey,
initialTickArrayStartTick,
);
txBuilder.addInstruction(initPoolIx);
txBuilder.addInstruction(
initTickArrayIx(ctx.program, {
startTick: initialTickArrayStartTick,
tickArrayPda: initialTickArrayPda,
whirlpool: whirlpoolPda.publicKey,
funder: wallet.publicKey,
}),
);
const tickLowerIndex = inverseOrder ? initialTick - tickSpacing : initialTick + tickSpacing;
const tickUpperIndex = PriceMath.priceToTickIndex(upperPrice, mintAAccount.decimals, mintBAccount.decimals);
const tickLowerInitializableIndex = TickUtil.getInitializableTickIndex(tickLowerIndex, tickSpacing);
const tickUpperInitializableIndex = TickUtil.getInitializableTickIndex(tickUpperIndex, tickSpacing);
const increasLiquidityQuoteParam: IncreaseLiquidityQuoteParam = {
inputTokenAmount: BN(depositTokenAmount),
inputTokenMint: depositTokenMint,
tokenMintA: mintA,
tokenMintB: mintB,
tickCurrentIndex: initialTick,
sqrtPrice: initSqrtPrice,
tickLowerIndex: tickLowerInitializableIndex,
tickUpperIndex: tickUpperInitializableIndex,
tokenExtensionCtx: tokenExtensionCtx,
slippageTolerance: Percentage.fromFraction(0, 100)
}
const liquidityInput = increaseLiquidityQuoteByInputTokenWithParams(
increasLiquidityQuoteParam
)
const { liquidityAmount: liquidity, tokenMaxA, tokenMaxB } = liquidityInput;
const positionMintKeypair = Keypair.generate();
const positionMintPubkey = positionMintKeypair.publicKey;
const positionPda = PDAUtil.getPosition(
ORCA_WHIRLPOOL_PROGRAM_ID,
positionMintPubkey,
);
const positionTokenAccountAddress = getAssociatedTokenAddressSync(
positionMintPubkey,
wallet.publicKey,
ctx.accountResolverOpts.allowPDAOwnerAddress,
TOKEN_2022_PROGRAM_ID,
);
const params = {
funder: wallet.publicKey,
owner: wallet.publicKey,
positionPda,
positionTokenAccount: positionTokenAccountAddress,
whirlpool: whirlpoolPda.publicKey,
tickLowerIndex: tickLowerInitializableIndex,
tickUpperIndex: tickUpperInitializableIndex,
};
const positionIx = openPositionWithTokenExtensionsIx(ctx.program, {
...params,
positionMint: positionMintPubkey,
withTokenMetadataExtension: true,
})
txBuilder.addInstruction(positionIx);
txBuilder.addSigner(positionMintKeypair);
const [ataA, ataB] = await resolveOrCreateATAs(
ctx.connection,
wallet.publicKey,
[
{ tokenMint: mintA, wrappedSolAmountIn: tokenMaxA },
{ tokenMint: mintB, wrappedSolAmountIn: tokenMaxB },
],
() => ctx.fetcher.getAccountRentExempt(),
wallet.publicKey,
undefined,
ctx.accountResolverOpts.allowPDAOwnerAddress,
ctx.accountResolverOpts.createWrappedSolAccountMethod,
);
const { address: tokenOwnerAccountA, ...tokenOwnerAccountAIx } = ataA;
const { address: tokenOwnerAccountB, ...tokenOwnerAccountBIx } = ataB;
txBuilder.addInstruction(tokenOwnerAccountAIx);
txBuilder.addInstruction(tokenOwnerAccountBIx);
const tickArrayLowerPda = PDAUtil.getTickArrayFromTickIndex(
tickLowerInitializableIndex,
tickSpacing,
whirlpoolPda.publicKey,
ctx.program.programId,
);
const tickArrayUpperPda = PDAUtil.getTickArrayFromTickIndex(
tickUpperInitializableIndex,
tickSpacing,
whirlpoolPda.publicKey,
ctx.program.programId,
);
const baseParamsLiquidity = {
liquidityAmount: liquidity,
tokenMaxA,
tokenMaxB,
whirlpool: whirlpoolPda.publicKey,
positionAuthority: wallet.publicKey,
position: positionPda.publicKey,
positionTokenAccount: positionTokenAccountAddress,
tokenOwnerAccountA,
tokenOwnerAccountB,
tokenVaultA: tokenVaultAKeypair.publicKey,
tokenVaultB: tokenVaultBKeypair.publicKey,
tickArrayLower: tickArrayLowerPda.publicKey,
tickArrayUpper: tickArrayUpperPda.publicKey,
};
const liquidityIx = !TokenExtensionUtil.isV2IxRequiredPool(
tokenExtensionCtx,
)
? increaseLiquidityIx(ctx.program, baseParamsLiquidity)
: increaseLiquidityV2Ix(ctx.program, {
...baseParamsLiquidity,
tokenMintA: mintA,
tokenMintB: mintB,
tokenProgramA: tokenExtensionCtx.tokenMintWithProgramA.tokenProgram,
tokenProgramB: tokenExtensionCtx.tokenMintWithProgramB.tokenProgram,
});
txBuilder.addInstruction(liquidityIx);
const txId = await txBuilder.buildAndExecute();
return txId;
}