UNPKG

seiai

Version:

The Future Of AI On Sei

546 lines (498 loc) 17.1 kB
import axios from 'axios'; import { DirectSecp256k1HdWallet } from '@cosmjs/proto-signing'; import { SigningStargateClient, StargateClient } from '@cosmjs/stargate'; import { ChatOpenAI } from '@langchain/openai'; import { ChatAnthropic } from '@langchain/anthropic'; import { GoogleGenerativeAI } from '@google/generative-ai'; import { ChatGroq } from '@langchain/groq'; import { ConversationChain } from 'langchain/chains'; import { BufferMemory } from 'langchain/memory'; import { ChatPromptTemplate, MessagesPlaceholder } from '@langchain/core/prompts'; class SeiWallet { async importWallet(mnemonicPhrase) { try { const wallet = await DirectSecp256k1HdWallet.fromMnemonic(mnemonicPhrase, { prefix: 'sei' }); const [account] = await wallet.getAccounts(); return { address: account.address, publicKey: account.pubkey, wallet }; } catch (e) { throw new Error(`Invalid mnemonic: ${e.message}`); } } async _importWalletInstance(mnemonicPhrase) { try { const wallet = await DirectSecp256k1HdWallet.fromMnemonic(mnemonicPhrase, { prefix: 'sei' }); return wallet; } catch (e) { throw new Error(`Invalid mnemonic: ${e.message}`); } } } class SeiTransaction { constructor(rpcNodes, chainId, wallet) { this.rpcNodes = rpcNodes; this.chainId = chainId; this.wallet = wallet; this.currentRpcIndex = 0; } async buildAndSignTx(toAddress, amount, denom = 'usei') { try { const client = await SigningStargateClient.connectWithSigner( this.rpcNodes[this.currentRpcIndex], this.wallet ); const [account] = await this.wallet.getAccounts(); return await client.sendTokens(account.address, toAddress, [{ denom, amount: amount.toString() }], 'auto'); } catch (e) { throw new Error(`Transaction failed: ${e.message}`); } } async checkTxStatus(txHash) { try { const client = await StargateClient.connect(this.rpcNodes[this.currentRpcIndex]); const result = await client.getTx(txHash); return result; } catch (error) { throw new Error(`Failed to check transaction status: ${error.message}`); } } // Added method for DEX transaction building (assuming a simplified message structure) async buildDexTransaction(message) { const client = await SigningStargateClient.connectWithSigner( this.rpcNodes[this.currentRpcIndex], this.wallet ); const [account] = await this.wallet.getAccounts(); const tx = await client.signAndBroadcast(account.address, [message], 'auto'); return tx; } } class DeFiData { async getTokenPrice(tokenAddress, source = 'dexscreener') { try { if (source === 'dexscreener') { const { data } = await axios.get(`https://api.dexscreener.com/latest/dex/tokens/${tokenAddress}`); return data.pairs?.[0]?.priceUsd || 0; } return 0; } catch (e) { return 0; } } } class AIEngine { constructor(config) { this.model = config.model; this.apiKey = config.apiKey; this.systemPrompt = config.systemPrompt; this.maxTokens = config.maxTokens || 300; this.temperature = config.temperature || 0.7; this.feature_type = config.feature_type; this.memory = new BufferMemory(); this.initLLM(); } initLLM() { try { switch (this.model) { case 'openai': this.llm = new ChatOpenAI({ modelName: 'gpt-4-turbo-preview', // Latest GPT-4 model apiKey: this.apiKey, maxTokens: this.maxTokens, temperature: this.temperature }); break; case 'anthropic': this.llm = new ChatAnthropic({ modelName: 'claude-3-opus-20240229', // Latest Claude model apiKey: this.apiKey, maxTokens: this.maxTokens, temperature: this.temperature }); break; case 'gemini': const genAI = new GoogleGenerativeAI(this.apiKey); this.llm = genAI.getGenerativeModel({ model: "gemini-pro", generationConfig: { maxOutputTokens: this.maxTokens, temperature: this.temperature } }); break; case 'groq': this.llm = new ChatGroq({ modelName: 'mixtral-8x7b-32768', // Latest Mixtral model apiKey: this.apiKey, maxTokens: this.maxTokens, temperature: this.temperature }); break; default: throw new Error('Unsupported model'); } const prompt = ChatPromptTemplate.fromMessages([ ['system', this.systemPrompt || `You are a helpful AI assistant specializing in ${this.feature_type || 'general tasks'}`], MessagesPlaceholder('history'), ['human', '{input}'] ]); this.chain = new ConversationChain({ llm: this.llm, memory: this.memory, prompt }); } catch (error) { console.error('Failed to initialize LLM:', error); throw error; } } async analyze(input, defiData = null) { try { const message = defiData ? `${input} (Current SEI price: $${defiData} USD)` : input; const response = await this.chain.call({ input: message }); return response.response; } catch (error) { console.error('AI chat error:', error); return 'Sorry, I encountered an error processing your request.'; } } } class CustomChatbot { constructor(config) { this.engine = new AIEngine({ model: config.model, apiKey: config.apiKey, systemPrompt: config.systemPrompt, maxTokens: config.maxTokens, temperature: config.temperature }); this.intents = config.intents || {}; this.defiData = config.defiData; } async processMessage(message) { try { const price = await this.defiData?.getTokenPrice('SEI'); for (const [intent, handler] of Object.entries(this.intents)) { if (message.toLowerCase().includes(intent.toLowerCase())) { const response = await handler(message, price); if (response) return response; } } return this.engine.analyze(message, price); } catch (error) { console.error('Message processing error:', error); return 'Sorry, I could not process your message.'; } } } class SeiAISDK { constructor(config) { if (!config?.rpcNodes?.length) { throw new Error("Please provide at least one RPC node in the configuration"); } if (!config?.ai?.model || !config?.ai?.apiKey) { throw new Error("AI configuration (model and apiKey) must be provided"); } this.config = config; this.aiConfig = { model: config.ai.model, apiKey: config.ai.apiKey, maxTokens: config.ai.maxTokens || 300, temperature: config.ai.temperature || 0.7 }; this.wallet = new SeiWallet(); this.defiData = new DeFiData(); this.rpcNodes = config.rpcNodes; this.chainId = config.chainId || 'atlantic-2'; this.aiAgents = { market: new AIEngine(this.aiConfig), trading: new AIEngine({ ...this.aiConfig, feature_type: 'trading_signals' }), chat: new AIEngine({ ...this.aiConfig, feature_type: 'chatbot' }) }; this.tx_handler = null; // Initialize transaction handler } async importWallet(mnemonic) { const result = await this.wallet.importWallet(mnemonic); this.walletInstance = await this.wallet._importWalletInstance(mnemonic); this.tx_handler = new SeiTransaction(this.rpcNodes, this.chainId, this.walletInstance); // Assign tx handler after wallet import return result; } async getTokenPrice(token, source = 'dexscreener') { return await this.defiData.getTokenPrice(token, source); } async analyzeMarket(data) { return await this.aiAgents.market.analyze(data); } async generateTradingSignals(data) { return await this.aiAgents.trading.analyze(data); } async chat(message) { const price = await this.getTokenPrice('SEI'); return await this.aiAgents.chat.analyze(message, price); } createCustomChatbot(config = {}) { return new CustomChatbot({ model: config.model || this.aiConfig.model, apiKey: config.apiKey || this.aiConfig.apiKey, intents: config.intents, systemPrompt: config.systemPrompt, maxTokens: config.maxTokens || this.aiConfig.maxTokens, temperature: config.temperature || this.aiConfig.temperature, defiData: this.defiData }); } async sendTokens(toAddress, amount, denom = 'usei') { if (!this.tx_handler) { throw new Error('Wallet not imported'); } return await this.tx_handler.buildAndSignTx(toAddress, amount, denom); } async checkTxStatus(txHash) { if (!this.tx_handler) { throw new Error('Wallet not imported'); } return await this.tx_handler.checkTxStatus(txHash); } // Added DEX swap function async swapTokensDex(tokenFrom, tokenTo, amount, slippage = 0.5) { if (!this.tx_handler) { throw new Error("Wallet not imported"); } try { const swapMsg = { typeUrl: "/cosmwasm.wasm.v1.MsgExecuteContract", // Example type URL - adjust as needed for your DEX value: { sender: this.walletInstance.getAccounts()[0].address, contract: "YOUR_DEX_CONTRACT_ADDRESS", // Replace with your DEX contract address msg: Buffer.from(JSON.stringify({ swap_exact_tokens_for_tokens: { amount_in: String(Math.floor(amount * 1e6)), min_amount_out: String(Math.floor(amount * (1 - slippage / 100) * 1e6)), path: [tokenFrom, tokenTo], recipient: this.walletInstance.getAccounts()[0].address } })).toString('base64'), funds: [] // Add funds if needed } }; return await this.tx_handler.buildDexTransaction(swapMsg); } catch (error) { console.error("DEX swap failed:", error); throw error; } } // Added add liquidity function async addLiquidity(tokenA, tokenB, amountA, amountB) { if (!this.tx_handler) { throw new Error("Wallet not imported"); } try { const addLiquidityMsg = { typeUrl: "/cosmwasm.wasm.v1.MsgExecuteContract", // Example type URL - adjust as needed for your DEX value: { sender: this.walletInstance.getAccounts()[0].address, contract: "YOUR_DEX_CONTRACT_ADDRESS", // Replace with your DEX contract address msg: Buffer.from(JSON.stringify({ add_liquidity: { token_a: tokenA, token_b: tokenB, amount_a_desired: String(Math.floor(amountA * 1e6)), amount_b_desired: String(Math.floor(amountB * 1e6)), min_shares: "1" } })).toString('base64'), funds: [] // Add funds if necessary. } }; return await this.tx_handler.buildDexTransaction(addLiquidityMsg); } catch (error) { console.error("Adding liquidity failed:", error); throw error; } } async stake_tokens(validator_address, amount, denom = "usei") { if (!this.tx_handler) { throw new Error("Wallet not imported"); } const stakeMsg = { typeUrl: "/cosmos.staking.v1beta1.MsgDelegate", value: { delegatorAddress: this.walletInstance.getAccounts()[0].address, validatorAddress: validator_address, amount: { denom, amount: String(Math.floor(amount * 1e6)) } } }; return await this.tx_handler.buildDexTransaction(stakeMsg); } async unstake_tokens(validator_address, amount, denom = "usei") { if (!this.tx_handler) { throw new Error("Wallet not imported"); } const unstakeMsg = { typeUrl: "/cosmos.staking.v1beta1.MsgUndelegate", value: { delegatorAddress: this.walletInstance.getAccounts()[0].address, validatorAddress: validator_address, amount: { denom, amount: String(Math.floor(amount * 1e6)) } } }; return await this.tx_handler.buildDexTransaction(unstakeMsg); } async vote_governance(proposal_id, vote) { if (!this.tx_handler) { throw new Error("Wallet not imported"); } const voteMsg = { typeUrl: "/cosmos.gov.v1beta1.MsgVote", value: { proposalId: proposal_id, voter: this.walletInstance.getAccounts()[0].address, option: vote } }; return await this.tx_handler.buildDexTransaction(voteMsg); } async create_limit_order(pair, side, price, quantity) { if (!this.tx_handler) { throw new Error("Wallet not imported"); } const orderMsg = { typeUrl: "/sei.dex.MsgPlaceLimitOrder", value: { creator: this.walletInstance.getAccounts()[0].address, pair, side, // "BUY" or "SELL" price: String(price), quantity: String(quantity), orderType: "LIMIT" } }; return await this.tx_handler.buildDexTransaction(orderMsg); } async cancel_order(orderId) { if (!this.tx_handler) { throw new Error("Wallet not imported"); } const cancelMsg = { typeUrl: "/sei.dex.MsgCancelOrder", value: { creator: this.walletInstance.getAccounts()[0].address, orderId } }; return await this.tx_handler.buildDexTransaction(cancelMsg); } async get_order_history() { try { const [account] = await this.walletInstance.getAccounts(); const response = await axios.get(`${this.rpcNodes[0]}/sei/orders/${account.address}`); return response.data; } catch (error) { throw new Error(`Failed to fetch order history: ${error.message}`); } } async get_validator_list() { try { const response = await axios.get(`${this.rpcNodes[0]}/cosmos/staking/v1beta1/validators`); return response.data.validators; } catch (error) { throw new Error(`Failed to fetch validators: ${error.message}`); } } async get_governance_proposals() { try { const response = await axios.get(`${this.rpcNodes[0]}/cosmos/gov/v1beta1/proposals`); return response.data.proposals; } catch (error) { throw new Error(`Failed to fetch proposals: ${error.message}`); } } async create_market_order(pair, side, quantity) { if (!this.tx_handler) { throw new Error("Wallet not imported"); } const orderMsg = { typeUrl: "/sei.dex.MsgPlaceMarketOrder", value: { creator: this.walletInstance.getAccounts()[0].address, pair, side, quantity: String(quantity), orderType: "MARKET" } }; return await this.tx_handler.buildDexTransaction(orderMsg); } async get_order_book(pair) { try { const response = await axios.get(`${this.rpcNodes[0]}/sei/orderbook/${pair}`); return response.data; } catch (error) { throw new Error(`Failed to fetch order book: ${error.message}`); } } async compound_rewards(validator_address) { if (!this.tx_handler) { throw new Error("Wallet not imported"); } const compoundMsg = { typeUrl: "/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward", value: { delegatorAddress: this.walletInstance.getAccounts()[0].address, validatorAddress: validator_address } }; return await this.tx_handler.buildDexTransaction(compoundMsg); } async get_market_depth(pair) { try { const response = await axios.get(`${this.rpcNodes[0]}/sei/market/depth/${pair}`); return response.data; } catch (error) { throw new Error(`Failed to fetch market depth: ${error.message}`); } } async get_price_history(pair, timeframe = "1h") { try { const response = await axios.get(`${this.rpcNodes[0]}/sei/price/history/${pair}/${timeframe}`); return response.data; } catch (error) { throw new Error(`Failed to fetch price history: ${error.message}`); } } async analyze_liquidity_pools() { try { const response = await axios.get(`${this.rpcNodes[0]}/sei/liquiditypools`); return response.data; } catch (error) { throw new Error(`Failed to analyze liquidity pools: ${error.message}`); } } async get_account_positions() { if (!this.tx_handler) { throw new Error("Wallet not imported"); } try { const [account] = await this.walletInstance.getAccounts(); const response = await axios.get(`${this.rpcNodes[0]}/sei/positions/${account.address}`); return response.data; } catch (error) { throw new Error(`Failed to fetch positions: ${error.message}`); } } async get_market_summary(pair) { try { const response = await axios.get(`${this.rpcNodes[0]}/sei/market/summary/${pair}`); return response.data; } catch (error) { throw new Error(`Failed to fetch market summary: ${error.message}`); } } } export default SeiAISDK;