diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ddfc583..1270412 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -22,7 +22,7 @@ importers: version: 0.1.2(@langchain/core@0.3.26(openai@4.77.0(zod@3.24.1))) '@langchain/langgraph': specifier: ^0.2.27 - version: 0.2.34(@langchain/core@0.3.26(openai@4.77.0(zod@3.24.1))) + version: 0.2.36(@langchain/core@0.3.26(openai@4.77.0(zod@3.24.1))) '@langchain/openai': specifier: ^0.3.13 version: 0.3.16(@langchain/core@0.3.26(openai@4.77.0(zod@3.24.1))) @@ -91,7 +91,7 @@ importers: version: 4.0.1 langchain: specifier: ^0.3.6 - version: 0.3.7(@langchain/core@0.3.26(openai@4.77.0(zod@3.24.1)))(@langchain/groq@0.1.2(@langchain/core@0.3.26(openai@4.77.0(zod@3.24.1))))(axios@1.7.9)(openai@4.77.0(zod@3.24.1)) + version: 0.3.8(@langchain/core@0.3.26(openai@4.77.0(zod@3.24.1)))(@langchain/groq@0.1.2(@langchain/core@0.3.26(openai@4.77.0(zod@3.24.1))))(axios@1.7.9)(openai@4.77.0(zod@3.24.1)) openai: specifier: ^4.75.0 version: 4.77.0(zod@3.24.1) @@ -235,8 +235,8 @@ packages: '@langchain/langgraph-sdk@0.0.32': resolution: {integrity: sha512-KQyM9kLO7T6AxwNrceajH7JOybP3pYpvUPnhiI2rrVndI1WyZUJ1eVC1e722BVRAPi6o+WcoTT4uMSZVinPOtA==} - '@langchain/langgraph@0.2.34': - resolution: {integrity: sha512-fSlmLYre+Skh5XJgBGe5YRtXaHyGMTlhu5UN3LzIgA3E9CmGODvH+Ydyk5vJzhXMjnPpLr8icqlKxKrYmZ3gTw==} + '@langchain/langgraph@0.2.36': + resolution: {integrity: sha512-zxk7ZCVxP0/Ut9785EiXCS7BE7sXd8cu943mcZUF2aNFUaQRTBbbiKpNdR3nb1+xO/B+HVktrJT2VFdkAywnng==} engines: {node: '>=18'} peerDependencies: '@langchain/core': '>=0.2.36 <0.3.0 || >=0.3.9 < 0.4.0' @@ -433,17 +433,17 @@ packages: '@scure/base@1.2.1': resolution: {integrity: sha512-DGmGtC8Tt63J5GfHgfl5CuAXh96VF/LD8K9Hr/Gv0J2lAoRGlPOMpqMpMbCTOoOJMZCk2Xt+DskdDyn6dEFdzQ==} - '@shikijs/core@1.24.3': - resolution: {integrity: sha512-VRcf4GYUIkxIchGM9DrapRcxtgojg4IWKUtX5EtW+4PJiGzF2xQqZSv27PJt+WLc18KT3CNLpNWow9JYV5n+Rg==} + '@shikijs/core@1.24.4': + resolution: {integrity: sha512-jjLsld+xEEGYlxAXDyGwWsKJ1sw5Pc1pnp4ai2ORpjx2UX08YYTC0NNqQYO1PaghYaR+PvgMOGuvzw2he9sk0Q==} - '@shikijs/engine-javascript@1.24.3': - resolution: {integrity: sha512-De8tNLvYjeK6V0Gb47jIH2M+OKkw+lWnSV1j3HVDFMlNIglmVcTMG2fASc29W0zuFbfEEwKjO8Fe4KYSO6Ce3w==} + '@shikijs/engine-javascript@1.24.4': + resolution: {integrity: sha512-TClaQOLvo9WEMJv6GoUsykQ6QdynuKszuORFWCke8qvi6PeLm7FcD9+7y45UenysxEWYpDL5KJaVXTngTE+2BA==} - '@shikijs/engine-oniguruma@1.24.3': - resolution: {integrity: sha512-iNnx950gs/5Nk+zrp1LuF+S+L7SKEhn8k9eXgFYPGhVshKppsYwRmW8tpmAMvILIMSDfrgqZ0w+3xWVQB//1Xw==} + '@shikijs/engine-oniguruma@1.24.4': + resolution: {integrity: sha512-Do2ry6flp2HWdvpj2XOwwa0ljZBRy15HKZITzPcNIBOGSeprnA8gOooA/bLsSPuy8aJBa+Q/r34dMmC3KNL/zw==} - '@shikijs/types@1.24.3': - resolution: {integrity: sha512-FPMrJ69MNxhRtldRk69CghvaGlbbN3pKRuvko0zvbfa2dXp4pAngByToqS5OY5jvN8D7LKR4RJE8UvzlCOuViw==} + '@shikijs/types@1.24.4': + resolution: {integrity: sha512-0r0XU7Eaow0PuDxuWC1bVqmWCgm3XqizIaT7SM42K03vc69LGooT0U8ccSR44xP/hGlNx4FKhtYpV+BU6aaKAA==} '@shikijs/vscode-textmate@9.3.1': resolution: {integrity: sha512-79QfK1393x9Ho60QFyLti+QfdJzRQCVLFb97kOIV7Eo9vQU/roINgk7m24uv0a7AUvN//RDH36FLjjK48v0s9g==} @@ -908,8 +908,8 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} - chalk@5.4.0: - resolution: {integrity: sha512-ZkD35Mx92acjB2yNJgziGqT9oKHEOxjTBTDRpOsRWtdecL/0jM3z5kM/CTzHWvHIen1GvkM85p6TuFfDGfc8/Q==} + chalk@5.4.1: + resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} character-entities-html4@2.1.0: @@ -953,8 +953,8 @@ 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==} + cross-fetch@3.2.0: + resolution: {integrity: sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==} cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} @@ -1406,8 +1406,8 @@ packages: keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - langchain@0.3.7: - resolution: {integrity: sha512-6/Gkk9Zez3HkbsETFxZVo1iKLmaK3OzkDseC5MYFKVmYFDXFAOyJR3srJ9P61xF8heVdsPixqYIsejBn7/9dXg==} + langchain@0.3.8: + resolution: {integrity: sha512-EiAHFgBdThuXFmIx9j81wjdPItpRsw0Ck4r5dyhB74gyhehRGna/UK2CTqeKVnIUM/f4g4JbxUgAU4voXljDMw==} engines: {node: '>=18'} peerDependencies: '@langchain/anthropic': '*' @@ -1452,8 +1452,8 @@ packages: typeorm: optional: true - langsmith@0.2.13: - resolution: {integrity: sha512-16EOM5nhU6GlMCKGm5sgBIAKOKzS2d30qcDZmF21kSLZJiUhUNTROwvYdqgZLrGfIIzmSMJHCKA7RFd5qf50uw==} + langsmith@0.2.14: + resolution: {integrity: sha512-ClAuAgSf3m9miMYotLEaZKQyKdaWlfjhebCuYco8bc6g72dU2VwTg31Bv4YINBq7EH2i1cMwbOiJxbOXPqjGig==} peerDependencies: openai: '*' peerDependenciesMeta: @@ -1592,8 +1592,8 @@ packages: once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - oniguruma-to-es@0.8.0: - resolution: {integrity: sha512-rY+/a6b+uCgoYIL9itjY0x99UUDHXmGaw7Jjk5ZvM/3cxDJifyxFr/Zm4tTmF6Tre18gAakJo7AzhKUeMNLgHA==} + oniguruma-to-es@0.8.1: + resolution: {integrity: sha512-dekySTEvCxCj0IgKcA2uUCO/e4ArsqpucDPcX26w9ajx+DvMWLc5eZeJaRQkd7oC/+rwif5gnT900tA34uN9Zw==} openai@4.77.0: resolution: {integrity: sha512-WWacavtns/7pCUkOWvQIjyOfcdr9X+9n9Vvb0zFeKVDAqwCMDHB+iSr24SVaBAhplvSG6JrRXFpcNM9gWhOGIw==} @@ -1706,14 +1706,14 @@ packages: regenerator-runtime@0.14.1: resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} - regex-recursion@5.0.0: - resolution: {integrity: sha512-UwyOqeobrCCqTXPcsSqH4gDhOjD5cI/b8kjngWgSZbxYh5yVjAwTjO5+hAuPRNiuR70+5RlWSs+U9PVcVcW9Lw==} + regex-recursion@5.1.1: + resolution: {integrity: sha512-ae7SBCbzVNrIjgSbh7wMznPcQel1DNlDtzensnFxpiNpXt1U2ju/bHugH422r+4LAVS1FpW1YCwilmnNsjum9w==} regex-utilities@2.3.0: resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==} - regex@5.0.2: - resolution: {integrity: sha512-/pczGbKIQgfTMRV0XjABvc5RzLqQmwqxLHdQao2RTXPk+pmTXB2P0IaUHYdYyk412YLwUIkaeMd5T+RzVgTqnQ==} + regex@5.1.1: + resolution: {integrity: sha512-dN5I359AVGPnwzJm2jN1k0W9LPZ+ePvoOeVMMfqIMFz53sSwXkxaJoxr50ptnsC771lK95BnTrVSZxq0b9yCGw==} resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} @@ -1758,8 +1758,8 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - shiki@1.24.3: - resolution: {integrity: sha512-eMeX/ehE2IDKVs71kB4zVcDHjutNcOtm+yIRuR4sA6ThBbdFI0DffGJiyoKCodj0xRGxIoWC3pk/Anmm5mzHmA==} + shiki@1.24.4: + resolution: {integrity: sha512-aVGSFAOAr1v26Hh/+GBIsRVDWJ583XYV7CuNURKRWh9gpGv4OdbisZGq96B9arMYTZhTQkmRF5BrShOSTvNqhw==} slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} @@ -2068,7 +2068,7 @@ snapshots: bs58: 4.0.1 buffer-layout: 1.2.2 camelcase: 6.3.0 - cross-fetch: 3.1.8 + cross-fetch: 3.2.0 crypto-hash: 1.3.0 eventemitter3: 4.0.7 pako: 2.1.0 @@ -2153,7 +2153,7 @@ snapshots: camelcase: 6.3.0 decamelize: 1.2.0 js-tiktoken: 1.0.16 - langsmith: 0.2.13(openai@4.77.0(zod@3.24.1)) + langsmith: 0.2.14(openai@4.77.0(zod@3.24.1)) mustache: 4.2.0 p-queue: 6.6.2 p-retry: 4.6.2 @@ -2185,7 +2185,7 @@ snapshots: p-retry: 4.6.2 uuid: 9.0.1 - '@langchain/langgraph@0.2.34(@langchain/core@0.3.26(openai@4.77.0(zod@3.24.1)))': + '@langchain/langgraph@0.2.36(@langchain/core@0.3.26(openai@4.77.0(zod@3.24.1)))': dependencies: '@langchain/core': 0.3.26(openai@4.77.0(zod@3.24.1)) '@langchain/langgraph-checkpoint': 0.0.13(@langchain/core@0.3.26(openai@4.77.0(zod@3.24.1))) @@ -2463,27 +2463,27 @@ snapshots: '@scure/base@1.2.1': {} - '@shikijs/core@1.24.3': + '@shikijs/core@1.24.4': dependencies: - '@shikijs/engine-javascript': 1.24.3 - '@shikijs/engine-oniguruma': 1.24.3 - '@shikijs/types': 1.24.3 + '@shikijs/engine-javascript': 1.24.4 + '@shikijs/engine-oniguruma': 1.24.4 + '@shikijs/types': 1.24.4 '@shikijs/vscode-textmate': 9.3.1 '@types/hast': 3.0.4 hast-util-to-html: 9.0.4 - '@shikijs/engine-javascript@1.24.3': + '@shikijs/engine-javascript@1.24.4': dependencies: - '@shikijs/types': 1.24.3 + '@shikijs/types': 1.24.4 '@shikijs/vscode-textmate': 9.3.1 - oniguruma-to-es: 0.8.0 + oniguruma-to-es: 0.8.1 - '@shikijs/engine-oniguruma@1.24.3': + '@shikijs/engine-oniguruma@1.24.4': dependencies: - '@shikijs/types': 1.24.3 + '@shikijs/types': 1.24.4 '@shikijs/vscode-textmate': 9.3.1 - '@shikijs/types@1.24.3': + '@shikijs/types@1.24.4': dependencies: '@shikijs/vscode-textmate': 9.3.1 '@types/hast': 3.0.4 @@ -2613,18 +2613,18 @@ snapshots: '@solana/errors@2.0.0-preview.2': dependencies: - chalk: 5.4.0 + chalk: 5.4.1 commander: 12.1.0 '@solana/errors@2.0.0-preview.4(typescript@5.7.2)': dependencies: - chalk: 5.4.0 + chalk: 5.4.1 commander: 12.1.0 typescript: 5.7.2 '@solana/errors@2.0.0-rc.1(typescript@5.7.2)': dependencies: - chalk: 5.4.0 + chalk: 5.4.1 commander: 12.1.0 typescript: 5.7.2 @@ -3123,7 +3123,7 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 - chalk@5.4.0: {} + chalk@5.4.1: {} character-entities-html4@2.1.0: {} @@ -3153,7 +3153,7 @@ snapshots: create-require@1.1.1: {} - cross-fetch@3.1.8: + cross-fetch@3.2.0: dependencies: node-fetch: 2.7.0 transitivePeerDependencies: @@ -3634,7 +3634,7 @@ snapshots: dependencies: json-buffer: 3.0.1 - langchain@0.3.7(@langchain/core@0.3.26(openai@4.77.0(zod@3.24.1)))(@langchain/groq@0.1.2(@langchain/core@0.3.26(openai@4.77.0(zod@3.24.1))))(axios@1.7.9)(openai@4.77.0(zod@3.24.1)): + langchain@0.3.8(@langchain/core@0.3.26(openai@4.77.0(zod@3.24.1)))(@langchain/groq@0.1.2(@langchain/core@0.3.26(openai@4.77.0(zod@3.24.1))))(axios@1.7.9)(openai@4.77.0(zod@3.24.1)): dependencies: '@langchain/core': 0.3.26(openai@4.77.0(zod@3.24.1)) '@langchain/openai': 0.3.16(@langchain/core@0.3.26(openai@4.77.0(zod@3.24.1))) @@ -3642,7 +3642,7 @@ snapshots: js-tiktoken: 1.0.16 js-yaml: 4.1.0 jsonpointer: 5.0.1 - langsmith: 0.2.13(openai@4.77.0(zod@3.24.1)) + langsmith: 0.2.14(openai@4.77.0(zod@3.24.1)) openapi-types: 12.1.3 p-retry: 4.6.2 uuid: 10.0.0 @@ -3656,7 +3656,7 @@ snapshots: - encoding - openai - langsmith@0.2.13(openai@4.77.0(zod@3.24.1)): + langsmith@0.2.14(openai@4.77.0(zod@3.24.1)): dependencies: '@types/uuid': 10.0.0 commander: 10.0.1 @@ -3801,11 +3801,11 @@ snapshots: dependencies: wrappy: 1.0.2 - oniguruma-to-es@0.8.0: + oniguruma-to-es@0.8.1: dependencies: emoji-regex-xs: 1.0.0 - regex: 5.0.2 - regex-recursion: 5.0.0 + regex: 5.1.1 + regex-recursion: 5.1.1 openai@4.77.0(zod@3.24.1): dependencies: @@ -3898,13 +3898,14 @@ snapshots: regenerator-runtime@0.14.1: {} - regex-recursion@5.0.0: + regex-recursion@5.1.1: dependencies: + regex: 5.1.1 regex-utilities: 2.3.0 regex-utilities@2.3.0: {} - regex@5.0.2: + regex@5.1.1: dependencies: regex-utilities: 2.3.0 @@ -3954,12 +3955,12 @@ snapshots: shebang-regex@3.0.0: {} - shiki@1.24.3: + shiki@1.24.4: dependencies: - '@shikijs/core': 1.24.3 - '@shikijs/engine-javascript': 1.24.3 - '@shikijs/engine-oniguruma': 1.24.3 - '@shikijs/types': 1.24.3 + '@shikijs/core': 1.24.4 + '@shikijs/engine-javascript': 1.24.4 + '@shikijs/engine-oniguruma': 1.24.4 + '@shikijs/types': 1.24.4 '@shikijs/vscode-textmate': 9.3.1 '@types/hast': 3.0.4 @@ -4065,7 +4066,7 @@ snapshots: lunr: 2.3.9 markdown-it: 14.1.0 minimatch: 9.0.5 - shiki: 1.24.3 + shiki: 1.24.4 typescript: 5.7.2 yaml: 2.6.1 diff --git a/src/agent/index.ts b/src/agent/index.ts index 56f66f4..b39eaa7 100644 --- a/src/agent/index.ts +++ b/src/agent/index.ts @@ -24,10 +24,12 @@ import { getTokenDataByTicker, stakeWithJup, sendCompressedAirdrop, - createOrcaSingleSidedWhirlpool, + orcaCreateSingleSidedLiquidityPool, + orcaCreateCLMM, + orcaOpenCenteredPositionWithLiquidity, + FEE_TIERS, fetchPrice, pythFetchPrice, - FEE_TIERS, getAllDomainsTLDs, getAllRegisteredAllDomains, getOwnedDomainsForTLD, @@ -36,6 +38,7 @@ import { resolveAllDomains, create_gibwork_task, } from "../tools"; + import { CollectionDeployment, CollectionOptions, @@ -199,7 +202,22 @@ export class SolanaAgentKit { ); } - async createOrcaSingleSidedWhirlpool( + async orcaCreateCLMM( + mintA: PublicKey, + mintB: PublicKey, + initialPrice: Decimal, + feeTier: keyof typeof FEE_TIERS, + ) { + return orcaCreateCLMM( + this, + mintA, + mintB, + initialPrice, + feeTier, + ); + } + + async orcaCreateSingleSidedLiquidityPool( depositTokenAmount: BN, depositTokenMint: PublicKey, otherTokenMint: PublicKey, @@ -207,7 +225,7 @@ export class SolanaAgentKit { maxPrice: Decimal, feeTier: keyof typeof FEE_TIERS, ) { - return createOrcaSingleSidedWhirlpool( + return orcaCreateSingleSidedLiquidityPool( this, depositTokenAmount, depositTokenMint, @@ -218,6 +236,21 @@ export class SolanaAgentKit { ); } + async orcaOpenCenteredPositionWithLiquidity( + whirlpoolAddress: PublicKey, + priceOffsetBps: number, + inputTokenMint: PublicKey, + inputAmount: Decimal, + ) { + return orcaOpenCenteredPositionWithLiquidity( + this, + whirlpoolAddress, + priceOffsetBps, + inputTokenMint, + inputAmount, + ); + } + async resolveAllDomains(domain: string): Promise { return resolveAllDomains(this, domain); } diff --git a/src/langchain/index.ts b/src/langchain/index.ts index 2ec7389..21da295 100644 --- a/src/langchain/index.ts +++ b/src/langchain/index.ts @@ -754,17 +754,72 @@ export class SolanaCompressedAirdropTool extends Tool { } } -export class SolanaCreateSingleSidedWhirlpoolTool extends Tool { - name = "create_orca_single_sided_whirlpool"; - description = `Create a single-sided liquidity pools with liquidity on Orca. +export class SolanaOrcaCreateCLMM extends Tool { + name = "orca_create_clmm"; + description = `Create a Concentrated Liquidity Market Maker (CLMM) pool on Orca, the most efficient and capital-optimized CLMM on Solana. This function initializes a CLMM pool but does not add liquidity. You can add liquidity later using a centered position or a single-sided position. Single-sided positions are ideal for directional price expectations, acting as sort of a limit call. Centered positions are ideal for generating yield. The tighter, the better. - Inputs (input is a JSON string): - - depositTokenAmount: number, in units of deposit token including decimals, eg: 1000000000 (required) - - depositTokenMint: string, mint address of deposit token, eg: "DepositTokenMintAddress" (required) - - otherTokenMint: string, mint address of other token, eg: "OtherTokenMintAddress" (required) - - initialPrice: number, initial price of deposit token in terms of other token, eg: 0.001, (required) - - maxPrice: number, maximum price at which liquidity is added, eg: 5.0 (required) - - feeTier: number, fee tier for the pool in %. Possible values on mainnet are: 0.01, 0.02, 0.04, 0.05, 0.16, 0.30, 0.65, 1.0, 2.0 (required)`; + Inputs (JSON string): + - mintA: string, mint address of the first token, e.g., "MintAAddress" (required). + - mintB: string, mint address of the second token, e.g., "MintBAddress" (required). + - initialPrice: number, initial price of mintA in terms of mintB, e.g., 0.001 (required). + - feeTier: number, fee tier in bps. Options: 1, 2, 4, 5, 16, 30, 65, 100, 200 (required).`; + + constructor(private solanaKit: SolanaAgentKit) { + super(); + } + + async _call(input: string): Promise { + try { + const inputFormat = JSON.parse(input); + const mintA = new PublicKey(inputFormat.mintA); + const mintB = new PublicKey(inputFormat.mintB); + const initialPrice = new Decimal(inputFormat.initialPrice); + const feeTier = inputFormat.feeTier; + + if (!feeTier || !(feeTier in FEE_TIERS)) { + throw new Error( + `Invalid feeTier. Available options: ${Object.keys(FEE_TIERS).join( + ", ", + )}`, + ); + } + + const txId = await this.solanaKit.orcaCreateCLMM( + mintA, + mintB, + initialPrice, + feeTier, + ); + + return JSON.stringify({ + status: "success", + message: "CLMM pool created successfully. Note: No liquidity was added.", + transaction: txId, + }); + } catch (error: any) { + return JSON.stringify({ + status: "error", + message: error.message, + code: error.code || "UNKNOWN_ERROR", + }); + } + } +} + + +export class SolanaOrcaCreateSingleSideLiquidityPool extends Tool { + name = "orca_create_single_sided_liquidity_pool"; + description = `Create a single-sided liquidity pool on Orca, the most efficient and capital-optimized CLMM platform on Solana. + + This function initializes a single-sided liquidity pool, ideal for community driven project, fair launches, and fundraising. Minimize price impact by setting a narrow price range. + + Inputs (JSON string): + - depositTokenAmount: number, in units of the deposit token including decimals, e.g., 1000000000 (required). + - depositTokenMint: string, mint address of the deposit token, e.g., "DepositTokenMintAddress" (required). + - otherTokenMint: string, mint address of the other token, e.g., "OtherTokenMintAddress" (required). + - initialPrice: number, initial price of the deposit token in terms of the other token, e.g., 0.001 (required). + - maxPrice: number, maximum price at which liquidity is added, e.g., 5.0 (required). + - feeTier: number, fee tier for the pool in bps. Options: 1, 2, 4, 5, 16, 30, 65, 100, 200 (required).`; constructor(private solanaKit: SolanaAgentKit) { super(); @@ -788,7 +843,7 @@ export class SolanaCreateSingleSidedWhirlpoolTool extends Tool { ); } - const txId = await this.solanaKit.createOrcaSingleSidedWhirlpool( + const txId = await this.solanaKit.orcaCreateSingleSidedLiquidityPool( depositTokenAmount, depositTokenMint, otherTokenMint, @@ -812,6 +867,54 @@ export class SolanaCreateSingleSidedWhirlpoolTool extends Tool { } } +export class SolanaOrcaOpenCenteredPosition extends Tool { + name = "orca_open_centered_position_with_liquidity"; + description = `Add liquidity to a CLMM by opening a position in an Orca Whirlpool, the most efficient CLMM on Solana for precise liquidity management. A tighter range concentrates more liquidity, increasing yield potential. This function calculates the required amount of the other token based on the input token and desired offset. Centered positions are ideal for optimizing returns within defined ranges. + + Inputs (JSON string): + - whirlpoolAddress: string, address of the Orca Whirlpool (required). + - priceOffsetBps: number, bps offset (one side) from the center price, e.g., 500 for 5% (required). + - inputTokenMint: string, mint address of the deposit token (required). + - inputAmount: number, amount of the deposit token, e.g., 100.0 (required).`; + + constructor(private solanaKit: SolanaAgentKit) { + super(); + } + + async _call(input: string): Promise { + try { + const inputFormat = JSON.parse(input); + const whirlpoolAddress = new PublicKey(inputFormat.whirlpoolAddress); + const priceOffsetBps = parseInt(inputFormat.priceOffsetBps, 10); + const inputTokenMint = new PublicKey(inputFormat.inputTokenMint); + const inputAmount = new Decimal(inputFormat.inputAmount); + + if (priceOffsetBps <= 0 || priceOffsetBps > 10_000) { + throw new Error("Invalid priceOffsetBps. It must be greater than 0 and less than or equal to 10,000."); + } + + const txId = await this.solanaKit.orcaOpenCenteredPositionWithLiquidity( + whirlpoolAddress, + priceOffsetBps, + inputTokenMint, + inputAmount, + ); + + return JSON.stringify({ + status: "success", + message: "Centered liquidity position opened successfully.", + transaction: txId, + }); + } catch (error: any) { + return JSON.stringify({ + status: "error", + message: error.message, + code: error.code || "UNKNOWN_ERROR", + }); + } + } +} + export class SolanaRaydiumCreateAmmV4 extends Tool { name = "raydium_create_ammV4"; description = `Raydium's Legacy AMM that requiers an OpenBook marketID @@ -1254,7 +1357,9 @@ export function createSolanaTools(solanaKit: SolanaAgentKit) { new SolanaRaydiumCreateClmm(solanaKit), new SolanaRaydiumCreateCpmm(solanaKit), new SolanaOpenbookCreateMarket(solanaKit), - new SolanaCreateSingleSidedWhirlpoolTool(solanaKit), + new SolanaOrcaCreateCLMM(solanaKit), + new SolanaOrcaCreateSingleSideLiquidityPool(solanaKit), + new SolanaOrcaOpenCenteredPosition(solanaKit), new SolanaPythFetchPrice(solanaKit), new SolanaResolveDomainTool(solanaKit), new SolanaGetOwnedDomains(solanaKit), diff --git a/src/tools/index.ts b/src/tools/index.ts index 9a18cf4..a87f931 100644 --- a/src/tools/index.ts +++ b/src/tools/index.ts @@ -15,7 +15,9 @@ export * from "./get_token_data"; export * from "./stake_with_jup"; export * from "./fetch_price"; export * from "./send_compressed_airdrop"; -export * from "./create_orca_single_sided_whirlpool"; +export * from "./orca_create_clmm"; +export * from "./orca_create_single_sided_liquidity_pool"; +export * from "./orca_open_centered_position_with_liquidity"; export * from "./get_all_domains_tlds"; export * from "./get_all_registered_all_domains"; export * from "./get_owned_domains_for_tld"; diff --git a/src/tools/orca_create_clmm.ts b/src/tools/orca_create_clmm.ts new file mode 100644 index 0000000..4b6d465 --- /dev/null +++ b/src/tools/orca_create_clmm.ts @@ -0,0 +1,117 @@ +import { Keypair, PublicKey, TransactionMessage, VersionedTransaction } from "@solana/web3.js"; +import { SolanaAgentKit } from "../agent"; +import { Wallet } from "@coral-xyz/anchor"; +import { Decimal } from "decimal.js"; +import { + ORCA_WHIRLPOOL_PROGRAM_ID, + WhirlpoolContext, + PriceMath, + PoolUtil, + buildWhirlpoolClient, +} from "@orca-so/whirlpools-sdk"; + +import { sendTx } from "../utils/send_tx"; +import { FEE_TIERS } from "./orca_create_single_sided_liquidity_pool"; + +/** + * # Creates a CLMM Pool (Concentrated Liquidity Market Maker Pool). + * + * This function initializes a new Whirlpool (CLMM Pool) on Orca. It only sets up the pool and does not seed it with liquidity. + * + * ## Example Usage: + * Suppose you want to create a CLMM pool with two tokens, SHARK and USDC, and set the initial price of SHARK to 0.001 USDC. + * You would call this function with `mintA` as SHARK's mint address and `mintB` as USDC's mint address. The pool is created + * with the specified fee tier and tick spacing associated with that fee tier. + * + * ### Note for Experts: + * The Whirlpool program determines the token mint order, which might not match your expectation. This function + * adjusts the input order as needed and inverts the initial price accordingly. + * + * @param agent - The `SolanaAgentKit` instance representing the wallet and connection details. + * @param mintA - The mint address of the first token in the pool (e.g., SHARK). + * @param mintB - The mint address of the second token in the pool (e.g., USDC). + * @param initialPrice - The initial price of `mintA` in terms of `mintB`. + * @param feeTier - The fee tier bps for the pool, determining tick spacing and fee collection rates. + * + * @returns A promise that resolves to a transaction ID (`string`) of the transaction creating the pool. + * + * @throws Will throw an error if: + * - Mint accounts for the tokens cannot be fetched. + * - The network is unsupported. + * + * @remarks + * This function only initializes the CLMM pool and does not add liquidity. For adding liquidity, you can use + * a separate function after the pool is successfully created. + * ``` + */ +export async function orcaCreateCLMM( + agent: SolanaAgentKit, + mintA: PublicKey, + mintB: PublicKey, + initialPrice: Decimal, + feeTier: keyof typeof FEE_TIERS, +): Promise { + try { + let whirlpoolsConfigAddress: PublicKey; + if (agent.connection.rpcEndpoint.includes('mainnet')) { + whirlpoolsConfigAddress = new PublicKey('2LecshUwdy9xi7meFgHtFJQNSKk4KdTrcpvaB56dP2NQ'); + } else if (agent.connection.rpcEndpoint.includes('devnet')) { + whirlpoolsConfigAddress = new PublicKey('FcrweFY1G9HJAHG5inkGB6pKg1HZ6x9UC2WioAfWrGkR'); + } else { + throw new Error('Unsupported network'); + } + const wallet = new Wallet(agent.wallet); + const ctx = WhirlpoolContext.from( + agent.connection, + wallet, + ORCA_WHIRLPOOL_PROGRAM_ID, + ); + const fetcher = ctx.fetcher; + const client = buildWhirlpoolClient(ctx) + + const correctTokenOrder = PoolUtil.orderMints( + mintA, + mintB, + ).map((addr) => addr.toString()); + const isCorrectMintOrder = + correctTokenOrder[0] === mintA.toString(); + if (!isCorrectMintOrder) { + [mintA, mintB] = [mintB, mintA]; + initialPrice = new Decimal(1 / initialPrice.toNumber()); + } + const mintAAccount = await fetcher.getMintInfo(mintA); + const mintBAccount = await fetcher.getMintInfo(mintB); + if (mintAAccount === null || mintBAccount === null) { + throw Error("Mint account not found"); + } + + const initialTick = PriceMath.priceToTickIndex(initialPrice, mintAAccount.decimals, mintBAccount.decimals) + const tickSpacing = FEE_TIERS[feeTier]; + + const { poolKey, tx: txBuilder } = await client.createPool( + whirlpoolsConfigAddress, + mintA, + mintB, + tickSpacing, + initialTick, + wallet.publicKey, + ) + + const txPayload = await txBuilder.build(); + const txPayloadDecompiled = TransactionMessage.decompile((txPayload.transaction as VersionedTransaction).message); + const instructions = txPayloadDecompiled.instructions; + + const txId = await sendTx( + agent, + instructions, + txPayload.signers as Keypair[] + ); + return JSON.stringify({ + transactionId: txId, + whirlpoolAddress: poolKey.toString(), + }); + } catch (error) { + console.log(error) + throw new Error(`${error}`); + } +} \ No newline at end of file diff --git a/src/tools/create_orca_single_sided_whirlpool.ts b/src/tools/orca_create_single_sided_liquidity_pool.ts similarity index 88% rename from src/tools/create_orca_single_sided_whirlpool.ts rename to src/tools/orca_create_single_sided_liquidity_pool.ts index b861c94..932f119 100644 --- a/src/tools/create_orca_single_sided_whirlpool.ts +++ b/src/tools/orca_create_single_sided_liquidity_pool.ts @@ -1,4 +1,9 @@ -import { Keypair, PublicKey, Transaction, TransactionMessage, VersionedTransaction } from "@solana/web3.js"; +import { + Keypair, + PublicKey, + TransactionMessage, + VersionedTransaction +} from "@solana/web3.js"; import { SolanaAgentKit } from "../agent"; import { BN, Wallet } from "@coral-xyz/anchor"; import { Decimal } from "decimal.js"; @@ -34,7 +39,7 @@ import { import { sendTx } from "../utils/send_tx"; /** - * Maps fee tier percentages to their corresponding tick spacing values in the Orca Whirlpool protocol. + * Maps fee tier bps to their corresponding tick spacing values in the Orca Whirlpool protocol. * * @remarks * Fee tiers determine the percentage of fees collected on swaps, while tick spacing affects @@ -45,22 +50,22 @@ import { sendTx } from "../utils/send_tx"; * - [Whirlpool Parameters](https://orca-so.github.io/whirlpools/Architecture%20Overview/Whirlpool%20Parameters) * * @example - * const tickSpacing = FEE_TIERS[0.30]; // Returns 64 + * const tickSpacing = FEE_TIERS[1]; // returns 1 */ export const FEE_TIERS = { - 0.01: 1, - 0.02: 2, - 0.04: 4, - 0.05: 8, - 0.16: 16, - 0.3: 64, - 0.65: 96, - 1.0: 128, - 2.0: 256, + 1: 1, + 2: 2, + 4: 4, + 5: 8, + 16: 16, + 30: 64, + 65: 96, + 100: 128, + 200: 256, } as const; /** - * # Creates a single-sided Whirlpool. + * # Creates a single-sided liquidity pool. * * This function initializes a new Whirlpool (liquidity pool) on Orca and seeds it with liquidity from a single token. * @@ -84,7 +89,7 @@ export const FEE_TIERS = { * @param otherTokenMint - The mint address of the other token in the pool, eg. USDC. * @param initialPrice - The initial price of the deposit token in terms of the other token. * @param maxPrice - The maximum price at which liquidity is added. - * @param feeTier - The fee tier percentage for the pool, determining tick spacing and fee collection rates. + * @param feeTier - The fee tier bps for the pool, determining tick spacing and fee collection rates. * * @returns A promise that resolves to a transaction ID (`string`) of the transaction creating the pool. * @@ -95,42 +100,15 @@ export const FEE_TIERS = { * @remarks * This function is designed for single-sided deposits where users only contribute one type of token, * and the function manages mint order and necessary calculations. - * - * @example - * ```typescript - * import { SolanaAgentKit } from "your-sdk"; - * import { PublicKey } from "@solana/web3.js"; - * import { BN } from "@coral-xyz/anchor"; - * import Decimal from "decimal.js"; - * - * const agent = new SolanaAgentKit(wallet, connection); - * const depositAmount = new BN(1_000_000_000_000); // 1 million SHARK if SHARK has 6 decimals - * const depositTokenMint = new PublicKey("DEPOSTI_TOKEN_ADDRESS"); - * const otherTokenMint = new PublicKey("OTHER_TOKEN_ADDRESS"); - * const initialPrice = new Decimal(0.001); - * const maxPrice = new Decimal(5.0); - * const feeTier = 0.02; - * - * const txId = await createOrcaSingleSidedWhirlpool( - * agent, - * depositAmount, - * depositTokenMint, - * otherTokenMint, - * initialPrice, - * maxPrice, - * feeTier, - * ); - * console.log(`Single sided whirlpool created in transaction: ${txId}`); - * ``` */ -export async function createOrcaSingleSidedWhirlpool( +export async function orcaCreateSingleSidedLiquidityPool( agent: SolanaAgentKit, depositTokenAmount: BN, depositTokenMint: PublicKey, otherTokenMint: PublicKey, initialPrice: Decimal, maxPrice: Decimal, - feeTier: keyof typeof FEE_TIERS, + feeTierBps: keyof typeof FEE_TIERS, ): Promise { let whirlpoolsConfigAddress: PublicKey; if (agent.connection.rpcEndpoint.includes('mainnet')) { @@ -167,7 +145,7 @@ export async function createOrcaSingleSidedWhirlpool( if (mintAAccount === null || mintBAccount === null) { throw Error("Mint account not found"); } - const tickSpacing = FEE_TIERS[feeTier]; + const tickSpacing = FEE_TIERS[feeTierBps]; const tickIndex = PriceMath.priceToTickIndex( initialPrice, mintAAccount.decimals, @@ -196,7 +174,7 @@ export async function createOrcaSingleSidedWhirlpool( whirlpoolsConfigAddress, mintA, mintB, - FEE_TIERS[feeTier], + FEE_TIERS[feeTierBps], ); const tokenBadgeA = PDAUtil.getTokenBadge( ORCA_WHIRLPOOL_PROGRAM_ID, @@ -419,7 +397,8 @@ export async function createOrcaSingleSidedWhirlpool( const txPayload = await txBuilder.build(); const instructions = TransactionMessage.decompile( - (txPayload.transaction as VersionedTransaction).message).instructions + (txPayload.transaction as VersionedTransaction).message, + ).instructions; try { const txId = await sendTx( @@ -429,6 +408,6 @@ export async function createOrcaSingleSidedWhirlpool( ); return txId; } catch (error) { - throw new Error(`Failed to create pool: ${JSON.stringify(error)}`); + throw new Error(`Failed to send transaction: ${JSON.stringify(error)}`); } -} +} \ No newline at end of file diff --git a/src/tools/orca_open_centered_position_with_liquidity.ts b/src/tools/orca_open_centered_position_with_liquidity.ts new file mode 100644 index 0000000..de89a28 --- /dev/null +++ b/src/tools/orca_open_centered_position_with_liquidity.ts @@ -0,0 +1,136 @@ +import { Keypair, PublicKey, TransactionInstruction, TransactionMessage, VersionedTransaction } from "@solana/web3.js"; +import { SolanaAgentKit } from "../agent"; +import { Wallet } from "@coral-xyz/anchor"; +import { Decimal } from "decimal.js"; +import { + ORCA_WHIRLPOOL_PROGRAM_ID, + WhirlpoolContext, + PriceMath, + buildWhirlpoolClient, + increaseLiquidityQuoteByInputToken, + TokenExtensionContextForPool, + NO_TOKEN_EXTENSION_CONTEXT, +} from "@orca-so/whirlpools-sdk"; + +import { sendTx } from "../utils/send_tx"; +import { Percentage } from "@orca-so/common-sdk"; + +/** + * # Opens a Centered Liquidity Position in an Orca Whirlpool + * + * This function opens a centered liquidity position in a specified Orca Whirlpool. The user defines + * a basis point (bps) offset from the center price to set the lower and upper bounds of the position. + * The user also specifies the token mint and the amount to deposit. The required amount of the other token + * is calculated automatically. + * + * ## Parameters + * - `agent`: The `SolanaAgentKit` instance representing the wallet and connection details. + * - `whirlpoolAddress`: The address of the Orca Whirlpool where the position will be opened. + * - `priceOffsetBps`: The basis point (bps) offset (on one side) from the center price. For example, + * 500 bps (5%) creates a range from 95% to 105% of the center price. + * - `inputTokenMint`: The mint address of the token being deposited (e.g., USDC or another token). + * - `inputAmount`: The amount of the input token to deposit, specified as a `Decimal` value. + * + * ## Returns + * A `Promise` that resolves to the transaction ID (`string`) of the transaction that opens the position. + * + * ## Notes + * - The `priceOffsetBps` specifies the range symmetrically around the current price. + * - The specified `inputTokenMint` determines which token is deposited directly. The function calculates + * the required amount of the other token based on the specified price range. + * - This function supports Orca's token extensions for managing tokens with special behaviors. + * - The function assumes a maximum slippage of 1% for liquidity provision. + * + * ## Throws + * An error will be thrown if: + * - The specified Whirlpool address is invalid or inaccessible. + * - The transaction fails to send. + * - Any required mint information cannot be fetched. + * + * @param agent - The `SolanaAgentKit` instance representing the wallet and connection. + * @param whirlpoolAddress - The address of the Orca Whirlpool. + * @param priceOffsetBps - The basis point offset (one side) from the center price. + * @param inputTokenMint - The mint address of the token to deposit. + * @param inputAmount - The amount of the input token to deposit. + * @returns A promise resolving to the transaction ID (`string`). + */ +export async function orcaOpenCenteredPositionWithLiquidity( + agent: SolanaAgentKit, + whirlpoolAddress: PublicKey, + priceOffsetBps: number, + inputTokenMint: PublicKey, + inputAmount: Decimal, +): Promise { + try { + const wallet = new Wallet(agent.wallet); + const ctx = WhirlpoolContext.from( + agent.connection, + wallet, + ORCA_WHIRLPOOL_PROGRAM_ID, + ); + const client = buildWhirlpoolClient(ctx) + + const whirlpool = await client.getPool(whirlpoolAddress); + const mintInfoA = whirlpool.getTokenAInfo() + const mintInfoB = whirlpool.getTokenBInfo() + const price = PriceMath.sqrtPriceX64ToPrice( + whirlpool.getData().sqrtPrice, + mintInfoA.decimals, + mintInfoB.decimals + ) + + const lowerPrice = price.mul(1 - priceOffsetBps / 10000) + const upperPrice = price.mul(1 + priceOffsetBps / 10000) + const lowerTick = PriceMath.priceToTickIndex(lowerPrice, mintInfoA.decimals, mintInfoB.decimals) + const upperTick = PriceMath.priceToTickIndex(upperPrice, mintInfoA.decimals, mintInfoB.decimals) + + const txBuilderTickArrays = await whirlpool.initTickArrayForTicks([lowerTick, upperTick]) + let instructions: TransactionInstruction[] = [] + let signers: Keypair[] = [] + if (txBuilderTickArrays !== null) { + const txPayloadTickArrays = await txBuilderTickArrays.build(); + const txPayloadTickArraysDecompiled = TransactionMessage.decompile((txPayloadTickArrays.transaction as VersionedTransaction).message); + const instructionsTickArrays = txPayloadTickArraysDecompiled.instructions; + instructions = instructions.concat(instructionsTickArrays); + signers = signers.concat(txPayloadTickArrays.signers as Keypair[]); + } + + const tokenExtensionCtx: TokenExtensionContextForPool = { + ...NO_TOKEN_EXTENSION_CONTEXT, + tokenMintWithProgramA: mintInfoA, + tokenMintWithProgramB: mintInfoB, + }; + const increaseLiquiditQuote = increaseLiquidityQuoteByInputToken( + inputTokenMint, + inputAmount, + lowerTick, + upperTick, + Percentage.fromFraction(1, 100), + whirlpool, + tokenExtensionCtx + ) + const { positionMint, tx: txBuilder } = await whirlpool.openPositionWithMetadata( + lowerTick, + upperTick, + increaseLiquiditQuote + ) + + const txPayload = await txBuilder.build(); + const txPayloadDecompiled = TransactionMessage.decompile((txPayload.transaction as VersionedTransaction).message); + instructions = instructions.concat(txPayloadDecompiled.instructions); + signers = signers.concat(txPayload.signers as Keypair[]); + + const txId = await sendTx( + agent, + instructions, + signers + ); + return JSON.stringify({ + transactionId: txId, + positionMint: positionMint.toString(), + }) + } catch (error) { + console.log(error) + throw new Error(`${error}`); + } +} \ No newline at end of file diff --git a/src/tools/orca_open_single_sided_position.ts b/src/tools/orca_open_single_sided_position.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/utils/send_tx.ts b/src/utils/send_tx.ts index f357b8e..ad42204 100644 --- a/src/utils/send_tx.ts +++ b/src/utils/send_tx.ts @@ -1,5 +1,5 @@ import { SolanaAgentKit } from "../agent"; -import { Keypair, TransactionInstruction, TransactionMessage, VersionedTransaction } from "@solana/web3.js"; +import { Keypair, Signer, TransactionInstruction, TransactionMessage, VersionedTransaction } from "@solana/web3.js"; import { ComputeBudgetProgram, } from "@solana/web3.js"; @@ -70,45 +70,55 @@ export async function sendTx( instructions: TransactionInstruction[], otherKeypairs?: Keypair[] ) { - const ixComputeBudget = await getComputeBudgetInstructions(agent, instructions, "mid"); - const allInstructions = [ - ixComputeBudget.computeBudgetLimitInstruction, - ixComputeBudget.computeBudgetPriorityFeeInstructions, - ...instructions]; - const messageV0 = new TransactionMessage({ - payerKey: agent.wallet_address, - recentBlockhash: ixComputeBudget.blockhash, - instructions: allInstructions, - }).compileToV0Message(); - const transaction = new VersionedTransaction(messageV0); - transaction.sign([agent.wallet, ...(otherKeypairs ?? [])]); + try { + const ixComputeBudget = await getComputeBudgetInstructions(agent, instructions, "mid"); + const allInstructions = [ + ixComputeBudget.computeBudgetLimitInstruction, + ixComputeBudget.computeBudgetPriorityFeeInstructions, + ...instructions]; + const messageV0 = new TransactionMessage({ + payerKey: agent.wallet_address, + recentBlockhash: ixComputeBudget.blockhash, + instructions: allInstructions, + }).compileToV0Message(); + const transaction = new VersionedTransaction(messageV0); + transaction.sign([agent.wallet, ...(otherKeypairs ?? [])]); - const timeoutMs = 90000; - const startTime = Date.now(); - while (Date.now() - startTime < timeoutMs) { - const transactionStartTime = Date.now(); + const timeoutMs = 90000; + const startTime = Date.now(); + try { + while (Date.now() - startTime < timeoutMs) { + const transactionStartTime = Date.now(); - const signature = await agent.connection.sendTransaction( - transaction, - { - maxRetries: 0, - skipPreflight: true, - }); + const signature = await agent.connection.sendTransaction( + transaction, + { + maxRetries: 0, + skipPreflight: true, + }); - const statuses = await agent.connection.getSignatureStatuses([signature]); - if (statuses.value[0]) { - if (!statuses.value[0].err) { - return signature; - } else { - throw new Error(`Transaction failed: ${statuses.value[0].err.toString()}`); + const statuses = await agent.connection.getSignatureStatuses([signature]); + if (statuses.value[0]) { + if (!statuses.value[0].err) { + return signature; + } else { + throw new Error(`Transaction failed: ${statuses.value[0].err.toString()}`); + } + } + + const elapsedTime = Date.now() - transactionStartTime; + const remainingTime = Math.max(0, 1000 - elapsedTime); + if (remainingTime > 0) { + await new Promise(resolve => setTimeout(resolve, remainingTime)); + } } + throw new Error("Transaction timeout"); + } catch (error) { + console.log("Error sending transaction:", error); + throw error; } - - const elapsedTime = Date.now() - transactionStartTime; - const remainingTime = Math.max(0, 1000 - elapsedTime); - if (remainingTime > 0) { - await new Promise(resolve => setTimeout(resolve, remainingTime)); - } + } catch (error) { + console.log("Error sending transaction:", error); + throw error; } - throw new Error("Transaction timeout"); } diff --git a/test/index.ts b/test/index.ts index c6f188d..1a64ec9 100644 --- a/test/index.ts +++ b/test/index.ts @@ -36,8 +36,8 @@ const WALLET_DATA_FILE = "wallet_data.txt"; async function initializeAgent() { try { const llm = new ChatOpenAI({ - modelName: "gpt-4o", - temperature: 0.7, + modelName: "gpt-4o-mini", + // temperature: 0.7, }); let walletDataStr: string | null = null;