diff --git a/.env.example b/.env.example index cbf1d0950e9..3eaf7b8bb6b 100644 --- a/.env.example +++ b/.env.example @@ -494,6 +494,9 @@ NEAR_NETWORK=testnet # or mainnet ZKSYNC_ADDRESS= ZKSYNC_PRIVATE_KEY= +# HoldStation Wallet Configuration +HOLDSTATION_PRIVATE_KEY= + # Avail DA Configuration AVAIL_ADDRESS= AVAIL_SEED= diff --git a/agent/package.json b/agent/package.json index dc6d2445511..49627608876 100644 --- a/agent/package.json +++ b/agent/package.json @@ -108,6 +108,7 @@ "@elizaos/plugin-pyth-data": "workspace:*", "@elizaos/plugin-openai": "workspace:*", "@elizaos/plugin-devin": "workspace:*", + "@elizaos/plugin-holdstation": "workspace:*", "readline": "1.3.0", "ws": "8.18.0", "yargs": "17.7.2" diff --git a/agent/src/index.ts b/agent/src/index.ts index eeb4d2828a7..87485dba0a9 100644 --- a/agent/src/index.ts +++ b/agent/src/index.ts @@ -17,6 +17,7 @@ import { agentKitPlugin } from "@elizaos/plugin-agentkit"; import { PrimusAdapter } from "@elizaos/plugin-primus"; import { lightningPlugin } from "@elizaos/plugin-lightning"; import { elizaCodeinPlugin, onchainJson } from "@elizaos/plugin-iq6900"; +import { holdstationPlugin } from "@elizaos/plugin-holdstation"; import { AgentRuntime, @@ -1092,6 +1093,9 @@ export async function createAgent( getSecret(character, "DEVIN_API_TOKEN") ? devinPlugin : null, + getSecret(character, "HOLDSTATION_PRIVATE_KEY") + ? holdstationPlugin + : null, ].filter(Boolean), providers: [], actions: [], diff --git a/packages/plugin-holdstation/.npmignore b/packages/plugin-holdstation/.npmignore new file mode 100644 index 00000000000..078562eceab --- /dev/null +++ b/packages/plugin-holdstation/.npmignore @@ -0,0 +1,6 @@ +* + +!dist/** +!package.json +!readme.md +!tsup.config.ts \ No newline at end of file diff --git a/packages/plugin-holdstation/README.md b/packages/plugin-holdstation/README.md new file mode 100644 index 00000000000..1088e51b835 --- /dev/null +++ b/packages/plugin-holdstation/README.md @@ -0,0 +1,51 @@ +# @elizaos/plugin-holdstation + +Holdstation Wallet Plugin for Eliza + +## Features + +This plugin provides functionality (now on ZKsync Era, and Berachain coming soon) to: + +- Token swapping on hold.so (Holdstation swap) + +## Configuration + +The plugin requires the following environment variables: + +```env +HOLDSTATION_PRIVATE_KEY= # Required: Your wallet's private key +``` + +## Installation + +```bash +pnpm add @elizaos/plugin-holdstation +``` + +## Development + +```bash +pnpm install --no-frozen-lockfile +``` + +### Building + +```bash +pnpm build +``` + +### Testing + +```bash +pnpm test +``` + +## Credits + +Special thanks to: + +- The Eliza community for their contributions and feedback + +## License + +This plugin is part of the Eliza project. See the main project repository for license information. diff --git a/packages/plugin-holdstation/eslint.config.mjs b/packages/plugin-holdstation/eslint.config.mjs new file mode 100644 index 00000000000..92fe5bbebef --- /dev/null +++ b/packages/plugin-holdstation/eslint.config.mjs @@ -0,0 +1,3 @@ +import eslintGlobalConfig from "../../eslint.config.mjs"; + +export default [...eslintGlobalConfig]; diff --git a/packages/plugin-holdstation/package.json b/packages/plugin-holdstation/package.json new file mode 100644 index 00000000000..c6d7ea35f16 --- /dev/null +++ b/packages/plugin-holdstation/package.json @@ -0,0 +1,32 @@ +{ + "name": "@elizaos/plugin-holdstation", + "version": "0.1.1", + "type": "module", + "main": "dist/index.js", + "module": "dist/index.js", + "types": "dist/index.d.ts", + "exports": { + "./package.json": "./package.json", + ".": { + "import": { + "@elizaos/source": "./src/index.ts", + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + } + } + }, + "dependencies": { + "@elizaos/core": "workspace:*", + "node-cache": "5.1.2", + "viem": "2.22.2" + }, + "devDependencies": { + "tsup": "8.3.5", + "@types/node": "^20.0.0" + }, + "scripts": { + "build": "tsup --format esm --dts", + "dev": "tsup --format esm --dts --watch", + "lint": "eslint --fix --cache ." + } +} diff --git a/packages/plugin-holdstation/src/actions/swapAction.ts b/packages/plugin-holdstation/src/actions/swapAction.ts new file mode 100644 index 00000000000..e7b33c5cb8b --- /dev/null +++ b/packages/plugin-holdstation/src/actions/swapAction.ts @@ -0,0 +1,237 @@ +import { + Action, + IAgentRuntime, + Memory, + HandlerCallback, + State, + composeContext, + ModelClass, + elizaLogger, + ActionExample, + generateObjectDeprecated, +} from "@elizaos/core"; + +import { swapTemplate } from "../templates"; +import { SendTransactionParams, SwapParams } from "../types"; +import { + initWalletProvider, + WalletProvider, +} from "../providers/walletProvider"; +import { validateHoldStationConfig } from "../environment"; +import { HOLDSTATION_ROUTER_ADDRESS, NATIVE_ADDRESS } from "../constants"; +import { parseUnits } from "viem"; + +export class SwapAction { + constructor(private walletProvider: WalletProvider) {} + + async swap(params: SwapParams): Promise { + const { items: tokens } = await this.walletProvider.fetchPortfolio(); + + if (!params.inputTokenCA && !params.inputTokenSymbol) { + throw new Error("Input token not provided"); + } + + const filters = tokens.filter( + (t) => + t.symbol === params.inputTokenSymbol || + t.address === params.inputTokenCA, + ); + if (filters.length != 1) { + throw new Error( + "Multiple tokens or no tokens found with the symbol", + ); + } + + // fill in token info + params.inputTokenCA = filters[0].address; + params.inputTokenSymbol = filters[0].symbol; + const decimals = filters[0].decimals ?? 18; + + // parse amount out + const tokenAmount = parseUnits(params.amount.toString(), decimals); + + if (!params.outputTokenCA && !params.outputTokenSymbol) { + throw new Error("Output token not provided"); + } + + if (!params.outputTokenCA || !params.outputTokenSymbol) { + const tokens = await this.walletProvider.fetchAllTokens(); + const filters = tokens.filter( + (t) => + t.symbol === params.outputTokenSymbol || + t.address === params.outputTokenCA, + ); + if (filters.length != 1) { + throw new Error( + "Multiple tokens or no tokens found with the symbol", + ); + } + params.outputTokenCA = filters[0].address; + params.outputTokenSymbol = filters[0].symbol; + } + + elizaLogger.info("--- Swap params:", params); + + // fetch swap tx data + const walletAddress = this.walletProvider.getAddress(); + const deadline = Math.floor(Date.now() / 1000) + 10 * 60; + const swapUrl = `https://swap.hold.so/api/swap?src=${params.inputTokenCA}&dst=${params.outputTokenCA}&amount=${tokenAmount}&receiver=${walletAddress}&deadline=${deadline}`; + elizaLogger.info("swapUrl:", swapUrl); + const swapResponse = await fetch(swapUrl); + const swapData = await swapResponse.json(); + if (!swapData || swapData.error) { + elizaLogger.error("Swap error:", swapData); + throw new Error( + `Failed to fetch swap: ${swapData?.error || "Unknown error"}`, + ); + } + + // generate nonce + const nonce = await this.walletProvider + .getPublicClient() + .getTransactionCount({ + address: walletAddress, + }); + + const populatedTx: SendTransactionParams = { + to: HOLDSTATION_ROUTER_ADDRESS, + data: swapData.tx.data, + nonce: nonce, + }; + + if ( + params.inputTokenCA.toLowerCase() !== NATIVE_ADDRESS.toLowerCase() + ) { + const allowance = await this.walletProvider.getAllowace( + params.inputTokenCA, + walletAddress, + HOLDSTATION_ROUTER_ADDRESS, + ); + if (allowance < tokenAmount) { + await this.walletProvider.approve( + HOLDSTATION_ROUTER_ADDRESS, + params.inputTokenCA, + tokenAmount, + ); + } + } else { + populatedTx.value = tokenAmount; + } + + const hash = await this.walletProvider.sendTransaction(populatedTx); + + return { + hash, + ...params, + }; + } +} + +export const swapAction: Action = { + name: "TOKEN_SWAP_BY_HOLDSTATION", + similes: [ + "SWAP_TOKEN", + "SWAP_TOKEN_BY_HOLDSTATION_SWAP", + "EXCHANGE_TOKENS", + "EXCHANGE_TOKENS_BY_HOLDSTATION_SWAP", + "CONVERT_TOKENS", + "CONVERT_TOKENS_BY_HOLDSTATION_SWAP", + ], + validate: async (runtime: IAgentRuntime, _message: Memory) => { + await validateHoldStationConfig(runtime); + return true; + }, + description: "Perform swapping of tokens on ZKsync by HoldStation swap.", + handler: async ( + runtime: IAgentRuntime, + message: Memory, + state: State, + _options: any, + callback: HandlerCallback, + ) => { + elizaLogger.log("Starting HoldStation Wallet TOKEN_SWAP handler..."); + + const walletProvider = await initWalletProvider(runtime); + const action = new SwapAction(walletProvider); + + // compose state + if (!state) { + state = (await runtime.composeState(message)) as State; + } else { + state = await runtime.updateRecentMessageState(state); + } + + // compose swap context + const swapContext = composeContext({ + state, + template: swapTemplate, + }); + + // generate swap content + const content = await generateObjectDeprecated({ + runtime, + context: swapContext, + modelClass: ModelClass.SMALL, + }); + + elizaLogger.info("generate swap content:", content); + + try { + const { + hash, + inputTokenCA, + inputTokenSymbol, + outputTokenCA, + outputTokenSymbol, + amount, + } = await action.swap(content); + + elizaLogger.success( + `Swap completed successfully from ${amount} ${inputTokenSymbol} (${inputTokenCA}) to ${outputTokenSymbol} (${outputTokenCA})!\nTransaction Hash: ${hash}`, + ); + + if (callback) { + callback({ + text: `Swap completed successfully from ${amount} ${inputTokenSymbol} (${inputTokenCA}) to ${outputTokenSymbol} (${outputTokenCA})!\nTransaction Hash: ${hash}`, + content: { + success: true, + hash: hash, + }, + }); + } + return true; + } catch (error) { + elizaLogger.error("Error during token swap:", error); + if (callback) { + callback({ + text: `Error during token swap: ${error.message}`, + content: { error: error.message }, + }); + } + return false; + } + }, + examples: [ + [ + { + user: "{{user1}}", + content: { + text: "Swap 100 USDC for HOLD", + }, + }, + { + user: "{{agent}}", + content: { + text: "Sure, I'll do swap 100 USDC for HOLD now.", + action: "TOKEN_SWAP", + }, + }, + { + user: "{{agent}}", + content: { + text: "Swap completed 100 USDC for HOLD successfully! Transaction: ...", + }, + }, + ], + ] as ActionExample[][], +}; diff --git a/packages/plugin-holdstation/src/constants/index.ts b/packages/plugin-holdstation/src/constants/index.ts new file mode 100644 index 00000000000..18b1cb12337 --- /dev/null +++ b/packages/plugin-holdstation/src/constants/index.ts @@ -0,0 +1,3 @@ +export const HOLDSTATION_ROUTER_ADDRESS = + "0xD1f1bA4BF2aDe4F47472D0B73ba0f5DC30E225DF"; +export const NATIVE_ADDRESS = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"; diff --git a/packages/plugin-holdstation/src/environment.ts b/packages/plugin-holdstation/src/environment.ts new file mode 100644 index 00000000000..d3e5d925382 --- /dev/null +++ b/packages/plugin-holdstation/src/environment.ts @@ -0,0 +1,31 @@ +import { IAgentRuntime } from "@elizaos/core"; +import { z } from "zod"; + +export const holdStationEnvSchema = z.object({ + HOLDSTATION_PRIVATE_KEY: z + .string() + .min(1, "holdstation plugin requires private key"), +}); + +export type holdStationConfig = z.infer; + +export async function validateHoldStationConfig( + runtime: IAgentRuntime, +): Promise { + try { + const config = { + HOLDSTATION_PRIVATE_KEY: + runtime.getSetting("HOLDSTATION_PRIVATE_KEY") || + process.env.HOLDSTATION_PRIVATE_KEY, + }; + return holdStationEnvSchema.parse(config); + } catch (error) { + if (error instanceof z.ZodError) { + const errorMessages = error.errors + .map((err) => `${err.path.join(".")}: ${err.message}`) + .join("\n"); + throw new Error(errorMessages); + } + throw error; + } +} diff --git a/packages/plugin-holdstation/src/hooks/index.ts b/packages/plugin-holdstation/src/hooks/index.ts new file mode 100644 index 00000000000..b77aa9b1c6c --- /dev/null +++ b/packages/plugin-holdstation/src/hooks/index.ts @@ -0,0 +1,2 @@ +export * from "./useGetAccount"; +export * from "./useGetWalletClient"; diff --git a/packages/plugin-holdstation/src/hooks/useGetAccount.ts b/packages/plugin-holdstation/src/hooks/useGetAccount.ts new file mode 100644 index 00000000000..d00ec44be9d --- /dev/null +++ b/packages/plugin-holdstation/src/hooks/useGetAccount.ts @@ -0,0 +1,8 @@ +import { IAgentRuntime } from "@elizaos/core"; +import type { PrivateKeyAccount } from "viem/accounts"; +import { privateKeyToAccount } from "viem/accounts"; + +export const useGetAccount = (runtime: IAgentRuntime): PrivateKeyAccount => { + const PRIVATE_KEY = runtime.getSetting("HOLDSTATION_PRIVATE_KEY")!; + return privateKeyToAccount(`0x${PRIVATE_KEY}`); +}; diff --git a/packages/plugin-holdstation/src/hooks/useGetWalletClient.ts b/packages/plugin-holdstation/src/hooks/useGetWalletClient.ts new file mode 100644 index 00000000000..9d0f083ff83 --- /dev/null +++ b/packages/plugin-holdstation/src/hooks/useGetWalletClient.ts @@ -0,0 +1,12 @@ +import { createWalletClient, http } from "viem"; +import { zksync } from "viem/chains"; +import { eip712WalletActions } from "viem/zksync"; + +export const useGetWalletClient = (): ReturnType => { + const client = createWalletClient({ + chain: zksync, + transport: http(), + }).extend(eip712WalletActions()); + + return client; +}; diff --git a/packages/plugin-holdstation/src/index.ts b/packages/plugin-holdstation/src/index.ts new file mode 100644 index 00000000000..9c987c5d7dd --- /dev/null +++ b/packages/plugin-holdstation/src/index.ts @@ -0,0 +1,14 @@ +import { Plugin } from "@elizaos/core"; +import { holdstationWalletProvider } from "./providers/walletProvider"; +import { swapAction } from "./actions/swapAction"; + +export const holdstationPlugin: Plugin = { + name: "holdstation", + description: "HoldStationWallet Plugin for Eliza", + providers: [holdstationWalletProvider], + evaluators: [], + services: [], + actions: [swapAction], +}; + +export default holdstationPlugin; diff --git a/packages/plugin-holdstation/src/providers/walletProvider.ts b/packages/plugin-holdstation/src/providers/walletProvider.ts new file mode 100644 index 00000000000..5353fd4bcfc --- /dev/null +++ b/packages/plugin-holdstation/src/providers/walletProvider.ts @@ -0,0 +1,198 @@ +import { + Provider, + IAgentRuntime, + Memory, + State, + elizaLogger, +} from "@elizaos/core"; + +import { + Address, + createPublicClient, + erc20Abi, + PublicClient, + http, + WalletClient, + HttpTransport, + Account, + Chain, + SendTransactionParameters, +} from "viem"; +import { zksync } from "viem/chains"; +import { PrivateKeyAccount } from "viem/accounts"; + +import { useGetAccount, useGetWalletClient } from "../hooks"; +import { Item, SendTransactionParams, WalletPortfolio } from "../types"; + +import NodeCache from "node-cache"; + +export class WalletProvider { + private cache: NodeCache; + account: PrivateKeyAccount; + walletClient: WalletClient; + publicClient: PublicClient; + + constructor(account: PrivateKeyAccount) { + this.account = account; + this.walletClient = useGetWalletClient(); + this.publicClient = createPublicClient({ + chain: zksync, + transport: http(), + }) as PublicClient; + this.cache = new NodeCache({ stdTTL: 300 }); + } + + getAddress() { + return this.account.address; + } + + getPublicClient() { + return this.publicClient; + } + + async getAllowace( + tokenAddress: Address, + owner: Address, + spender: Address, + ): Promise { + return this.publicClient.readContract({ + address: tokenAddress, + abi: erc20Abi, + functionName: "allowance", + args: [owner, spender], + }); + } + + async approve( + spenderAddress: Address, + tokenAddress: Address, + amount: bigint, + ) { + const result = await this.walletClient.writeContract({ + account: this.account, + address: tokenAddress, + abi: erc20Abi, + chain: zksync, + functionName: "approve", + args: [spenderAddress, amount], + }); + } + + async sendTransaction(req: SendTransactionParams): Promise { + const txRequest: SendTransactionParameters = { + ...req, + account: this.account, + chain: zksync, + kzg: undefined, + }; + const tx = await this.walletClient.sendTransaction(txRequest); + console.log("sendTransaction txhash:", tx); + return tx; + } + + async fetchPortfolio(): Promise { + try { + const cacheKey = `portfolio-${this.getAddress()}`; + const cachedValue = this.cache.get(cacheKey); + if (cachedValue) { + elizaLogger.info("Cache hit for fetchPortfolio"); + return cachedValue; + } + elizaLogger.info("Cache miss for fetchPortfolio"); + + const fetchUrl = `https://api.holdstation.com/api/user-balance/chain/324/wallet/${this.getAddress()}`; + + const portfolioResp = await fetch(fetchUrl); + const portfolioData = await portfolioResp.json(); + if (!portfolioData || !portfolioData.success) { + elizaLogger.error("Failed to fetch portfolio:", portfolioData); + throw new Error( + `Failed to fetch portfolio: ${ + portfolioData?.error || "Unknown error" + }`, + ); + } + + const items: Array = + portfolioData.data.map( + (item: any): Item => ({ + name: item.contract_name, + address: item.contract_address, + symbol: item.contract_ticker_symbol, + decimals: item.contract_decimals, + }), + ) || []; + const portfolio: WalletPortfolio = { items }; + + this.cache.set(cacheKey, portfolio); + return portfolio; + } catch (error) { + elizaLogger.error("Error fetching portfolio:", error); + throw error; + } + } + + async fetchAllTokens(): Promise> { + try { + const cacheKey = `all-hswallet-tokens`; + const cachedValue = this.cache.get>(cacheKey); + if (cachedValue) { + elizaLogger.log("Cache hit for fetch all"); + return cachedValue; + } + elizaLogger.log("Cache miss for fetch all"); + + const fetchUrl = `https://tokens.coingecko.com/zksync/all.json`; + + const tokensResp = await fetch(fetchUrl); + const tokensData = await tokensResp.json(); + if (!tokensData || tokensData.error || !tokensData.data) { + elizaLogger.error("Failed to fetch all tokens:", tokensData); + throw new Error( + `Failed to fetch all tokens: ${ + tokensData?.error || "Unknown error" + }`, + ); + } + + const tokens: Array = + tokensData.tokens.map( + (item: any): Item => ({ + name: item.name, + address: item.address, + symbol: item.symbol, + decimals: item.decimals, + }), + ) || []; + + this.cache.set(cacheKey, tokens); + return tokens; + } catch (error) { + elizaLogger.error("Error fetching all tokens:", error); + throw error; + } + } +} + +export const initWalletProvider = async (runtime: IAgentRuntime) => { + const account = useGetAccount(runtime); + + return new WalletProvider(account); +}; + +export const holdstationWalletProvider: Provider = { + get: async ( + runtime: IAgentRuntime, + message: Memory, + state: State, + ): Promise => { + try { + const walletProvider = await initWalletProvider(runtime); + const agentName = state.agentName || "The agent"; + return `${agentName}'s HoldStation Wallet address: ${walletProvider.getAddress()}`; + } catch (error) { + console.error("Error in HoldStation Wallet provider:", error); + return null; + } + }, +}; diff --git a/packages/plugin-holdstation/src/templates/index.ts b/packages/plugin-holdstation/src/templates/index.ts new file mode 100644 index 00000000000..788420f151b --- /dev/null +++ b/packages/plugin-holdstation/src/templates/index.ts @@ -0,0 +1 @@ +export * from "./swapTemplate"; diff --git a/packages/plugin-holdstation/src/templates/swapTemplate.ts b/packages/plugin-holdstation/src/templates/swapTemplate.ts new file mode 100644 index 00000000000..00ef87e8ca6 --- /dev/null +++ b/packages/plugin-holdstation/src/templates/swapTemplate.ts @@ -0,0 +1,70 @@ +export const swapTemplate = `Respond with a JSON markdown block containing only the extracted values. Use null for any values that cannot be determined: + +Here are several frequently used addresses. Use these for the corresponding tokens: +- ZK/zk: 0x5A7d6b2F92C77FAD6CCaBd7EE0624E64907Eaf3E +- ETH/eth: 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee +- USDC/usdc: 0x1d17CBcF0D6D143135aE902365D2E5e2A16538D4 +- HOLD/hold: 0xed4040fD47629e7c8FBB7DA76bb50B3e7695F0f2 + +Example response: +\`\`\`json +{ + "inputTokenSymbol": "USDC | null", + "outputTokenSymbol": "HOLD | null", + "inputTokenCA": "0x1d17CBcF0D6D143135aE902365D2E5e2A16538D4 | null", + "outputTokenCA": "0xed4040fD47629e7c8FBB7DA76bb50B3e7695F0f2 | null", + "amount": "100", + "slippage": "0.005" +} +\`\`\` + +{{recentMessages}} + +Given the recent messages and wallet information below: + +{{account}} + +Extract the following information about the requested token swap: +- Input token symbol (the token being sold) +- Output token symbol (the token being bought) +- Input token contract address +- Output token contract address +- Amount to swap +- Slippage tolerance (optional, default 0.005 if not specified) + +**Validation Details**: +1. **Amount**: + - Verify the amount is a valid numeric string. + +2. **Input and Output Tokens**: + - Verify that atleast one of the symbol or contract address is provided for both input and output tokens. + +3. **Slippage**: + - If the user does not specify, use the default value of 0.5%. + +**Example Scenarios**: +1. User says, "Swap 1 HOLD for ETH": + - Input token symbol: HOLD + - Output token symbol: ETH + - Input token contract address: null + - Output token contract address: null + - Amount to swap: 1 + - Slippage: null (default will apply) + +2. User says, "Swap 4 USDC to HOLD (0xed4040fD47629e7c8FBB7DA76bb50B3e7695F0f2) with 1% slippage": + - Input token symbol: USDC + - Output token symbol: HOLD + - Input token contract address: null + - Output token contract address: 0xed4040fD47629e7c8FBB7DA76bb50B3e7695F0f2 + - Amount to swap: 4 + - Slippage: 0.01 + +3. User says, "Swap 1 token CA 0xed4040fD47629e7c8FBB7DA76bb50B3e7695F0f2 to USDC with 0.5% slippage": + - Input token symbol: null + - Output token symbol: USDC + - Input token contract address: 0xed4040fD47629e7c8FBB7DA76bb50B3e7695F0f2 + - Output token contract address: null + - Amount to swap: 1 + - Slippage: 0.005 + +Now, process the user's request and provide the JSON response.`; diff --git a/packages/plugin-holdstation/src/types/index.ts b/packages/plugin-holdstation/src/types/index.ts new file mode 100644 index 00000000000..8c9495f4bdc --- /dev/null +++ b/packages/plugin-holdstation/src/types/index.ts @@ -0,0 +1,29 @@ +import { Content } from "@elizaos/core"; +import { Address } from "viem"; + +export interface SwapParams extends Content { + inputTokenCA?: Address; + inputTokenSymbol?: string; + outputTokenCA?: Address; + outputTokenSymbol?: string; + amount: bigint; + slippage?: number; +} + +export interface SendTransactionParams { + to: Address; + data: string; + value?: bigint; + nonce: number; +} + +export interface Item { + name: string; + address: Address; + symbol: string; + decimals: number; +} + +export interface WalletPortfolio { + items: Array; +} diff --git a/packages/plugin-holdstation/tsconfig.json b/packages/plugin-holdstation/tsconfig.json new file mode 100644 index 00000000000..834c4dce269 --- /dev/null +++ b/packages/plugin-holdstation/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../core/tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "types": [ + "node" + ] + }, + "include": [ + "src/**/*.ts" + ] +} \ No newline at end of file diff --git a/packages/plugin-holdstation/tsup.config.ts b/packages/plugin-holdstation/tsup.config.ts new file mode 100644 index 00000000000..1a96f24afa1 --- /dev/null +++ b/packages/plugin-holdstation/tsup.config.ts @@ -0,0 +1,21 @@ +import { defineConfig } from "tsup"; + +export default defineConfig({ + entry: ["src/index.ts"], + outDir: "dist", + sourcemap: true, + clean: true, + format: ["esm"], // Ensure you're targeting CommonJS + external: [ + "dotenv", // Externalize dotenv to prevent bundling + "fs", // Externalize fs to use Node.js built-in module + "path", // Externalize other built-ins if necessary + "@reflink/reflink", + "@node-llama-cpp", + "https", + "http", + "agentkeepalive", + "safe-buffer", + // Add other modules you want to externalize + ], +});