mirror of
https://github.com/d0zingcat/solana-agent-kit.git
synced 2026-05-16 07:36:45 +00:00
Merge branch 'main' into update-orca-single-sided-pools-and-send_transaction
This commit is contained in:
40
.eslintrc
Normal file
40
.eslintrc
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"root": true,
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"plugins": ["@typescript-eslint", "prettier"],
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"prettier"
|
||||
],
|
||||
"rules": {
|
||||
"prettier/prettier": "error",
|
||||
"no-constant-condition": "off",
|
||||
"@typescript-eslint/explicit-function-return-type": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/no-unused-vars": ["warn", { "argsIgnorePattern": "^_" }],
|
||||
"no-console": ["warn", { "allow": ["warn", "error"] }],
|
||||
"curly": ["error", "all"],
|
||||
"eqeqeq": ["error", "always"],
|
||||
"no-floating-decimal": "error",
|
||||
"no-var": "error",
|
||||
"prefer-const": "error"
|
||||
},
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": true,
|
||||
"es6": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2020,
|
||||
"sourceType": "module"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["test/**/*", "src/utils/keypair.ts"],
|
||||
"rules": {
|
||||
"no-console": "off"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
4
.prettierignore
Normal file
4
.prettierignore
Normal file
@@ -0,0 +1,4 @@
|
||||
dist
|
||||
node_modules
|
||||
docs
|
||||
*.md
|
||||
12
.prettierrc
Normal file
12
.prettierrc
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"semi": true,
|
||||
"trailingComma": "all",
|
||||
"singleQuote": false,
|
||||
"printWidth": 80,
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"bracketSpacing": true,
|
||||
"arrowParens": "always",
|
||||
"endOfLine": "lf",
|
||||
"bracketSameLine": false
|
||||
}
|
||||
2
LICENSE
2
LICENSE
@@ -186,7 +186,7 @@
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
Copyright [2024] [SendAI]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
48
README.md
48
README.md
@@ -183,60 +183,14 @@ import { PublicKey } from "@solana/web3.js";
|
||||
### Fetch Price Data from Pyth
|
||||
|
||||
```typescript
|
||||
import { pythFetchPrice } from "solana-agent-kit";
|
||||
|
||||
const price = await pythFetchPrice(
|
||||
agent,
|
||||
const price = await agent.pythFetchPrice(
|
||||
"0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43"
|
||||
);
|
||||
|
||||
console.log("Price in BTC/USD:", price);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### Core Functions
|
||||
|
||||
#### `deploy_token(agent, decimals?, name, uri, symbol, initialSupply?)`
|
||||
|
||||
Deploy a new SPL token with optional initial supply. If not specified, decimals default to 9.
|
||||
|
||||
#### `deploy_collection(agent, options)`
|
||||
|
||||
Create a new NFT collection with customizable metadata and royalties.
|
||||
|
||||
#### `mintCollectionNFT(agent, collectionMint, metadata, recipient?)`
|
||||
|
||||
Mint a new NFT as part of an existing collection.
|
||||
|
||||
#### `transfer(agent, to, amount, mint?)`
|
||||
|
||||
Transfer SOL or SPL tokens to a recipient.
|
||||
|
||||
#### `trade(agent, outputMint, inputAmount, inputMint?, slippageBps?)`
|
||||
|
||||
Swap tokens using Jupiter Exchange integration.
|
||||
|
||||
#### `get_balance(agent, token_address)`
|
||||
|
||||
Check SOL or token balance for the agent's wallet.
|
||||
|
||||
#### `lendAsset(agent, assetMint, amount, apiKey)`
|
||||
|
||||
Lend idle assets to earn interest with Lulo.
|
||||
|
||||
#### `stakeWithJup(agent, amount)`
|
||||
|
||||
Stake SOL with Jupiter to earn rewards.
|
||||
|
||||
#### `sendCompressedAirdrop(agent, mintAddress, amount, recipients, priorityFeeInLamports?, shouldLog?)`
|
||||
|
||||
Send an SPL token airdrop to many recipients at low cost via ZK Compression.
|
||||
|
||||
#### `pythFetchPrice(agent, priceFeedID)`
|
||||
|
||||
Fetch price data from Pyth's Hermes service.
|
||||
|
||||
## Dependencies
|
||||
|
||||
The toolkit relies on several key Solana and Metaplex libraries:
|
||||
|
||||
@@ -1 +1 @@
|
||||
window.navigationData = "data:application/octet-stream;base64,H4sIAAAAAAAAE4XTQUvDMBTA8e+Sc7E4dEhvw9KDzm1ob+IhxNc1LH0vJC+gyL67bBNdXfZ26SX//l4T0tcvxfDBqlIv5DTq2RqQHy2rQnnNvaqUcTpGiOV4/arnwalCbSy+q+p6crctfqV7cg4MW8IavKPPAfDIs8gQOm0glrlwDE9up1l46XfPeEH9qUQygGYKeeiwJr3eAJt+FayBZ4ieMEJWOs0k9CF5yxBa2gDWmnWW/B9J4Dw5mhlDCbkG1tZF8WvP59KQJ4v8d/SLphVnnK2lEas0+C7hXCc0vchny0t0k3B/nNLlynQSa3ZXCA6/TkvkjtAu4X7vsTyJxuL0Zvv2DYU9ByOnAwAA"
|
||||
window.navigationData = "data:application/octet-stream;base64,H4sIAAAAAAAAE42TwU7DMAyG3yXniooJJtTbRNUDDJigN8QhCi6JltpR40hMaO+OtiFYWebtkos/f7asP69fiuGTVaVeyGvUsw9AvnesChU0W1Up43WMEMtx/cJy71Whlg7fVXU5uVkXv6Zb8h4MO8IagqdVD7jnc8gwdNpALHPgWDy5nmbFT2HzxhPWH0pUDqCZhrxoV5PaG2BjF4Mz8AwxEEbImg4xSXqXgmMYWloC1pp1VvkfkoTz5GlmDCXkGlg7H8Vtj+PSkAeH/Hf6x6YVZxylpRGL1Icu4VwnNFbUZ8lT6ibh9pxSuDKcqF2xPTMjeVSSm00+YfcvWyK/t3GXcHvYWB5AY+P0av32DUTvPWMEBAAA"
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
117
docs/index.html
117
docs/index.html
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
6
docs/interfaces/PythFetchPriceResponse.html
Normal file
6
docs/interfaces/PythFetchPriceResponse.html
Normal file
File diff suppressed because one or more lines are too long
154
docs/media/CONTRIBUTING.md
Normal file
154
docs/media/CONTRIBUTING.md
Normal file
@@ -0,0 +1,154 @@
|
||||
# Contributing to Solana Agent Kit
|
||||
|
||||
First off, thank you for considering contributing to Solana Agent Kit! 🎉 Your contributions are **greatly appreciated**.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Contributing to Solana Agent Kit](#contributing-to-solana-agent-kit)
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Code of Conduct](#code-of-conduct)
|
||||
- [How Can I Contribute?](#how-can-i-contribute)
|
||||
- [Reporting Bugs](#reporting-bugs)
|
||||
- [Suggesting Enhancements](#suggesting-enhancements)
|
||||
- [Your First Code Contribution](#your-first-code-contribution)
|
||||
- [Pull Requests](#pull-requests)
|
||||
- [Style Guides](#style-guides)
|
||||
- [Code Style](#code-style)
|
||||
- [Commit Messages](#commit-messages)
|
||||
- [Naming Conventions](#naming-conventions)
|
||||
- [Development Setup](#development-setup)
|
||||
- [Prerequisites](#prerequisites)
|
||||
- [Installation](#installation)
|
||||
- [Building the Project](#building-the-project)
|
||||
- [Running Tests](#running-tests)
|
||||
- [Generating Documentation](#generating-documentation)
|
||||
- [Security](#security)
|
||||
- [License](#license)
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
This project adheres to the [Contributor Covenant Code of Conduct](https://www.contributor-covenant.org/version/2/0/code_of_conduct/). By participating, you are expected to uphold this code. Please report unacceptable behavior to [aryan@sendai.fun](mailto:aryan@sendai.fun).
|
||||
|
||||
## How Can I Contribute?
|
||||
|
||||
### Reporting Bugs
|
||||
|
||||
**Great**! Opening an issue is the best way to help us improve. Here's how you can report a bug:
|
||||
|
||||
1. **Search** the [existing issues](https://github.com/sendaifun/solana-agent-kit/issues) to make sure it hasn't been reported.
|
||||
2. **Open a new issue** and fill out the template with as much information as possible.
|
||||
3. **Provide reproduction steps** if applicable.
|
||||
|
||||
### Suggesting Enhancements
|
||||
|
||||
We welcome your ideas for improving Solana Agent Kit! To suggest an enhancement:
|
||||
|
||||
1. **Search** the [existing issues](https://github.com/sendaifun/solana-agent-kit/issues) to see if it's already been suggested.
|
||||
2. **Open a new issue** and describe your idea in detail.
|
||||
|
||||
### Your First Code Contribution
|
||||
|
||||
Unsure where to start? You can help out by:
|
||||
|
||||
- Fixing simple bugs.
|
||||
- Improving documentation.
|
||||
- Adding tests.
|
||||
|
||||
Check out the [Good First Issues](https://github.com/sendaifun/solana-agent-kit/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) to get started!
|
||||
|
||||
### Pull Requests
|
||||
|
||||
1. **Fork** the repository.
|
||||
2. **Create** a new branch for your feature or bugfix.
|
||||
```bash
|
||||
git checkout -b feature/your-feature-name
|
||||
```
|
||||
3. **Commit** your changes with clear and descriptive messages.
|
||||
4. **Push** to your fork.
|
||||
```bash
|
||||
git push origin feature/your-feature-name
|
||||
```
|
||||
5. **Open a Pull Request** against the `main` branch of this repository.
|
||||
|
||||
## Style Guides
|
||||
|
||||
### Code Style
|
||||
|
||||
- **Language**: TypeScript
|
||||
- **Formatting**: Follow the existing codebase formatting. Consider using [Prettier](https://prettier.io/) for consistent code formatting.
|
||||
- **Code Quality**: Adhere to the code quality rules defined in `.eslintrc`. Ensure all checks pass before submitting a PR.
|
||||
|
||||
### Commit Messages
|
||||
|
||||
Use [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) for your commit messages. Examples:
|
||||
|
||||
- `feat: add ability to deploy new SPL token`
|
||||
- `fix: handle edge case when deploying collection`
|
||||
- `docs: update README with new usage examples`
|
||||
|
||||
### Naming Conventions
|
||||
|
||||
- **Variables and Functions**: `camelCase`
|
||||
- **Classes and Types**: `PascalCase`
|
||||
- **Constants**: `UPPER_SNAKE_CASE`
|
||||
|
||||
## Development Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- **Node.js**: v23.x or higher
|
||||
- **npm**: v10.x or higher
|
||||
- **Git**: Installed and configured
|
||||
|
||||
### Installation
|
||||
|
||||
1. **Clone** the repository:
|
||||
```bash
|
||||
git clone https://github.com/yourusername/solana-agent-kit.git
|
||||
```
|
||||
2. **Navigate** to the project directory:
|
||||
```bash
|
||||
cd solana-agent-kit
|
||||
```
|
||||
3. **Install** dependencies:
|
||||
```bash
|
||||
pnpm install
|
||||
```
|
||||
|
||||
### Building the Project
|
||||
|
||||
To compile the TypeScript code:
|
||||
|
||||
```bash
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
### Running Tests
|
||||
|
||||
To execute the test suite:
|
||||
|
||||
```bash
|
||||
pnpm run test
|
||||
```
|
||||
|
||||
### Generating Documentation
|
||||
|
||||
To generate the project documentation using TypeDoc:
|
||||
|
||||
```bash
|
||||
npm run docs
|
||||
```
|
||||
|
||||
The documentation will be available in the `docs/` directory.
|
||||
|
||||
## Security
|
||||
|
||||
This toolkit handles sensitive information such as private keys and API keys. **Ensure you never commit `.env` files or any sensitive data**. Review the `.gitignore` to confirm that sensitive files are excluded.
|
||||
|
||||
For security vulnerabilities, please follow the [responsible disclosure](mailto:aryan@sendai.fun) process.
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the [ISC License](LICENSE).
|
||||
|
||||
---
|
||||
@@ -8,5 +8,6 @@
|
||||
<a href="interfaces/MintCollectionNFTResponse.html" class="tsd-index-link"><svg class="tsd-kind-icon" viewBox="0 0 24 24"><use href="assets/icons.svg#icon-256"></use></svg><span>Mint<wbr/>CollectionNFTResponse</span></a>
|
||||
<a href="interfaces/PumpfunLaunchResponse.html" class="tsd-index-link"><svg class="tsd-kind-icon" viewBox="0 0 24 24"><use href="assets/icons.svg#icon-256"></use></svg><span>Pumpfun<wbr/>Launch<wbr/>Response</span></a>
|
||||
<a href="interfaces/PumpFunTokenOptions.html" class="tsd-index-link"><svg class="tsd-kind-icon" viewBox="0 0 24 24"><use href="assets/icons.svg#icon-256"></use></svg><span>Pump<wbr/>Fun<wbr/>Token<wbr/>Options</span></a>
|
||||
<a href="interfaces/PythFetchPriceResponse.html" class="tsd-index-link"><svg class="tsd-kind-icon" viewBox="0 0 24 24"><use href="assets/icons.svg#icon-256"></use></svg><span>Pyth<wbr/>Fetch<wbr/>Price<wbr/>Response</span></a>
|
||||
</div></section><section class="tsd-index-section"><h3 class="tsd-index-heading">Functions</h3><div class="tsd-index-list"><a href="functions/createSolanaTools.html" class="tsd-index-link"><svg class="tsd-kind-icon" viewBox="0 0 24 24"><use href="assets/icons.svg#icon-64"></use></svg><span>create<wbr/>Solana<wbr/>Tools</span></a>
|
||||
</div></section></section></section></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><h3><svg width="20" height="20" viewBox="0 0 24 24" fill="none"><use href="assets/icons.svg#icon-chevronDown"></use></svg>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-protected" name="protected"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Protected</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-external" name="external"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>External</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div></div><div class="site-menu"><nav class="tsd-navigation"><a href="modules.html" class="current"><svg class="tsd-kind-icon" viewBox="0 0 24 24"><use href="assets/icons.svg#icon-1"></use></svg><span>solana-agent-kit</span></a><ul class="tsd-small-nested-navigation" id="tsd-nav-container" data-base="."><li>Loading...</li></ul></nav></div></div></div><footer><p class="tsd-generator">Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></footer><div class="overlay"></div></body></html>
|
||||
|
||||
@@ -178,4 +178,4 @@ If you encounter any issues while implementing your custom tool:
|
||||
- Contact the maintainer
|
||||
- Check existing tools for implementation examples
|
||||
|
||||
---
|
||||
---
|
||||
|
||||
20
package.json
20
package.json
@@ -8,15 +8,18 @@
|
||||
"build": "tsc",
|
||||
"docs": "typedoc src --out docs",
|
||||
"test": "ts-node test/index.ts",
|
||||
"generate": "ts-node src/utils/keypair.ts"
|
||||
"generate": "ts-node src/utils/keypair.ts",
|
||||
"lint": "eslint . --ext .ts",
|
||||
"lint:fix": "eslint . --ext .ts --fix",
|
||||
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\""
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=23.1.0",
|
||||
"pnpm": ">=8.0.0"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"author": "sendaifun",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@bonfida/spl-name-service": "^3.0.7",
|
||||
"@coral-xyz/anchor": "0.29",
|
||||
@@ -32,6 +35,7 @@
|
||||
"@metaplex-foundation/umi": "^0.9.2",
|
||||
"@metaplex-foundation/umi-bundle-defaults": "^0.9.2",
|
||||
"@metaplex-foundation/umi-web3js-adapters": "^0.9.2",
|
||||
"@onsol/tldparser": "^0.6.7",
|
||||
"@orca-so/common-sdk": "0.6.4",
|
||||
"@orca-so/whirlpools-sdk": "^0.13.12",
|
||||
"@pythnetwork/price-service-client": "^1.9.0",
|
||||
@@ -40,6 +44,7 @@
|
||||
"@solana/web3.js": "^1.95.4",
|
||||
"bn.js": "^5.2.1",
|
||||
"bs58": "^6.0.0",
|
||||
"chai": "^5.1.2",
|
||||
"decimal.js": "^10.4.3",
|
||||
"dotenv": "^16.4.5",
|
||||
"form-data": "^4.0.1",
|
||||
@@ -49,8 +54,15 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bn.js": "^5.1.5",
|
||||
"@types/chai": "^5.0.1",
|
||||
"@types/node": "^22.9.0",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.7.2"
|
||||
"typescript": "^5.7.2",
|
||||
"eslint": "^8.56.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"@typescript-eslint/eslint-plugin": "^7.0.0",
|
||||
"@typescript-eslint/parser": "^7.0.0",
|
||||
"prettier": "^3.2.5"
|
||||
}
|
||||
}
|
||||
|
||||
1487
pnpm-lock.yaml
generated
1487
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -25,12 +25,21 @@ import {
|
||||
stakeWithJup,
|
||||
sendCompressedAirdrop,
|
||||
createOrcaSingleSidedWhirlpool,
|
||||
FEE_TIERS,
|
||||
fetchPrice,
|
||||
pythFetchPrice,
|
||||
FEE_TIERS,
|
||||
getAllDomainsTLDs,
|
||||
getAllRegisteredAllDomains,
|
||||
getOwnedDomainsForTLD,
|
||||
getMainAllDomainsDomain,
|
||||
getOwnedAllDomains,
|
||||
resolveAllDomains,
|
||||
create_gibwork_task,
|
||||
} from "../tools";
|
||||
import {
|
||||
CollectionDeployment,
|
||||
CollectionOptions,
|
||||
GibworkCreateTaskReponse,
|
||||
JupiterTokenData,
|
||||
MintCollectionNFTResponse,
|
||||
PumpfunLaunchResponse,
|
||||
@@ -40,7 +49,7 @@ import { BN } from "@coral-xyz/anchor";
|
||||
|
||||
/**
|
||||
* Main class for interacting with Solana blockchain
|
||||
* Provides a unified interface for token operations, NFT management, and trading
|
||||
* Provides a unified interface for token operations, NFT management, trading and more
|
||||
*
|
||||
* @class SolanaAgentKit
|
||||
* @property {Connection} connection - Solana RPC connection
|
||||
@@ -146,6 +155,10 @@ export class SolanaAgentKit {
|
||||
return getTokenDataByTicker(ticker);
|
||||
}
|
||||
|
||||
async fetchTokenPrice(mint: string) {
|
||||
return fetchPrice(new PublicKey(mint));
|
||||
}
|
||||
|
||||
async launchPumpFunToken(
|
||||
tokenName: string,
|
||||
tokenTicker: string,
|
||||
@@ -193,7 +206,7 @@ export class SolanaAgentKit {
|
||||
initialPrice: Decimal,
|
||||
maxPrice: Decimal,
|
||||
feeTier: keyof typeof FEE_TIERS,
|
||||
): Promise<string> {
|
||||
) {
|
||||
return createOrcaSingleSidedWhirlpool(
|
||||
this,
|
||||
depositTokenAmount,
|
||||
@@ -205,6 +218,31 @@ export class SolanaAgentKit {
|
||||
);
|
||||
}
|
||||
|
||||
async resolveAllDomains(domain: string): Promise<PublicKey | undefined> {
|
||||
return resolveAllDomains(this, domain);
|
||||
}
|
||||
|
||||
async getOwnedAllDomains(owner: PublicKey): Promise<string[]> {
|
||||
return getOwnedAllDomains(this, owner);
|
||||
}
|
||||
|
||||
async getOwnedDomainsForTLD(tld: string): Promise<string[]> {
|
||||
return getOwnedDomainsForTLD(this, tld);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
async getAllDomainsTLDs(): Promise<String[]> {
|
||||
return getAllDomainsTLDs(this);
|
||||
}
|
||||
|
||||
async getAllRegisteredAllDomains(): Promise<string[]> {
|
||||
return getAllRegisteredAllDomains(this);
|
||||
}
|
||||
|
||||
async getMainAllDomainsDomain(owner: PublicKey): Promise<string | null> {
|
||||
return getMainAllDomainsDomain(this, owner);
|
||||
}
|
||||
|
||||
async raydiumCreateAmmV4(
|
||||
marketId: PublicKey,
|
||||
baseAmount: BN,
|
||||
@@ -254,6 +292,7 @@ export class SolanaAgentKit {
|
||||
configId,
|
||||
mintAAmount,
|
||||
mintBAmount,
|
||||
|
||||
startTime,
|
||||
);
|
||||
}
|
||||
@@ -271,10 +310,31 @@ export class SolanaAgentKit {
|
||||
|
||||
lotSize,
|
||||
tickSize,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
async pythFetchPrice(priceFeedID: string) {
|
||||
return pythFetchPrice(this, priceFeedID);
|
||||
async pythFetchPrice(priceFeedID: string): Promise<string> {
|
||||
return pythFetchPrice(priceFeedID);
|
||||
}
|
||||
|
||||
async createGibworkTask(
|
||||
title: string,
|
||||
content: string,
|
||||
requirements: string,
|
||||
tags: string[],
|
||||
tokenMintAddress: string,
|
||||
tokenAmount: number,
|
||||
payer?: string,
|
||||
): Promise<GibworkCreateTaskReponse> {
|
||||
return create_gibwork_task(
|
||||
this,
|
||||
title,
|
||||
content,
|
||||
requirements,
|
||||
tags,
|
||||
new PublicKey(tokenMintAddress),
|
||||
tokenAmount,
|
||||
payer ? new PublicKey(payer) : undefined,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { SolanaAgentKit } from './agent'; // Move the SolanaAgentKit class to src/agent.ts
|
||||
import { createSolanaTools } from './langchain';
|
||||
import { SolanaAgentKit } from "./agent";
|
||||
import { createSolanaTools } from "./langchain";
|
||||
|
||||
export { SolanaAgentKit, createSolanaTools };
|
||||
|
||||
// Optional: Export types that users might need
|
||||
export * from './types';
|
||||
export * from "./types";
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import Decimal from "decimal.js";
|
||||
import { Tool } from "langchain/tools";
|
||||
import { PythFetchPriceResponse, SolanaAgentKit } from "../index";
|
||||
import {
|
||||
GibworkCreateTaskReponse,
|
||||
PythFetchPriceResponse,
|
||||
SolanaAgentKit,
|
||||
} from "../index";
|
||||
import { create_image } from "../tools/create_image";
|
||||
import { fetchPrice } from "../tools/fetch_price";
|
||||
import { BN } from "@coral-xyz/anchor";
|
||||
import { FEE_TIERS } from "../tools";
|
||||
import { toJSON } from "../utils/toJSON";
|
||||
@@ -67,7 +70,7 @@ export class SolanaTransferTool extends Tool {
|
||||
const tx = await this.solanaKit.transfer(
|
||||
recipient,
|
||||
parsedInput.amount,
|
||||
mintAddress
|
||||
mintAddress,
|
||||
);
|
||||
|
||||
return JSON.stringify({
|
||||
@@ -94,7 +97,7 @@ export class SolanaDeployTokenTool extends Tool {
|
||||
|
||||
Inputs (input is a JSON string):
|
||||
name: string, eg "My Token" (required)
|
||||
uri: string, eg "https://example.com/token.json" (required)
|
||||
uri: string, eg "https://example.com/token.json" (required)
|
||||
symbol: string, eg "MTK" (required)
|
||||
decimals?: number, eg 9 (optional, defaults to 9)
|
||||
initialSupply?: number, eg 1000000 (optional)`;
|
||||
@@ -112,7 +115,7 @@ export class SolanaDeployTokenTool extends Tool {
|
||||
parsedInput.uri,
|
||||
parsedInput.symbol,
|
||||
parsedInput.decimals,
|
||||
parsedInput.initialSupply
|
||||
parsedInput.initialSupply,
|
||||
);
|
||||
|
||||
return JSON.stringify({
|
||||
@@ -192,7 +195,7 @@ export class SolanaMintNFTTool extends Tool {
|
||||
},
|
||||
parsedInput.recipient
|
||||
? new PublicKey(parsedInput.recipient)
|
||||
: this.solanaKit.wallet_address
|
||||
: this.solanaKit.wallet_address,
|
||||
);
|
||||
|
||||
return JSON.stringify({
|
||||
@@ -240,7 +243,7 @@ export class SolanaTradeTool extends Tool {
|
||||
parsedInput.inputMint
|
||||
? new PublicKey(parsedInput.inputMint)
|
||||
: new PublicKey("So11111111111111111111111111111111111111112"),
|
||||
parsedInput.slippageBps
|
||||
parsedInput.slippageBps,
|
||||
);
|
||||
|
||||
return JSON.stringify({
|
||||
@@ -320,7 +323,7 @@ export class SolanaRegisterDomainTool extends Tool {
|
||||
|
||||
const tx = await this.solanaKit.registerDomain(
|
||||
parsedInput.name,
|
||||
parsedInput.spaceKB || 1
|
||||
parsedInput.spaceKB || 1,
|
||||
);
|
||||
|
||||
return JSON.stringify({
|
||||
@@ -342,10 +345,12 @@ export class SolanaRegisterDomainTool extends Tool {
|
||||
|
||||
export class SolanaResolveDomainTool extends Tool {
|
||||
name = "solana_resolve_domain";
|
||||
description = `Resolve a .sol domain to a Solana PublicKey.
|
||||
description = `Resolve ONLY .sol domain names to a Solana PublicKey.
|
||||
This tool is exclusively for .sol domains.
|
||||
DO NOT use this for other domain types like .blink, .bonk, etc.
|
||||
|
||||
Inputs:
|
||||
domain: string, eg "pumpfun.sol" or "pumpfun"(required)
|
||||
domain: string, eg "pumpfun.sol" (required)
|
||||
`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
@@ -460,7 +465,7 @@ export class SolanaPumpfunTokenLaunchTool extends Tool {
|
||||
try {
|
||||
// Parse and normalize input
|
||||
input = input.trim();
|
||||
let parsedInput = JSON.parse(input);
|
||||
const parsedInput = JSON.parse(input);
|
||||
|
||||
this.validateInput(parsedInput);
|
||||
|
||||
@@ -475,7 +480,7 @@ export class SolanaPumpfunTokenLaunchTool extends Tool {
|
||||
telegram: parsedInput.telegram,
|
||||
website: parsedInput.website,
|
||||
initialLiquiditySOL: parsedInput.initialLiquiditySOL,
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
return JSON.stringify({
|
||||
@@ -542,7 +547,7 @@ export class SolanaLendAssetTool extends Tool {
|
||||
|
||||
async _call(input: string): Promise<string> {
|
||||
try {
|
||||
let amount = JSON.parse(input).amount || input;
|
||||
const amount = JSON.parse(input).amount || input;
|
||||
|
||||
const tx = await this.solanaKit.lendAssets(amount);
|
||||
|
||||
@@ -619,7 +624,7 @@ export class SolanaStakeTool extends Tool {
|
||||
export class SolanaFetchPriceTool extends Tool {
|
||||
name = "solana_fetch_price";
|
||||
description = `Fetch the price of a given token in USDC.
|
||||
|
||||
|
||||
Inputs:
|
||||
- tokenId: string, the mint address of the token, e.g., "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN"`;
|
||||
|
||||
@@ -629,7 +634,7 @@ export class SolanaFetchPriceTool extends Tool {
|
||||
|
||||
async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const price = await fetchPrice(this.solanaKit, input.trim());
|
||||
const price = await this.solanaKit.fetchTokenPrice(input.trim());
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
tokenId: input.trim(),
|
||||
@@ -708,7 +713,7 @@ export class SolanaTokenDataByTickerTool extends Tool {
|
||||
export class SolanaCompressedAirdropTool extends Tool {
|
||||
name = "solana_compressed_airdrop";
|
||||
description = `Airdrop SPL tokens with ZK Compression (also called as airdropping tokens)
|
||||
|
||||
|
||||
Inputs (input is a JSON string):
|
||||
mintAddress: string, the mint address of the token, e.g., "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN" (required)
|
||||
amount: number, the amount of tokens to airdrop per recipient, e.g., 42 (required)
|
||||
@@ -731,7 +736,7 @@ export class SolanaCompressedAirdropTool extends Tool {
|
||||
parsedInput.decimals,
|
||||
parsedInput.recipients,
|
||||
parsedInput.priorityFeeInLamports || 30_000,
|
||||
parsedInput.shouldLog || false
|
||||
parsedInput.shouldLog || false,
|
||||
);
|
||||
|
||||
return JSON.stringify({
|
||||
@@ -776,7 +781,11 @@ export class SolanaCreateSingleSidedWhirlpoolTool extends Tool {
|
||||
const feeTier = inputFormat.feeTier;
|
||||
|
||||
if (!feeTier || !(feeTier in FEE_TIERS)) {
|
||||
throw new Error(`Invalid feeTier. Available options: ${Object.keys(FEE_TIERS).join(", ")}`);
|
||||
throw new Error(
|
||||
`Invalid feeTier. Available options: ${Object.keys(FEE_TIERS).join(
|
||||
", ",
|
||||
)}`,
|
||||
);
|
||||
}
|
||||
|
||||
const txId = await this.solanaKit.createOrcaSingleSidedWhirlpool(
|
||||
@@ -820,7 +829,7 @@ export class SolanaRaydiumCreateAmmV4 extends Tool {
|
||||
|
||||
async _call(input: string): Promise<string> {
|
||||
try {
|
||||
let inputFormat = JSON.parse(input)
|
||||
const inputFormat = JSON.parse(input);
|
||||
|
||||
const tx = await this.solanaKit.raydiumCreateAmmV4(
|
||||
new PublicKey(inputFormat.marketId),
|
||||
@@ -862,7 +871,7 @@ export class SolanaRaydiumCreateClmm extends Tool {
|
||||
|
||||
async _call(input: string): Promise<string> {
|
||||
try {
|
||||
let inputFormat = JSON.parse(input)
|
||||
const inputFormat = JSON.parse(input);
|
||||
|
||||
const tx = await this.solanaKit.raydiumCreateClmm(
|
||||
new PublicKey(inputFormat.mint1),
|
||||
@@ -891,7 +900,7 @@ export class SolanaRaydiumCreateClmm extends Tool {
|
||||
|
||||
export class SolanaRaydiumCreateCpmm extends Tool {
|
||||
name = "raydium_create_cpmm";
|
||||
description = `Raydium's newest CPMM, does not require marketID, supports Token 2022 standard
|
||||
description = `Raydium's newest CPMM, does not require marketID, supports Token 2022 standard
|
||||
|
||||
Inputs (input is a json string):
|
||||
mint1: string (required)
|
||||
@@ -908,7 +917,7 @@ export class SolanaRaydiumCreateCpmm extends Tool {
|
||||
|
||||
async _call(input: string): Promise<string> {
|
||||
try {
|
||||
let inputFormat = JSON.parse(input)
|
||||
const inputFormat = JSON.parse(input);
|
||||
|
||||
const tx = await this.solanaKit.raydiumCreateCpmm(
|
||||
new PublicKey(inputFormat.mint1),
|
||||
@@ -939,7 +948,7 @@ export class SolanaRaydiumCreateCpmm extends Tool {
|
||||
|
||||
export class SolanaOpenbookCreateMarket extends Tool {
|
||||
name = "solana_openbook_create_market";
|
||||
description = `Openbook marketId, required for ammv4
|
||||
description = `Openbook marketId, required for ammv4
|
||||
|
||||
Inputs (input is a json string):
|
||||
baseMint: string (required)
|
||||
@@ -954,7 +963,7 @@ export class SolanaOpenbookCreateMarket extends Tool {
|
||||
|
||||
async _call(input: string): Promise<string> {
|
||||
try {
|
||||
let inputFormat = JSON.parse(input)
|
||||
const inputFormat = JSON.parse(input);
|
||||
|
||||
const tx = await this.solanaKit.openbookCreateMarket(
|
||||
new PublicKey(inputFormat.baseMint),
|
||||
@@ -993,14 +1002,14 @@ export class SolanaPythFetchPrice extends Tool {
|
||||
async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const price = await this.solanaKit.pythFetchPrice(input);
|
||||
let response: PythFetchPriceResponse = {
|
||||
const response: PythFetchPriceResponse = {
|
||||
status: "success",
|
||||
priceFeedID: input,
|
||||
price: price,
|
||||
};
|
||||
return JSON.stringify(response);
|
||||
} catch (error: any) {
|
||||
let response: PythFetchPriceResponse = {
|
||||
const response: PythFetchPriceResponse = {
|
||||
status: "error",
|
||||
priceFeedID: input,
|
||||
message: error.message,
|
||||
@@ -1011,6 +1020,215 @@ export class SolanaPythFetchPrice extends Tool {
|
||||
}
|
||||
}
|
||||
|
||||
export class SolanaResolveAllDomainsTool extends Tool {
|
||||
name = "solana_resolve_all_domains";
|
||||
description = `Resolve domain names to a public key for ALL domain types EXCEPT .sol domains.
|
||||
Use this for domains like .blink, .bonk, etc.
|
||||
DO NOT use this for .sol domains (use solana_resolve_domain instead).
|
||||
|
||||
Input:
|
||||
domain: string, eg "mydomain.blink" or "mydomain.bonk" (required)`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const owner = await this.solanaKit.resolveAllDomains(input);
|
||||
|
||||
if (!owner) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: "Domain not found",
|
||||
code: "DOMAIN_NOT_FOUND",
|
||||
});
|
||||
}
|
||||
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
message: "Domain resolved successfully",
|
||||
owner: owner?.toString(),
|
||||
});
|
||||
} catch (error: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: error.message,
|
||||
code: error.code || "DOMAIN_RESOLUTION_ERROR",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class SolanaGetOwnedDomains extends Tool {
|
||||
name = "solana_get_owned_domains";
|
||||
description = `Get all domains owned by a specific wallet address.
|
||||
|
||||
Inputs:
|
||||
owner: string, eg "4Be9CvxqHW6BYiRAxW9Q3xu1ycTMWaL5z8NX4HR3ha7t" (required)`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const ownerPubkey = new PublicKey(input.trim());
|
||||
const domains = await this.solanaKit.getOwnedAllDomains(ownerPubkey);
|
||||
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
message: "Owned domains fetched successfully",
|
||||
domains: domains,
|
||||
});
|
||||
} catch (error: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: error.message,
|
||||
code: error.code || "FETCH_OWNED_DOMAINS_ERROR",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class SolanaGetOwnedTldDomains extends Tool {
|
||||
name = "solana_get_owned_tld_domains";
|
||||
description = `Get all domains owned by the agent's wallet for a specific TLD.
|
||||
|
||||
Inputs:
|
||||
tld: string, eg "bonk" (required)`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const domains = await this.solanaKit.getOwnedDomainsForTLD(input);
|
||||
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
message: "TLD domains fetched successfully",
|
||||
domains: domains,
|
||||
});
|
||||
} catch (error: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: error.message,
|
||||
code: error.code || "FETCH_TLD_DOMAINS_ERROR",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class SolanaGetAllTlds extends Tool {
|
||||
name = "solana_get_all_tlds";
|
||||
description = `Get all active top-level domains (TLDs) in the AllDomains Name Service`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
async _call(): Promise<string> {
|
||||
try {
|
||||
const tlds = await this.solanaKit.getAllDomainsTLDs();
|
||||
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
message: "TLDs fetched successfully",
|
||||
tlds: tlds,
|
||||
});
|
||||
} catch (error: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: error.message,
|
||||
code: error.code || "FETCH_TLDS_ERROR",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class SolanaGetMainDomain extends Tool {
|
||||
name = "solana_get_main_domain";
|
||||
description = `Get the main/favorite domain for a given wallet address.
|
||||
|
||||
Inputs:
|
||||
owner: string, eg "4Be9CvxqHW6BYiRAxW9Q3xu1ycTMWaL5z8NX4HR3ha7t" (required)`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const ownerPubkey = new PublicKey(input.trim());
|
||||
const mainDomain =
|
||||
await this.solanaKit.getMainAllDomainsDomain(ownerPubkey);
|
||||
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
message: "Main domain fetched successfully",
|
||||
domain: mainDomain,
|
||||
});
|
||||
} catch (error: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: error.message,
|
||||
code: error.code || "FETCH_MAIN_DOMAIN_ERROR",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class SolanaCreateGibworkTask extends Tool {
|
||||
name = "create_gibwork_task";
|
||||
description = `Create a task on Gibwork.
|
||||
|
||||
Inputs (input is a JSON string):
|
||||
title: string, title of the task (required)
|
||||
content: string, description of the task (required)
|
||||
requirements: string, requirements to complete the task (required)
|
||||
tags: string[], list of tags associated with the task (required)
|
||||
payer: string, payer address (optional, defaults to agent wallet)
|
||||
tokenMintAddress: string, the mint address of the token, e.g., "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN" (required)
|
||||
amount: number, payment amount (required)
|
||||
`;
|
||||
|
||||
constructor(private solanaSdk: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const parsedInput = JSON.parse(input);
|
||||
|
||||
const taskData = await this.solanaSdk.createGibworkTask(
|
||||
parsedInput.title,
|
||||
parsedInput.content,
|
||||
parsedInput.requirements,
|
||||
parsedInput.tags,
|
||||
parsedInput.tokenMintAddress,
|
||||
parsedInput.amount,
|
||||
parsedInput.payer,
|
||||
);
|
||||
|
||||
const response: GibworkCreateTaskReponse = {
|
||||
status: "success",
|
||||
taskId: taskData.taskId,
|
||||
signature: taskData.signature,
|
||||
};
|
||||
|
||||
return JSON.stringify(response);
|
||||
} catch (err: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: err.message,
|
||||
code: err.code || "CREATE_TASK_ERROR",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function createSolanaTools(solanaKit: SolanaAgentKit) {
|
||||
return [
|
||||
new SolanaBalanceTool(solanaKit),
|
||||
@@ -1028,7 +1246,6 @@ export function createSolanaTools(solanaKit: SolanaAgentKit) {
|
||||
new SolanaTPSCalculatorTool(solanaKit),
|
||||
new SolanaStakeTool(solanaKit),
|
||||
new SolanaFetchPriceTool(solanaKit),
|
||||
new SolanaResolveDomainTool(solanaKit),
|
||||
new SolanaGetDomainTool(solanaKit),
|
||||
new SolanaTokenDataTool(solanaKit),
|
||||
new SolanaTokenDataByTickerTool(solanaKit),
|
||||
@@ -1039,6 +1256,12 @@ export function createSolanaTools(solanaKit: SolanaAgentKit) {
|
||||
new SolanaOpenbookCreateMarket(solanaKit),
|
||||
new SolanaCreateSingleSidedWhirlpoolTool(solanaKit),
|
||||
new SolanaPythFetchPrice(solanaKit),
|
||||
new SolanaResolveDomainTool(solanaKit),
|
||||
new SolanaGetOwnedDomains(solanaKit),
|
||||
new SolanaGetOwnedTldDomains(solanaKit),
|
||||
new SolanaGetAllTlds(solanaKit),
|
||||
new SolanaGetMainDomain(solanaKit),
|
||||
new SolanaResolveAllDomainsTool(solanaKit),
|
||||
new SolanaCreateGibworkTask(solanaKit),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
81
src/tools/create_gibwork_task.ts
Normal file
81
src/tools/create_gibwork_task.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
import { VersionedTransaction } from "@solana/web3.js";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import { GibworkCreateTaskReponse, SolanaAgentKit } from "../index";
|
||||
|
||||
/**
|
||||
* Create an new task on Gibwork
|
||||
* @param agent SolanaAgentKit instance
|
||||
* @param title Title of the task
|
||||
* @param content Description of the task
|
||||
* @param requirements Requirements to complete the task
|
||||
* @param tags List of tags associated with the task
|
||||
* @param payer Payer address for the task (default: agent wallet address)
|
||||
* @param tokenMintAddress Token mint address for payment
|
||||
* @param tokenAmount Payment amount for the task
|
||||
* @returns Object containing task creation transaction and generated taskId
|
||||
*/
|
||||
export async function create_gibwork_task(
|
||||
agent: SolanaAgentKit,
|
||||
title: string,
|
||||
content: string,
|
||||
requirements: string,
|
||||
tags: string[],
|
||||
tokenMintAddress: PublicKey,
|
||||
tokenAmount: number,
|
||||
payer?: PublicKey,
|
||||
): Promise<GibworkCreateTaskReponse> {
|
||||
try {
|
||||
const apiResponse = await fetch(
|
||||
"https://api2.gib.work/tasks/public/transaction",
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
title: title,
|
||||
content: content,
|
||||
requirements: requirements,
|
||||
tags: tags,
|
||||
payer: payer?.toBase58() || agent.wallet.publicKey.toBase58(),
|
||||
token: {
|
||||
mintAddress: tokenMintAddress.toBase58(),
|
||||
amount: tokenAmount,
|
||||
},
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
const responseData = await apiResponse.json();
|
||||
if (!responseData.taskId && !responseData.serializedTransaction) {
|
||||
throw new Error(`${responseData.message}`);
|
||||
}
|
||||
|
||||
const serializedTransaction = Buffer.from(
|
||||
responseData.serializedTransaction,
|
||||
"base64",
|
||||
);
|
||||
const tx = VersionedTransaction.deserialize(serializedTransaction);
|
||||
|
||||
tx.sign([agent.wallet]);
|
||||
const signature = await agent.connection.sendTransaction(tx, {
|
||||
preflightCommitment: "confirmed",
|
||||
maxRetries: 3,
|
||||
});
|
||||
|
||||
const latestBlockhash = await agent.connection.getLatestBlockhash();
|
||||
await agent.connection.confirmTransaction({
|
||||
signature,
|
||||
blockhash: latestBlockhash.blockhash,
|
||||
lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
|
||||
});
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
taskId: responseData.taskId,
|
||||
signature: signature,
|
||||
};
|
||||
} catch (err: any) {
|
||||
throw new Error(`${err.message}`);
|
||||
}
|
||||
}
|
||||
@@ -39,7 +39,7 @@ import { sendTx } from "../utils/send_tx";
|
||||
* @remarks
|
||||
* Fee tiers determine the percentage of fees collected on swaps, while tick spacing affects
|
||||
* the granularity of price ranges for liquidity positions.
|
||||
*
|
||||
*
|
||||
* For more details, refer to:
|
||||
* - [Whirlpool Fees](https://orca-so.github.io/whirlpools/Architecture%20Overview/Whirlpool%20Fees)
|
||||
* - [Whirlpool Parameters](https://orca-so.github.io/whirlpools/Architecture%20Overview/Whirlpool%20Parameters)
|
||||
@@ -53,17 +53,17 @@ export const FEE_TIERS = {
|
||||
0.04: 4,
|
||||
0.05: 8,
|
||||
0.16: 16,
|
||||
0.30: 64,
|
||||
0.3: 64,
|
||||
0.65: 96,
|
||||
1.00: 128,
|
||||
2.00: 256,
|
||||
1.0: 128,
|
||||
2.0: 256,
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* # Creates a single-sided Whirlpool.
|
||||
*
|
||||
* This function initializes a new Whirlpool (liquidity pool) on Orca and seeds it with liquidity from a single token.
|
||||
*
|
||||
*
|
||||
* ## Example Usage:
|
||||
* You created a new token called SHARK, and you want to set the initial price to 0.001 USDC.
|
||||
* You set `depositTokenMint` to SHARK's mint address and `otherTokenMint` to USDC's mint address.
|
||||
@@ -71,7 +71,7 @@ export const FEE_TIERS = {
|
||||
* 1. Increase the amount of tokens you deposit
|
||||
* 2. Set the initial price very low
|
||||
* 3. Set the maximum price closer to the initial price
|
||||
*
|
||||
*
|
||||
* ### Note for experts:
|
||||
* The Wrhirlpool program initializes the Whirlpool with the in a specific order. This might not be
|
||||
* the order you expect, so the function checks the order and adjusts the inverts the prices. This means that
|
||||
@@ -85,13 +85,13 @@ export const FEE_TIERS = {
|
||||
* @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.
|
||||
*
|
||||
*
|
||||
* @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.
|
||||
* - Prices are out of bounds.
|
||||
*
|
||||
*
|
||||
* @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.
|
||||
@@ -102,7 +102,7 @@ export const FEE_TIERS = {
|
||||
* 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");
|
||||
@@ -141,13 +141,19 @@ export async function createOrcaSingleSidedWhirlpool(
|
||||
throw new Error('Unsupported network');
|
||||
}
|
||||
const wallet = new Wallet(agent.wallet);
|
||||
const ctx = WhirlpoolContext.from(agent.connection, wallet, ORCA_WHIRLPOOL_PROGRAM_ID);
|
||||
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 isCorrectMintOrder = correctTokenOrder[0] === depositTokenMint.toString();
|
||||
const correctTokenOrder = PoolUtil.orderMints(
|
||||
otherTokenMint,
|
||||
depositTokenMint,
|
||||
).map((addr) => addr.toString());
|
||||
const isCorrectMintOrder =
|
||||
correctTokenOrder[0] === depositTokenMint.toString();
|
||||
let mintA, mintB;
|
||||
if (isCorrectMintOrder) {
|
||||
[mintA, mintB] = [depositTokenMint, otherTokenMint];
|
||||
@@ -158,10 +164,19 @@ export async function createOrcaSingleSidedWhirlpool(
|
||||
}
|
||||
const mintAAccount = await fetcher.getMintInfo(mintA);
|
||||
const mintBAccount = await fetcher.getMintInfo(mintB);
|
||||
if (mintAAccount === null || mintBAccount === null) throw Error('Mint account not found');
|
||||
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);
|
||||
const tickIndex = PriceMath.priceToTickIndex(
|
||||
initialPrice,
|
||||
mintAAccount.decimals,
|
||||
mintBAccount.decimals,
|
||||
);
|
||||
const initialTick = TickUtil.getInitializableTickIndex(
|
||||
tickIndex,
|
||||
tickSpacing,
|
||||
);
|
||||
|
||||
const tokenExtensionCtx: TokenExtensionContextForPool = {
|
||||
...NO_TOKEN_EXTENSION_CONTEXT,
|
||||
@@ -203,17 +218,17 @@ export async function createOrcaSingleSidedWhirlpool(
|
||||
tokenVaultBKeypair,
|
||||
feeTierKey,
|
||||
tickSpacing: tickSpacing,
|
||||
funder: wallet.publicKey
|
||||
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,
|
||||
});
|
||||
...baseParamsPool,
|
||||
tokenProgramA: tokenExtensionCtx.tokenMintWithProgramA.tokenProgram,
|
||||
tokenProgramB: tokenExtensionCtx.tokenMintWithProgramB.tokenProgram,
|
||||
tokenBadgeA,
|
||||
tokenBadgeB,
|
||||
});
|
||||
const initialTickArrayStartTick = TickUtil.getStartTickIndex(
|
||||
initialTick,
|
||||
tickSpacing,
|
||||
@@ -242,14 +257,33 @@ export async function createOrcaSingleSidedWhirlpool(
|
||||
let tickLowerIndex, tickUpperIndex;
|
||||
if (isCorrectMintOrder) {
|
||||
tickLowerIndex = initialTick;
|
||||
tickUpperIndex = PriceMath.priceToTickIndex(maxPrice, mintAAccount.decimals, mintBAccount.decimals);
|
||||
tickUpperIndex = PriceMath.priceToTickIndex(
|
||||
maxPrice,
|
||||
mintAAccount.decimals,
|
||||
mintBAccount.decimals,
|
||||
);
|
||||
} else {
|
||||
tickLowerIndex = PriceMath.priceToTickIndex(maxPrice, mintAAccount.decimals, mintBAccount.decimals);
|
||||
tickLowerIndex = PriceMath.priceToTickIndex(
|
||||
maxPrice,
|
||||
mintAAccount.decimals,
|
||||
mintBAccount.decimals,
|
||||
);
|
||||
tickUpperIndex = initialTick;
|
||||
}
|
||||
const tickLowerInitializableIndex = TickUtil.getInitializableTickIndex(tickLowerIndex, tickSpacing);
|
||||
const tickUpperInitializableIndex = TickUtil.getInitializableTickIndex(tickUpperIndex, tickSpacing);
|
||||
if (!TickUtil.checkTickInBounds(tickLowerInitializableIndex) || !TickUtil.checkTickInBounds(tickUpperInitializableIndex)) throw Error('Prices out of bounds');
|
||||
const tickLowerInitializableIndex = TickUtil.getInitializableTickIndex(
|
||||
tickLowerIndex,
|
||||
tickSpacing,
|
||||
);
|
||||
const tickUpperInitializableIndex = TickUtil.getInitializableTickIndex(
|
||||
tickUpperIndex,
|
||||
tickSpacing,
|
||||
);
|
||||
if (
|
||||
!TickUtil.checkTickInBounds(tickLowerInitializableIndex) ||
|
||||
!TickUtil.checkTickInBounds(tickUpperInitializableIndex)
|
||||
) {
|
||||
throw Error("Prices out of bounds");
|
||||
}
|
||||
const increasLiquidityQuoteParam: IncreaseLiquidityQuoteParam = {
|
||||
inputTokenAmount: new BN(depositTokenAmount),
|
||||
inputTokenMint: depositTokenMint,
|
||||
@@ -260,11 +294,11 @@ export async function createOrcaSingleSidedWhirlpool(
|
||||
tickLowerIndex: tickLowerInitializableIndex,
|
||||
tickUpperIndex: tickUpperInitializableIndex,
|
||||
tokenExtensionCtx: tokenExtensionCtx,
|
||||
slippageTolerance: Percentage.fromFraction(0, 100)
|
||||
}
|
||||
slippageTolerance: Percentage.fromFraction(0, 100),
|
||||
};
|
||||
const liquidityInput = increaseLiquidityQuoteByInputTokenWithParams(
|
||||
increasLiquidityQuoteParam
|
||||
)
|
||||
increasLiquidityQuoteParam,
|
||||
);
|
||||
const { liquidityAmount: liquidity, tokenMaxA, tokenMaxB } = liquidityInput;
|
||||
|
||||
const positionMintKeypair = Keypair.generate();
|
||||
@@ -292,7 +326,7 @@ export async function createOrcaSingleSidedWhirlpool(
|
||||
...params,
|
||||
positionMint: positionMintPubkey,
|
||||
withTokenMetadataExtension: true,
|
||||
})
|
||||
});
|
||||
|
||||
txBuilder.addInstruction(positionIx);
|
||||
txBuilder.addSigner(positionMintKeypair);
|
||||
@@ -372,17 +406,15 @@ export async function createOrcaSingleSidedWhirlpool(
|
||||
tickArrayUpper: tickArrayUpperPda.publicKey,
|
||||
};
|
||||
|
||||
const liquidityIx = !TokenExtensionUtil.isV2IxRequiredPool(
|
||||
tokenExtensionCtx,
|
||||
)
|
||||
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,
|
||||
});
|
||||
...baseParamsLiquidity,
|
||||
tokenMintA: mintA,
|
||||
tokenMintB: mintB,
|
||||
tokenProgramA: tokenExtensionCtx.tokenMintWithProgramA.tokenProgram,
|
||||
tokenProgramB: tokenExtensionCtx.tokenMintWithProgramB.tokenProgram,
|
||||
});
|
||||
txBuilder.addInstruction(liquidityIx);
|
||||
|
||||
const txPayload = await txBuilder.build();
|
||||
|
||||
@@ -1,8 +1,19 @@
|
||||
import { SolanaAgentKit } from "../index";
|
||||
import { generateSigner, keypairIdentity, publicKey } from "@metaplex-foundation/umi";
|
||||
import { createCollection, mplCore, ruleSet } from "@metaplex-foundation/mpl-core";
|
||||
import {
|
||||
generateSigner,
|
||||
keypairIdentity,
|
||||
publicKey,
|
||||
} from "@metaplex-foundation/umi";
|
||||
import {
|
||||
createCollection,
|
||||
mplCore,
|
||||
ruleSet,
|
||||
} from "@metaplex-foundation/mpl-core";
|
||||
import { CollectionOptions, CollectionDeployment } from "../types";
|
||||
import { fromWeb3JsKeypair, toWeb3JsPublicKey } from "@metaplex-foundation/umi-web3js-adapters";
|
||||
import {
|
||||
fromWeb3JsKeypair,
|
||||
toWeb3JsPublicKey,
|
||||
} from "@metaplex-foundation/umi-web3js-adapters";
|
||||
import { createUmi } from "@metaplex-foundation/umi-bundle-defaults";
|
||||
|
||||
/**
|
||||
@@ -28,11 +39,11 @@ export async function deploy_collection(
|
||||
address: publicKey(creator.address),
|
||||
percentage: creator.percentage,
|
||||
})) || [
|
||||
{
|
||||
address: publicKey(agent.wallet_address.toString()),
|
||||
percentage: 100,
|
||||
},
|
||||
];
|
||||
{
|
||||
address: publicKey(agent.wallet_address.toString()),
|
||||
percentage: 100,
|
||||
},
|
||||
];
|
||||
|
||||
// Create collection
|
||||
const tx = await createCollection(umi, {
|
||||
|
||||
@@ -2,9 +2,17 @@ import { SolanaAgentKit } from "../index";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import { createUmi } from "@metaplex-foundation/umi-bundle-defaults";
|
||||
import { generateSigner, keypairIdentity } from "@metaplex-foundation/umi";
|
||||
import { createFungible, mintV1, TokenStandard } from "@metaplex-foundation/mpl-token-metadata";
|
||||
import { fromWeb3JsKeypair, fromWeb3JsPublicKey, toWeb3JsPublicKey } from "@metaplex-foundation/umi-web3js-adapters";
|
||||
import {mplToolbox} from "@metaplex-foundation/mpl-toolbox"
|
||||
import {
|
||||
createFungible,
|
||||
mintV1,
|
||||
TokenStandard,
|
||||
} from "@metaplex-foundation/mpl-token-metadata";
|
||||
import {
|
||||
fromWeb3JsKeypair,
|
||||
fromWeb3JsPublicKey,
|
||||
toWeb3JsPublicKey,
|
||||
} from "@metaplex-foundation/umi-web3js-adapters";
|
||||
import { mplToolbox } from "@metaplex-foundation/mpl-toolbox";
|
||||
|
||||
/**
|
||||
* Deploy a new SPL token
|
||||
@@ -22,11 +30,11 @@ export async function deploy_token(
|
||||
uri: string,
|
||||
symbol: string,
|
||||
decimals: number = 9,
|
||||
initialSupply?: number
|
||||
initialSupply?: number,
|
||||
): Promise<{ mint: PublicKey }> {
|
||||
try {
|
||||
// Create UMI instance from agent
|
||||
const umi = createUmi(agent.connection.rpcEndpoint).use(mplToolbox())
|
||||
const umi = createUmi(agent.connection.rpcEndpoint).use(mplToolbox());
|
||||
umi.use(keypairIdentity(fromWeb3JsKeypair(agent.wallet)));
|
||||
|
||||
// Create new token mint
|
||||
@@ -52,11 +60,11 @@ export async function deploy_token(
|
||||
tokenStandard: TokenStandard.Fungible,
|
||||
tokenOwner: fromWeb3JsPublicKey(agent.wallet_address),
|
||||
amount: initialSupply,
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
builder.sendAndConfirm(umi, { confirm: { commitment: 'finalized' } });
|
||||
builder.sendAndConfirm(umi, { confirm: { commitment: "finalized" } });
|
||||
|
||||
return {
|
||||
mint: toWeb3JsPublicKey(mint.publicKey),
|
||||
|
||||
@@ -1,20 +1,13 @@
|
||||
import { SolanaAgentKit } from "../index";
|
||||
import { Tool } from "langchain/tools";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
|
||||
/**
|
||||
* Fetch the price of a given token in USDC using Jupiter API
|
||||
* @param agent SolanaAgentKit instance
|
||||
* Fetch the price of a given token quoted in USDC using Jupiter API
|
||||
* @param tokenId The token mint address
|
||||
* @returns The price of the token in USDC
|
||||
* @returns The price of the token quoted in USDC
|
||||
*/
|
||||
export async function fetchPrice(
|
||||
agent: SolanaAgentKit,
|
||||
tokenId: string
|
||||
): Promise<string> {
|
||||
export async function fetchPrice(tokenId: PublicKey): Promise<string> {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`https://api.jup.ag/price/v2?ids=${tokenId}`
|
||||
);
|
||||
const response = await fetch(`https://api.jup.ag/price/v2?ids=${tokenId}`);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch price: ${response.statusText}`);
|
||||
@@ -22,7 +15,7 @@ export async function fetchPrice(
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
const price = data.data[tokenId]?.price;
|
||||
const price = data.data[tokenId.toBase58()]?.price;
|
||||
|
||||
if (!price) {
|
||||
throw new Error("Price data not available for the given token.");
|
||||
@@ -32,4 +25,4 @@ export async function fetchPrice(
|
||||
} catch (error: any) {
|
||||
throw new Error(`Price fetch failed: ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
19
src/tools/get_all_domains_tlds.ts
Normal file
19
src/tools/get_all_domains_tlds.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { SolanaAgentKit } from "../index";
|
||||
import { getAllTld } from "@onsol/tldparser";
|
||||
|
||||
/**
|
||||
* Get all active top-level domains (TLDs) in the AllDomains Name Service
|
||||
* @param agent SolanaAgentKit instance
|
||||
* @returns Array of active TLD strings
|
||||
*/
|
||||
export async function getAllDomainsTLDs(
|
||||
agent: SolanaAgentKit,
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
): Promise<String[]> {
|
||||
try {
|
||||
const tlds = await getAllTld(agent.connection);
|
||||
return tlds.map((tld) => tld.tld);
|
||||
} catch (error: any) {
|
||||
throw new Error(`Failed to fetch TLDs: ${error.message}`);
|
||||
}
|
||||
}
|
||||
36
src/tools/get_all_registered_all_domains.ts
Normal file
36
src/tools/get_all_registered_all_domains.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { getAllDomains } from "@bonfida/spl-name-service";
|
||||
import { SolanaAgentKit } from "../agent";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import { getAllDomainsTLDs } from "./get_all_domains_tlds";
|
||||
|
||||
/**
|
||||
* Get all registered domains across all TLDs
|
||||
* @param agent SolanaAgentKit instance
|
||||
* @returns Array of all registered domain names with their TLDs
|
||||
*/
|
||||
export async function getAllRegisteredAllDomains(
|
||||
agent: SolanaAgentKit,
|
||||
): Promise<string[]> {
|
||||
try {
|
||||
// First get all TLDs
|
||||
const tlds = await getAllDomainsTLDs(agent);
|
||||
const allDomains: string[] = [];
|
||||
|
||||
// For each TLD, fetch all registered domains
|
||||
for (const tld of tlds) {
|
||||
const domains = await getAllDomains(
|
||||
agent.connection,
|
||||
new PublicKey("namesLPneVptA9Z5rqUDD9tMTWEJwofgaYwp8cawRkX"),
|
||||
);
|
||||
|
||||
// Add domains with TLD suffix
|
||||
domains.forEach((domain) => {
|
||||
allDomains.push(`${domain}.${tld}`);
|
||||
});
|
||||
}
|
||||
|
||||
return allDomains;
|
||||
} catch (error: any) {
|
||||
throw new Error(`Failed to fetch all registered domains: ${error.message}`);
|
||||
}
|
||||
}
|
||||
@@ -11,11 +11,12 @@ export async function get_balance(
|
||||
agent: SolanaAgentKit,
|
||||
token_address?: PublicKey,
|
||||
): Promise<number> {
|
||||
if (!token_address)
|
||||
if (!token_address) {
|
||||
return (
|
||||
(await agent.connection.getBalance(agent.wallet_address)) /
|
||||
LAMPORTS_PER_SOL
|
||||
);
|
||||
}
|
||||
|
||||
const token_account =
|
||||
await agent.connection.getTokenAccountBalance(token_address);
|
||||
|
||||
21
src/tools/get_main_all_domains_domain.ts
Normal file
21
src/tools/get_main_all_domains_domain.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { getFavoriteDomain as _getFavoriteDomain } from "@bonfida/spl-name-service";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
|
||||
/**
|
||||
* Get the user's main/favorite domain for a SolanaAgentKit instance
|
||||
* @param agent SolanaAgentKit instance
|
||||
* @param owner Owner's public key
|
||||
* @returns Promise resolving to the main domain name or null if not found
|
||||
*/
|
||||
export async function getMainAllDomainsDomain(
|
||||
agent: any,
|
||||
owner: PublicKey,
|
||||
): Promise<string | null> {
|
||||
let mainDomain = null;
|
||||
try {
|
||||
mainDomain = await _getFavoriteDomain(agent.connection, owner);
|
||||
return mainDomain.stale ? null : mainDomain.reverse;
|
||||
} catch (error: any) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
23
src/tools/get_owned_all_domains.ts
Normal file
23
src/tools/get_owned_all_domains.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { SolanaAgentKit } from "../agent";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import { TldParser } from "@onsol/tldparser";
|
||||
|
||||
/**
|
||||
* Get all domains owned domains for a specific TLD for the agent's wallet
|
||||
* @param agent SolanaAgentKit instance
|
||||
* @param owner - PublicKey of the owner
|
||||
* @returns Promise resolving to an array of owned domains or an empty array if none are found
|
||||
*/
|
||||
export async function getOwnedAllDomains(
|
||||
agent: SolanaAgentKit,
|
||||
owner: PublicKey,
|
||||
): Promise<string[]> {
|
||||
try {
|
||||
const domains = await new TldParser(
|
||||
agent.connection,
|
||||
).getParsedAllUserDomains(owner);
|
||||
return domains.map((domain) => domain.domain);
|
||||
} catch (error: any) {
|
||||
throw new Error(`Failed to fetch owned domains: ${error.message}`);
|
||||
}
|
||||
}
|
||||
21
src/tools/get_owned_domains_for_tld.ts
Normal file
21
src/tools/get_owned_domains_for_tld.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { TldParser } from "@onsol/tldparser";
|
||||
import { SolanaAgentKit } from "../agent";
|
||||
/**
|
||||
* Get all domains owned by an address for a specific TLD
|
||||
* @param agent SolanaAgentKit instance
|
||||
* @param tld Top-level domain (e.g., "sol")
|
||||
* @returns Promise resolving to an array of owned domain names for the specified TLD or an empty array if none are found
|
||||
*/
|
||||
export async function getOwnedDomainsForTLD(
|
||||
agent: SolanaAgentKit,
|
||||
tld: string,
|
||||
): Promise<string[]> {
|
||||
try {
|
||||
const domains = await new TldParser(
|
||||
agent.connection,
|
||||
).getParsedAllUserDomainsFromTld(agent.wallet_address, tld);
|
||||
return domains.map((domain) => domain.domain);
|
||||
} catch (error: any) {
|
||||
throw new Error(`Failed to fetch domains for TLD: ${error.message}`);
|
||||
}
|
||||
}
|
||||
@@ -16,22 +16,22 @@ import { SolanaAgentKit } from "../index";
|
||||
*/
|
||||
export async function getPrimaryDomain(
|
||||
agent: SolanaAgentKit,
|
||||
account: PublicKey
|
||||
account: PublicKey,
|
||||
): Promise<string> {
|
||||
try {
|
||||
const { reverse, stale } = await _getPrimaryDomain(
|
||||
agent.connection,
|
||||
account
|
||||
account,
|
||||
);
|
||||
if (stale) {
|
||||
throw new Error(
|
||||
`Primary domain is stale for account: ${account.toBase58()}`
|
||||
`Primary domain is stale for account: ${account.toBase58()}`,
|
||||
);
|
||||
}
|
||||
return reverse;
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`Failed to get primary domain for account: ${account.toBase58()}`
|
||||
`Failed to get primary domain for account: ${account.toBase58()}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,11 +27,11 @@ export async function getTokenDataByAddress(
|
||||
}
|
||||
|
||||
export async function getTokenAddressFromTicker(
|
||||
ticker: string
|
||||
ticker: string,
|
||||
): Promise<string | null> {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`https://api.dexscreener.com/latest/dex/search?q=${ticker}`
|
||||
`https://api.dexscreener.com/latest/dex/search?q=${ticker}`,
|
||||
);
|
||||
const data = await response.json();
|
||||
|
||||
@@ -46,7 +46,7 @@ export async function getTokenAddressFromTicker(
|
||||
|
||||
solanaPairs = solanaPairs.filter(
|
||||
(pair: any) =>
|
||||
pair.baseToken.symbol.toLowerCase() === ticker.toLowerCase()
|
||||
pair.baseToken.symbol.toLowerCase() === ticker.toLowerCase(),
|
||||
);
|
||||
|
||||
// Return the address of the highest FDV Solana pair
|
||||
@@ -58,11 +58,11 @@ export async function getTokenAddressFromTicker(
|
||||
}
|
||||
|
||||
export async function getTokenDataByTicker(
|
||||
ticker: string
|
||||
ticker: string,
|
||||
): Promise<JupiterTokenData | undefined> {
|
||||
const address = await getTokenAddressFromTicker(ticker);
|
||||
if (!address) {
|
||||
throw new Error(`Token address not found for ticker: ${ticker}`);
|
||||
}
|
||||
return getTokenDataByAddress(new PublicKey(address));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,24 @@ export * from "./stake_with_jup";
|
||||
export * from "./fetch_price";
|
||||
export * from "./send_compressed_airdrop";
|
||||
export * from "./create_orca_single_sided_whirlpool";
|
||||
export * from "./get_all_domains_tlds";
|
||||
export * from "./get_all_registered_all_domains";
|
||||
export * from "./get_owned_domains_for_tld";
|
||||
export * from "./get_main_all_domains_domain";
|
||||
export * from "./get_owned_all_domains";
|
||||
export * from "./resolve_domain";
|
||||
|
||||
export * from "./get_all_domains_tlds";
|
||||
export * from "./get_all_registered_all_domains";
|
||||
export * from "./get_owned_domains_for_tld";
|
||||
export * from "./get_main_all_domains_domain";
|
||||
export * from "./get_owned_all_domains";
|
||||
export * from "./resolve_domain";
|
||||
|
||||
export * from "./raydium_create_ammV4";
|
||||
export * from "./raydium_create_clmm";
|
||||
export * from "./raydium_create_cpmm";
|
||||
export * from "./openbook_create_market";
|
||||
export * from "./pyth_fetch_price";
|
||||
export * from "./pyth_fetch_price";
|
||||
|
||||
export * from "./create_gibwork_task";
|
||||
|
||||
@@ -21,9 +21,15 @@ async function uploadMetadata(
|
||||
|
||||
formData.append("showName", "true");
|
||||
|
||||
if (options?.twitter) formData.append("twitter", options.twitter);
|
||||
if (options?.telegram) formData.append("telegram", options.telegram);
|
||||
if (options?.website) formData.append("website", options.website);
|
||||
if (options?.twitter) {
|
||||
formData.append("twitter", options.twitter);
|
||||
}
|
||||
if (options?.telegram) {
|
||||
formData.append("telegram", options.telegram);
|
||||
}
|
||||
if (options?.website) {
|
||||
formData.append("website", options.website);
|
||||
}
|
||||
|
||||
const imageResponse = await fetch(imageUrl);
|
||||
const imageBlob = await imageResponse.blob();
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { VersionedTransaction } from "@solana/web3.js";
|
||||
import { LuloAccountDetailsResponse } from "../types";
|
||||
import { SolanaAgentKit } from "../agent";
|
||||
import { SolanaAgentKit } from "../index";
|
||||
|
||||
/**
|
||||
* Lend tokens for yields using Lulo
|
||||
@@ -10,7 +9,7 @@ import { SolanaAgentKit } from "../agent";
|
||||
*/
|
||||
export async function lendAsset(
|
||||
agent: SolanaAgentKit,
|
||||
amount: number
|
||||
amount: number,
|
||||
): Promise<string> {
|
||||
try {
|
||||
const response = await fetch(
|
||||
@@ -23,14 +22,14 @@ export async function lendAsset(
|
||||
body: JSON.stringify({
|
||||
account: agent.wallet.publicKey.toBase58(),
|
||||
}),
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
// Deserialize the transaction
|
||||
const luloTxn = VersionedTransaction.deserialize(
|
||||
Buffer.from(data.transaction, "base64")
|
||||
Buffer.from(data.transaction, "base64"),
|
||||
);
|
||||
|
||||
// Get a recent blockhash and set it
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
import { SolanaAgentKit } from "../index";
|
||||
import { generateSigner, keypairIdentity } from '@metaplex-foundation/umi';
|
||||
import { create, mplCore } from '@metaplex-foundation/mpl-core';
|
||||
import { fetchCollection } from '@metaplex-foundation/mpl-core';
|
||||
import { generateSigner, keypairIdentity } from "@metaplex-foundation/umi";
|
||||
import { create, mplCore } from "@metaplex-foundation/mpl-core";
|
||||
import { fetchCollection } from "@metaplex-foundation/mpl-core";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import { fromWeb3JsKeypair, fromWeb3JsPublicKey, toWeb3JsPublicKey } from "@metaplex-foundation/umi-web3js-adapters";
|
||||
import { createUmi } from '@metaplex-foundation/umi-bundle-defaults';
|
||||
import { MintCollectionNFTResponse } from '../types';
|
||||
import {
|
||||
fromWeb3JsKeypair,
|
||||
fromWeb3JsPublicKey,
|
||||
toWeb3JsPublicKey,
|
||||
} from "@metaplex-foundation/umi-web3js-adapters";
|
||||
import { createUmi } from "@metaplex-foundation/umi-bundle-defaults";
|
||||
import { MintCollectionNFTResponse } from "../types";
|
||||
|
||||
/**
|
||||
* Mint a new NFT as part of an existing collection
|
||||
@@ -27,7 +31,7 @@ export async function mintCollectionNFT(
|
||||
share: number;
|
||||
}>;
|
||||
},
|
||||
recipient?: PublicKey
|
||||
recipient?: PublicKey,
|
||||
): Promise<MintCollectionNFTResponse> {
|
||||
try {
|
||||
// Create UMI instance from agent
|
||||
@@ -49,15 +53,15 @@ export async function mintCollectionNFT(
|
||||
collection: collection,
|
||||
name: metadata.name,
|
||||
uri: metadata.uri,
|
||||
owner: fromWeb3JsPublicKey(recipient ?? agent.wallet.publicKey)
|
||||
owner: fromWeb3JsPublicKey(recipient ?? agent.wallet.publicKey),
|
||||
}).sendAndConfirm(umi);
|
||||
|
||||
return {
|
||||
mint: toWeb3JsPublicKey(assetSigner.publicKey),
|
||||
// Note: Token account is now handled automatically by the create instruction
|
||||
metadata: toWeb3JsPublicKey(assetSigner.publicKey)
|
||||
metadata: toWeb3JsPublicKey(assetSigner.publicKey),
|
||||
};
|
||||
} catch (error: any) {
|
||||
throw new Error(`Collection NFT minting failed: ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,33 +1,34 @@
|
||||
import { OPEN_BOOK_PROGRAM, Raydium, TxVersion } from "@raydium-io/raydium-sdk-v2";
|
||||
import {
|
||||
OPEN_BOOK_PROGRAM,
|
||||
Raydium,
|
||||
TxVersion,
|
||||
} from "@raydium-io/raydium-sdk-v2";
|
||||
import { MintLayout, TOKEN_PROGRAM_ID } from "@solana/spl-token";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import { SolanaAgentKit } from "../agent";
|
||||
import { SolanaAgentKit } from "../index";
|
||||
|
||||
export async function openbookCreateMarket(
|
||||
agent: SolanaAgentKit,
|
||||
|
||||
baseMint: PublicKey,
|
||||
quoteMint: PublicKey,
|
||||
|
||||
lotSize: number = 1,
|
||||
tickSize: number = 0.01,
|
||||
): Promise<string[]> {
|
||||
|
||||
const raydium = await Raydium.load({
|
||||
owner: agent.wallet,
|
||||
connection: agent.connection,
|
||||
})
|
||||
});
|
||||
|
||||
const baseMintInfo = await agent.connection.getAccountInfo(baseMint)
|
||||
const quoteMintInfo = await agent.connection.getAccountInfo(quoteMint)
|
||||
const baseMintInfo = await agent.connection.getAccountInfo(baseMint);
|
||||
const quoteMintInfo = await agent.connection.getAccountInfo(quoteMint);
|
||||
|
||||
if (
|
||||
baseMintInfo?.owner.toString() !== TOKEN_PROGRAM_ID.toBase58() ||
|
||||
quoteMintInfo?.owner.toString() !== TOKEN_PROGRAM_ID.toBase58()
|
||||
) {
|
||||
throw new Error(
|
||||
'openbook market only support TOKEN_PROGRAM_ID mints, if you want to create pool with token-2022, please create raydium cpmm pool instead'
|
||||
)
|
||||
"openbook market only support TOKEN_PROGRAM_ID mints, if you want to create pool with token-2022, please create raydium cpmm pool instead",
|
||||
);
|
||||
}
|
||||
|
||||
const { execute } = await raydium.marketV2.create({
|
||||
@@ -44,9 +45,9 @@ export async function openbookCreateMarket(
|
||||
dexProgramId: OPEN_BOOK_PROGRAM,
|
||||
|
||||
txVersion: TxVersion.V0,
|
||||
})
|
||||
});
|
||||
|
||||
const { txIds } = await execute({ sequentially: true, })
|
||||
const { txIds } = await execute({ sequentially: true });
|
||||
|
||||
return txIds
|
||||
return txIds;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import { SolanaAgentKit } from "../index";
|
||||
import { Tool } from "langchain/tools";
|
||||
import { PriceServiceConnection } from "@pythnetwork/price-service-client";
|
||||
import BN from "bn.js";
|
||||
|
||||
@@ -9,40 +6,35 @@ import BN from "bn.js";
|
||||
* @param agent SolanaAgentKit instance
|
||||
* @param priceFeedID Price feed ID
|
||||
* @returns Latest price value from feed
|
||||
*
|
||||
*
|
||||
* You can find priceFeedIDs here: https://www.pyth.network/developers/price-feed-ids#stable
|
||||
*/
|
||||
export async function pythFetchPrice(
|
||||
agent: SolanaAgentKit,
|
||||
priceFeedID: string
|
||||
) {
|
||||
// get Hermes service URL from https://docs.pyth.network/price-feeds/api-instances-and-providers/hermes
|
||||
export async function pythFetchPrice(priceFeedID: string): Promise<string> {
|
||||
// get Hermes service URL from https://docs.pyth.network/price-feeds/api-instances-and-providers/hermes
|
||||
const stableHermesServiceUrl: string = "https://hermes.pyth.network";
|
||||
const connection = new PriceServiceConnection(stableHermesServiceUrl);
|
||||
const feeds = [priceFeedID];
|
||||
|
||||
try {
|
||||
const currentPrice = await connection.getLatestPriceFeeds(feeds);
|
||||
|
||||
|
||||
if (currentPrice === undefined) {
|
||||
throw new Error("Price data not available for the given token.");
|
||||
}
|
||||
|
||||
|
||||
if (currentPrice.length === 0) {
|
||||
throw new Error("Price data not available for the given token.");
|
||||
}
|
||||
|
||||
|
||||
// get price and exponent from price feed
|
||||
let price = new BN(currentPrice[0].getPriceUnchecked().price);
|
||||
let exponent = new BN(currentPrice[0].getPriceUnchecked().expo);
|
||||
|
||||
const price = new BN(currentPrice[0].getPriceUnchecked().price);
|
||||
const exponent = new BN(currentPrice[0].getPriceUnchecked().expo);
|
||||
|
||||
// convert to scaled price
|
||||
let scaledPrice = price.div(new BN(10).pow(exponent));
|
||||
|
||||
const scaledPrice = price.div(new BN(10).pow(exponent));
|
||||
|
||||
return scaledPrice.toString();
|
||||
} catch (error: any) {
|
||||
throw new Error(`Fetching price from Pyth failed: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,42 +1,59 @@
|
||||
import { AMM_V4, FEE_DESTINATION_ID, MARKET_STATE_LAYOUT_V3, OPEN_BOOK_PROGRAM, Raydium, TxVersion } from "@raydium-io/raydium-sdk-v2";
|
||||
import {
|
||||
AMM_V4,
|
||||
FEE_DESTINATION_ID,
|
||||
MARKET_STATE_LAYOUT_V3,
|
||||
OPEN_BOOK_PROGRAM,
|
||||
Raydium,
|
||||
TxVersion,
|
||||
} from "@raydium-io/raydium-sdk-v2";
|
||||
import { MintLayout, TOKEN_PROGRAM_ID } from "@solana/spl-token";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import BN from 'bn.js';
|
||||
import { SolanaAgentKit } from "../agent";
|
||||
import BN from "bn.js";
|
||||
import { SolanaAgentKit } from "../index";
|
||||
|
||||
export async function raydiumCreateAmmV4(
|
||||
agent: SolanaAgentKit,
|
||||
|
||||
marketId: PublicKey,
|
||||
|
||||
baseAmount: BN,
|
||||
quoteAmount: BN,
|
||||
|
||||
startTime: BN,
|
||||
): Promise<string> {
|
||||
|
||||
const raydium = await Raydium.load({
|
||||
owner: agent.wallet,
|
||||
connection: agent.connection,
|
||||
})
|
||||
});
|
||||
|
||||
const marketBufferInfo = await agent.connection.getAccountInfo(new PublicKey(marketId))
|
||||
const { baseMint, quoteMint } = MARKET_STATE_LAYOUT_V3.decode(marketBufferInfo!.data)
|
||||
const marketBufferInfo = await agent.connection.getAccountInfo(
|
||||
new PublicKey(marketId),
|
||||
);
|
||||
const { baseMint, quoteMint } = MARKET_STATE_LAYOUT_V3.decode(
|
||||
marketBufferInfo!.data,
|
||||
);
|
||||
|
||||
const baseMintInfo = await agent.connection.getAccountInfo(baseMint)
|
||||
const quoteMintInfo = await agent.connection.getAccountInfo(quoteMint)
|
||||
const baseMintInfo = await agent.connection.getAccountInfo(baseMint);
|
||||
const quoteMintInfo = await agent.connection.getAccountInfo(quoteMint);
|
||||
|
||||
if (
|
||||
baseMintInfo?.owner.toString() !== TOKEN_PROGRAM_ID.toBase58() ||
|
||||
quoteMintInfo?.owner.toString() !== TOKEN_PROGRAM_ID.toBase58()
|
||||
) {
|
||||
throw new Error(
|
||||
'amm pools with openbook market only support TOKEN_PROGRAM_ID mints, if you want to create pool with token-2022, please create cpmm pool instead'
|
||||
)
|
||||
"amm pools with openbook market only support TOKEN_PROGRAM_ID mints, if you want to create pool with token-2022, please create cpmm pool instead",
|
||||
);
|
||||
}
|
||||
|
||||
if (baseAmount.mul(quoteAmount).lte(new BN(1).mul(new BN(10 ** MintLayout.decode(baseMintInfo.data).decimals)).pow(new BN(2)))) {
|
||||
throw new Error('initial liquidity too low, try adding more baseAmount/quoteAmount')
|
||||
if (
|
||||
baseAmount
|
||||
.mul(quoteAmount)
|
||||
.lte(
|
||||
new BN(1)
|
||||
.mul(new BN(10 ** MintLayout.decode(baseMintInfo.data).decimals))
|
||||
.pow(new BN(2)),
|
||||
)
|
||||
) {
|
||||
throw new Error(
|
||||
"initial liquidity too low, try adding more baseAmount/quoteAmount",
|
||||
);
|
||||
}
|
||||
|
||||
const { execute } = await raydium.liquidity.createPoolV4({
|
||||
@@ -63,9 +80,9 @@ export async function raydiumCreateAmmV4(
|
||||
associatedOnly: false,
|
||||
txVersion: TxVersion.V0,
|
||||
feeDestinationId: FEE_DESTINATION_ID,
|
||||
})
|
||||
});
|
||||
|
||||
const { txId } = await execute({ sendAndConfirm: true })
|
||||
const { txId } = await execute({ sendAndConfirm: true });
|
||||
|
||||
return txId
|
||||
}
|
||||
return txId;
|
||||
}
|
||||
|
||||
@@ -1,62 +1,66 @@
|
||||
import { CLMM_PROGRAM_ID, Raydium, TxVersion } from '@raydium-io/raydium-sdk-v2'
|
||||
import { MintLayout } from '@solana/spl-token'
|
||||
import { PublicKey } from '@solana/web3.js'
|
||||
import BN from 'bn.js'
|
||||
import Decimal from 'decimal.js'
|
||||
import { SolanaAgentKit } from '../agent'
|
||||
import {
|
||||
CLMM_PROGRAM_ID,
|
||||
Raydium,
|
||||
TxVersion,
|
||||
} from "@raydium-io/raydium-sdk-v2";
|
||||
import { MintLayout } from "@solana/spl-token";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import BN from "bn.js";
|
||||
import Decimal from "decimal.js";
|
||||
import { SolanaAgentKit } from "../index";
|
||||
|
||||
export async function raydiumCreateClmm(
|
||||
agent: SolanaAgentKit,
|
||||
|
||||
mint1: PublicKey,
|
||||
mint2: PublicKey,
|
||||
|
||||
configId: PublicKey,
|
||||
|
||||
initialPrice: Decimal,
|
||||
startTime: BN,
|
||||
): Promise<string> {
|
||||
|
||||
const raydium = await Raydium.load({
|
||||
owner: agent.wallet,
|
||||
connection: agent.connection,
|
||||
})
|
||||
});
|
||||
|
||||
const [mintInfo1, mintInfo2] = await agent.connection.getMultipleAccountsInfo([mint1, mint2])
|
||||
if (mintInfo1 === null || mintInfo2 === null) throw Error('fetch mint info error')
|
||||
const [mintInfo1, mintInfo2] = await agent.connection.getMultipleAccountsInfo(
|
||||
[mint1, mint2],
|
||||
);
|
||||
if (mintInfo1 === null || mintInfo2 === null) {
|
||||
throw Error("fetch mint info error");
|
||||
}
|
||||
|
||||
const mintDecodeInfo1 = MintLayout.decode(mintInfo1.data)
|
||||
const mintDecodeInfo2 = MintLayout.decode(mintInfo2.data)
|
||||
const mintDecodeInfo1 = MintLayout.decode(mintInfo1.data);
|
||||
const mintDecodeInfo2 = MintLayout.decode(mintInfo2.data);
|
||||
|
||||
const mintFormatInfo1 = {
|
||||
chainId: 101,
|
||||
address: mint1.toString(),
|
||||
programId: mintInfo1.owner.toString(),
|
||||
logoURI: '',
|
||||
symbol: '',
|
||||
name: '',
|
||||
logoURI: "",
|
||||
symbol: "",
|
||||
name: "",
|
||||
decimals: mintDecodeInfo1.decimals,
|
||||
tags: [],
|
||||
extensions: {}
|
||||
}
|
||||
extensions: {},
|
||||
};
|
||||
const mintFormatInfo2 = {
|
||||
chainId: 101,
|
||||
address: mint2.toString(),
|
||||
programId: mintInfo2.owner.toString(),
|
||||
logoURI: '',
|
||||
symbol: '',
|
||||
name: '',
|
||||
logoURI: "",
|
||||
symbol: "",
|
||||
name: "",
|
||||
decimals: mintDecodeInfo2.decimals,
|
||||
tags: [],
|
||||
extensions: {}
|
||||
}
|
||||
extensions: {},
|
||||
};
|
||||
|
||||
const { execute } = await raydium.clmm.createPool({
|
||||
programId: CLMM_PROGRAM_ID,
|
||||
// programId: DEVNET_PROGRAM_ID.CLMM,
|
||||
mint1: mintFormatInfo1,
|
||||
mint2: mintFormatInfo2,
|
||||
// @ts-ignore
|
||||
// @ts-expect-error sdk bug
|
||||
ammConfig: { id: configId },
|
||||
initialPrice,
|
||||
startTime,
|
||||
@@ -65,9 +69,9 @@ export async function raydiumCreateClmm(
|
||||
// units: 600000,
|
||||
// microLamports: 46591500,
|
||||
// },
|
||||
})
|
||||
});
|
||||
|
||||
const { txId } = await execute({ sendAndConfirm: true })
|
||||
const { txId } = await execute({ sendAndConfirm: true });
|
||||
|
||||
return txId
|
||||
return txId;
|
||||
}
|
||||
|
||||
@@ -2,62 +2,61 @@ import {
|
||||
CREATE_CPMM_POOL_FEE_ACC,
|
||||
CREATE_CPMM_POOL_PROGRAM,
|
||||
Raydium,
|
||||
TxVersion
|
||||
} from '@raydium-io/raydium-sdk-v2'
|
||||
import { MintLayout } from '@solana/spl-token'
|
||||
import { PublicKey } from '@solana/web3.js'
|
||||
import BN from 'bn.js'
|
||||
import { SolanaAgentKit } from '../agent'
|
||||
TxVersion,
|
||||
} from "@raydium-io/raydium-sdk-v2";
|
||||
import { MintLayout } from "@solana/spl-token";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import BN from "bn.js";
|
||||
import { SolanaAgentKit } from "../index";
|
||||
|
||||
export async function raydiumCreateCpmm(
|
||||
agent: SolanaAgentKit,
|
||||
|
||||
mintA: PublicKey,
|
||||
mintB: PublicKey,
|
||||
|
||||
configId: PublicKey,
|
||||
|
||||
mintAAmount: BN,
|
||||
mintBAmount: BN,
|
||||
|
||||
startTime: BN,
|
||||
): Promise<string> {
|
||||
|
||||
const raydium = await Raydium.load({
|
||||
owner: agent.wallet,
|
||||
connection: agent.connection,
|
||||
})
|
||||
});
|
||||
|
||||
const [mintInfoA, mintInfoB] = await agent.connection.getMultipleAccountsInfo([mintA, mintB])
|
||||
if (mintInfoA === null || mintInfoB === null) throw Error('fetch mint info error')
|
||||
const [mintInfoA, mintInfoB] = await agent.connection.getMultipleAccountsInfo(
|
||||
[mintA, mintB],
|
||||
);
|
||||
if (mintInfoA === null || mintInfoB === null) {
|
||||
throw Error("fetch mint info error");
|
||||
}
|
||||
|
||||
const mintDecodeInfoA = MintLayout.decode(mintInfoA.data)
|
||||
const mintDecodeInfoB = MintLayout.decode(mintInfoB.data)
|
||||
const mintDecodeInfoA = MintLayout.decode(mintInfoA.data);
|
||||
const mintDecodeInfoB = MintLayout.decode(mintInfoB.data);
|
||||
|
||||
const mintFormatInfoA = {
|
||||
chainId: 101,
|
||||
address: mintA.toString(),
|
||||
programId: mintInfoA.owner.toString(),
|
||||
logoURI: '',
|
||||
symbol: '',
|
||||
name: '',
|
||||
logoURI: "",
|
||||
symbol: "",
|
||||
name: "",
|
||||
decimals: mintDecodeInfoA.decimals,
|
||||
tags: [],
|
||||
extensions: {}
|
||||
}
|
||||
extensions: {},
|
||||
};
|
||||
const mintFormatInfoB = {
|
||||
chainId: 101,
|
||||
address: mintB.toString(),
|
||||
programId: mintInfoB.owner.toString(),
|
||||
logoURI: '',
|
||||
symbol: '',
|
||||
name: '',
|
||||
logoURI: "",
|
||||
symbol: "",
|
||||
name: "",
|
||||
decimals: mintDecodeInfoB.decimals,
|
||||
tags: [],
|
||||
extensions: {}
|
||||
}
|
||||
extensions: {},
|
||||
};
|
||||
|
||||
const { execute, extInfo } = await raydium.cpmm.createPool({
|
||||
const { execute } = await raydium.cpmm.createPool({
|
||||
programId: CREATE_CPMM_POOL_PROGRAM,
|
||||
poolFeeAccount: CREATE_CPMM_POOL_FEE_ACC,
|
||||
mintA: mintFormatInfoA,
|
||||
@@ -65,7 +64,7 @@ export async function raydiumCreateCpmm(
|
||||
mintAAmount,
|
||||
mintBAmount,
|
||||
startTime,
|
||||
//@ts-ignore
|
||||
//@ts-expect-error sdk bug
|
||||
feeConfig: { id: configId.toString() },
|
||||
associatedOnly: false,
|
||||
ownerInfo: {
|
||||
@@ -76,9 +75,9 @@ export async function raydiumCreateCpmm(
|
||||
// units: 600000,
|
||||
// microLamports: 46591500,
|
||||
// },
|
||||
})
|
||||
});
|
||||
|
||||
const { txId } = await execute({ sendAndConfirm: true })
|
||||
const { txId } = await execute({ sendAndConfirm: true });
|
||||
|
||||
return txId
|
||||
return txId;
|
||||
}
|
||||
|
||||
30
src/tools/resolve_domain.ts
Normal file
30
src/tools/resolve_domain.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { TldParser } from "@onsol/tldparser";
|
||||
import { SolanaAgentKit } from "../index";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
|
||||
/**
|
||||
* Resolve all domains for a given agent and domain
|
||||
* @param agent SolanaAgentKit instance
|
||||
* @param domain Domain name to resolve
|
||||
* @returns Promise resolving to the domain or undefined if not found
|
||||
*/
|
||||
export async function resolveAllDomains(
|
||||
agent: SolanaAgentKit,
|
||||
domain: string,
|
||||
): Promise<PublicKey | undefined> {
|
||||
try {
|
||||
const tld = await new TldParser(agent.connection).getOwnerFromDomainTld(
|
||||
domain,
|
||||
);
|
||||
return tld;
|
||||
} catch (error: any) {
|
||||
if (
|
||||
error.message.includes(
|
||||
"Cannot read properties of undefined (reading 'owner')",
|
||||
)
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
throw new Error(`Domain resolution failed: ${error.message}`);
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ import { SolanaAgentKit } from "../index";
|
||||
*/
|
||||
export async function resolveSolDomain(
|
||||
agent: SolanaAgentKit,
|
||||
domain: string
|
||||
domain: string,
|
||||
): Promise<PublicKey> {
|
||||
if (!domain || typeof domain !== "string") {
|
||||
throw new Error("Invalid domain. Expected a non-empty string.");
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import {
|
||||
AddressLookupTableAccount,
|
||||
ComputeBudgetProgram,
|
||||
Connection,
|
||||
Keypair,
|
||||
PublicKey,
|
||||
TransactionInstruction,
|
||||
} from "@solana/web3.js";
|
||||
import { SolanaAgentKit } from "../agent/index.js";
|
||||
import { SolanaAgentKit } from "../index";
|
||||
import {
|
||||
buildAndSignTx,
|
||||
calculateComputeUnitPrice,
|
||||
@@ -19,7 +18,7 @@ import {
|
||||
CompressedTokenProgram,
|
||||
createTokenPool,
|
||||
} from "@lightprotocol/compressed-token";
|
||||
import { Account, getOrCreateAssociatedTokenAccount } from "@solana/spl-token";
|
||||
import { getOrCreateAssociatedTokenAccount } from "@solana/spl-token";
|
||||
|
||||
// arbitrary
|
||||
const MAX_AIRDROP_RECIPIENTS = 1000;
|
||||
@@ -33,7 +32,7 @@ const MAX_CONCURRENT_TXS = 30;
|
||||
*/
|
||||
export const getAirdropCostEstimate = (
|
||||
numberOfRecipients: number,
|
||||
priorityFeeInLamports: number
|
||||
priorityFeeInLamports: number,
|
||||
) => {
|
||||
const baseFee = 5000;
|
||||
const perRecipientCompressedStateFee = 300;
|
||||
@@ -63,36 +62,34 @@ export async function sendCompressedAirdrop(
|
||||
decimals: number,
|
||||
recipients: PublicKey[],
|
||||
priorityFeeInLamports: number,
|
||||
shouldLog: boolean = false
|
||||
shouldLog: boolean = false,
|
||||
): Promise<string[]> {
|
||||
if (recipients.length > MAX_AIRDROP_RECIPIENTS) {
|
||||
throw new Error(
|
||||
`Max airdrop can be ${MAX_AIRDROP_RECIPIENTS} recipients at a time. For more scale, use open source ZK Compression airdrop tools such as https://github.com/helius-labs/airship.`
|
||||
`Max airdrop can be ${MAX_AIRDROP_RECIPIENTS} recipients at a time. For more scale, use open source ZK Compression airdrop tools such as https://github.com/helius-labs/airship.`,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
const url = agent.connection.rpcEndpoint;
|
||||
if (url.includes("devnet")) {
|
||||
throw new Error("Devnet is not supported for airdrop. Please use mainnet.");
|
||||
}
|
||||
if (!url.includes("helius")) {
|
||||
console.warn(
|
||||
"Warning: Must use RPC with ZK Compression support. Double check with your RPC provider if in doubt."
|
||||
"Warning: Must use RPC with ZK Compression support. Double check with your RPC provider if in doubt.",
|
||||
);
|
||||
}
|
||||
|
||||
let sourceTokenAccount: Account;
|
||||
try {
|
||||
sourceTokenAccount = await getOrCreateAssociatedTokenAccount(
|
||||
await getOrCreateAssociatedTokenAccount(
|
||||
agent.connection,
|
||||
agent.wallet,
|
||||
mintAddress,
|
||||
agent.wallet.publicKey
|
||||
agent.wallet.publicKey,
|
||||
);
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
"Source token account not found and failed to create it. Please add funds to your wallet and try again."
|
||||
"Source token account not found and failed to create it. Please add funds to your wallet and try again.",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -100,7 +97,7 @@ export async function sendCompressedAirdrop(
|
||||
await createTokenPool(
|
||||
agent.connection as unknown as Rpc,
|
||||
agent.wallet,
|
||||
mintAddress
|
||||
mintAddress,
|
||||
);
|
||||
} catch (error: any) {
|
||||
if (error.message.includes("already in use")) {
|
||||
@@ -116,7 +113,7 @@ export async function sendCompressedAirdrop(
|
||||
mintAddress,
|
||||
recipients,
|
||||
priorityFeeInLamports,
|
||||
shouldLog
|
||||
shouldLog,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -126,7 +123,7 @@ async function processAll(
|
||||
mint: PublicKey,
|
||||
recipients: PublicKey[],
|
||||
priorityFeeInLamports: number,
|
||||
shouldLog: boolean
|
||||
shouldLog: boolean,
|
||||
): Promise<string[]> {
|
||||
const mintAddress = mint;
|
||||
const payer = agent.wallet;
|
||||
@@ -135,13 +132,13 @@ async function processAll(
|
||||
agent.connection,
|
||||
agent.wallet,
|
||||
mintAddress,
|
||||
agent.wallet.publicKey
|
||||
agent.wallet.publicKey,
|
||||
);
|
||||
|
||||
const maxRecipientsPerInstruction = 5;
|
||||
const maxIxs = 3; // empirically determined (as of 12/15/2024)
|
||||
const lookupTableAddress = new PublicKey(
|
||||
"9NYFyEqPkyXUhkerbGHXUXkvb4qpzeEdHuGpgbgpH1NJ"
|
||||
"9NYFyEqPkyXUhkerbGHXUXkvb4qpzeEdHuGpgbgpH1NJ",
|
||||
);
|
||||
|
||||
const lookupTableAccount = (
|
||||
@@ -164,7 +161,7 @@ async function processAll(
|
||||
ComputeBudgetProgram.setComputeUnitPrice({
|
||||
microLamports: calculateComputeUnitPrice(
|
||||
priorityFeeInLamports,
|
||||
500_000
|
||||
500_000,
|
||||
),
|
||||
}),
|
||||
];
|
||||
@@ -184,13 +181,13 @@ async function processAll(
|
||||
toAddress: batch,
|
||||
amount: batch.map(() => amount),
|
||||
mint: mintAddress,
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
const compressIxs = await Promise.all(compressIxPromises);
|
||||
return [...instructions, ...compressIxs];
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
const url = agent.connection.rpcEndpoint;
|
||||
@@ -225,12 +222,12 @@ async function processAll(
|
||||
instructions,
|
||||
payer,
|
||||
lookupTableAccount,
|
||||
i + idx
|
||||
i + idx,
|
||||
).then((signature) => {
|
||||
confirmedCount++;
|
||||
log("\r" + renderProgressBar(confirmedCount, totalBatches));
|
||||
return signature;
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
const batchResults = await Promise.allSettled(batchPromises);
|
||||
@@ -250,7 +247,7 @@ async function processAll(
|
||||
throw new Error(
|
||||
`Failed to process ${failures.length} batches: ${failures
|
||||
.map((f) => f.error)
|
||||
.join(", ")}`
|
||||
.join(", ")}`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -262,7 +259,7 @@ async function sendTransactionWithRetry(
|
||||
instructions: TransactionInstruction[],
|
||||
payer: Keypair,
|
||||
lookupTableAccount: AddressLookupTableAccount,
|
||||
batchIndex: number
|
||||
batchIndex: number,
|
||||
): Promise<string> {
|
||||
const MAX_RETRIES = 3;
|
||||
const INITIAL_BACKOFF = 500; // ms
|
||||
@@ -275,7 +272,7 @@ async function sendTransactionWithRetry(
|
||||
payer,
|
||||
blockhash,
|
||||
[],
|
||||
[lookupTableAccount]
|
||||
[lookupTableAccount],
|
||||
);
|
||||
|
||||
const signature = await sendAndConfirmTx(connection, tx);
|
||||
@@ -292,7 +289,7 @@ async function sendTransactionWithRetry(
|
||||
throw new Error(
|
||||
`Batch ${batchIndex} failed after ${attempt + 1} attempts: ${
|
||||
error.message
|
||||
}`
|
||||
}`,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { VersionedTransaction } from "@solana/web3.js";
|
||||
import { SolanaAgentKit } from "../agent";
|
||||
import { SolanaAgentKit } from "../index";
|
||||
|
||||
/**
|
||||
* Stake SOL with Jup validator
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import { VersionedTransaction, PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js";
|
||||
import {
|
||||
VersionedTransaction,
|
||||
PublicKey,
|
||||
LAMPORTS_PER_SOL,
|
||||
} from "@solana/web3.js";
|
||||
import { SolanaAgentKit } from "../index";
|
||||
import { TOKENS, DEFAULT_OPTIONS, JUP_API } from "../constants";
|
||||
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
import { SolanaAgentKit } from "../index";
|
||||
import {
|
||||
PublicKey,
|
||||
SystemProgram,
|
||||
Transaction
|
||||
} from "@solana/web3.js";
|
||||
import { PublicKey, SystemProgram, Transaction } from "@solana/web3.js";
|
||||
import { LAMPORTS_PER_SOL } from "@solana/web3.js";
|
||||
import {
|
||||
getAssociatedTokenAddress,
|
||||
import {
|
||||
getAssociatedTokenAddress,
|
||||
createTransferInstruction,
|
||||
getMint
|
||||
getMint,
|
||||
} from "@solana/spl-token";
|
||||
|
||||
/**
|
||||
@@ -23,7 +19,7 @@ export async function transfer(
|
||||
agent: SolanaAgentKit,
|
||||
to: PublicKey,
|
||||
amount: number,
|
||||
mint?: PublicKey
|
||||
mint?: PublicKey,
|
||||
): Promise<string> {
|
||||
try {
|
||||
let tx: string;
|
||||
@@ -34,19 +30,19 @@ export async function transfer(
|
||||
SystemProgram.transfer({
|
||||
fromPubkey: agent.wallet_address,
|
||||
toPubkey: to,
|
||||
lamports: amount * LAMPORTS_PER_SOL
|
||||
})
|
||||
lamports: amount * LAMPORTS_PER_SOL,
|
||||
}),
|
||||
);
|
||||
|
||||
tx = await agent.connection.sendTransaction(
|
||||
transaction,
|
||||
[agent.wallet]
|
||||
);
|
||||
tx = await agent.connection.sendTransaction(transaction, [agent.wallet]);
|
||||
} else {
|
||||
// Transfer SPL token
|
||||
const fromAta = await getAssociatedTokenAddress(mint, agent.wallet_address);
|
||||
const fromAta = await getAssociatedTokenAddress(
|
||||
mint,
|
||||
agent.wallet_address,
|
||||
);
|
||||
const toAta = await getAssociatedTokenAddress(mint, to);
|
||||
|
||||
|
||||
// Get mint info to determine decimals
|
||||
const mintInfo = await getMint(agent.connection, mint);
|
||||
const adjustedAmount = amount * Math.pow(10, mintInfo.decimals);
|
||||
@@ -56,18 +52,15 @@ export async function transfer(
|
||||
fromAta,
|
||||
toAta,
|
||||
agent.wallet_address,
|
||||
adjustedAmount
|
||||
)
|
||||
adjustedAmount,
|
||||
),
|
||||
);
|
||||
|
||||
tx = await agent.connection.sendTransaction(
|
||||
transaction,
|
||||
[agent.wallet]
|
||||
);
|
||||
tx = await agent.connection.sendTransaction(transaction, [agent.wallet]);
|
||||
}
|
||||
|
||||
return tx;
|
||||
} catch (error: any) {
|
||||
throw new Error(`Transfer failed: ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,3 +85,9 @@ export interface PythFetchPriceResponse {
|
||||
message?: string;
|
||||
code?: string;
|
||||
}
|
||||
|
||||
export interface GibworkCreateTaskReponse {
|
||||
status: "success" | "error";
|
||||
taskId?: string | undefined;
|
||||
signature?: string | undefined;
|
||||
}
|
||||
|
||||
@@ -4,4 +4,4 @@ import bs58 from "bs58";
|
||||
export const keypair = Keypair.generate();
|
||||
|
||||
console.log(keypair.publicKey.toString());
|
||||
console.log(bs58.encode(keypair.secretKey));
|
||||
console.log(bs58.encode(keypair.secretKey));
|
||||
|
||||
@@ -14,7 +14,7 @@ function validateEnvironment(): void {
|
||||
const missingVars: string[] = [];
|
||||
const requiredVars = ["OPENAI_API_KEY", "RPC_URL", "SOLANA_PRIVATE_KEY"];
|
||||
|
||||
requiredVars.forEach(varName => {
|
||||
requiredVars.forEach((varName) => {
|
||||
if (!process.env[varName]) {
|
||||
missingVars.push(varName);
|
||||
}
|
||||
@@ -22,7 +22,7 @@ function validateEnvironment(): void {
|
||||
|
||||
if (missingVars.length > 0) {
|
||||
console.error("Error: Required environment variables are not set");
|
||||
missingVars.forEach(varName => {
|
||||
missingVars.forEach((varName) => {
|
||||
console.error(`${varName}=your_${varName.toLowerCase()}_here`);
|
||||
});
|
||||
process.exit(1);
|
||||
@@ -50,13 +50,13 @@ async function initializeAgent() {
|
||||
}
|
||||
}
|
||||
|
||||
const solanaKit = new SolanaAgentKit(
|
||||
const solanaAgent = new SolanaAgentKit(
|
||||
process.env.SOLANA_PRIVATE_KEY!,
|
||||
process.env.RPC_URL,
|
||||
process.env.OPENAI_API_KEY!
|
||||
process.env.OPENAI_API_KEY!,
|
||||
);
|
||||
|
||||
const tools = createSolanaTools(solanaKit);
|
||||
const tools = createSolanaTools(solanaAgent);
|
||||
const memory = new MemorySaver();
|
||||
const config = { configurable: { thread_id: "Solana Agent Kit!" } };
|
||||
|
||||
@@ -65,14 +65,13 @@ async function initializeAgent() {
|
||||
tools,
|
||||
checkpointSaver: memory,
|
||||
messageModifier: `
|
||||
You are a helpful agent that can interact onchain using the Solana Agent Kit. You are
|
||||
empowered to interact onchain using your tools. If you ever need funds, you can request them from the
|
||||
faucet. If not, you can provide your wallet details and request funds from the user. If there is a 5XX
|
||||
(internal) HTTP error code, ask the user to try again later. If someone asks you to do something you
|
||||
can't do with your currently available tools, you must say so, and encourage them to implement it
|
||||
themselves using the Solana Agent Kit, recommend they go to https://www.solanaagentkit.xyz for more information. Be
|
||||
concise and helpful with your responses. Refrain from restating your tools' descriptions unless it is
|
||||
explicitly requested.
|
||||
You are a helpful agent that can interact onchain using the Solana Agent Kit. You are
|
||||
empowered to interact onchain using your tools. If you ever need funds, you can request them from the
|
||||
faucet. If not, you can provide your wallet details and request funds from the user. If there is a 5XX
|
||||
(internal) HTTP error code, ask the user to try again later. If someone asks you to do something you
|
||||
can't do with your currently available tools, you must say so, and encourage them to implement it
|
||||
themselves using the Solana Agent Kit, recommend they go to https://www.solanaagentkit.xyz for more information. Be
|
||||
concise and helpful with your responses. Refrain from restating your tools' descriptions unless it is explicitly requested.
|
||||
`,
|
||||
});
|
||||
|
||||
@@ -96,7 +95,10 @@ async function runAutonomousMode(agent: any, config: any, interval = 10) {
|
||||
"Be creative and do something interesting on the blockchain. " +
|
||||
"Choose an action or set of actions and execute it that highlights your abilities.";
|
||||
|
||||
const stream = await agent.stream({ messages: [new HumanMessage(thought)] }, config);
|
||||
const stream = await agent.stream(
|
||||
{ messages: [new HumanMessage(thought)] },
|
||||
config,
|
||||
);
|
||||
|
||||
for await (const chunk of stream) {
|
||||
if ("agent" in chunk) {
|
||||
@@ -107,7 +109,7 @@ async function runAutonomousMode(agent: any, config: any, interval = 10) {
|
||||
console.log("-------------------");
|
||||
}
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, interval * 1000));
|
||||
await new Promise((resolve) => setTimeout(resolve, interval * 1000));
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
console.error("Error:", error.message);
|
||||
@@ -126,7 +128,7 @@ async function runChatMode(agent: any, config: any) {
|
||||
});
|
||||
|
||||
const question = (prompt: string): Promise<string> =>
|
||||
new Promise(resolve => rl.question(prompt, resolve));
|
||||
new Promise((resolve) => rl.question(prompt, resolve));
|
||||
|
||||
try {
|
||||
while (true) {
|
||||
@@ -136,7 +138,10 @@ async function runChatMode(agent: any, config: any) {
|
||||
break;
|
||||
}
|
||||
|
||||
const stream = await agent.stream({ messages: [new HumanMessage(userInput)] }, config);
|
||||
const stream = await agent.stream(
|
||||
{ messages: [new HumanMessage(userInput)] },
|
||||
config,
|
||||
);
|
||||
|
||||
for await (const chunk of stream) {
|
||||
if ("agent" in chunk) {
|
||||
@@ -164,7 +169,7 @@ async function chooseMode(): Promise<"chat" | "auto"> {
|
||||
});
|
||||
|
||||
const question = (prompt: string): Promise<string> =>
|
||||
new Promise(resolve => rl.question(prompt, resolve));
|
||||
new Promise((resolve) => rl.question(prompt, resolve));
|
||||
|
||||
while (true) {
|
||||
console.log("\nAvailable modes:");
|
||||
@@ -206,7 +211,7 @@ async function main() {
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main().catch(error => {
|
||||
main().catch((error) => {
|
||||
console.error("Fatal error:", error);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user