From e9d343d8a7a42b855dedecd982f672d32cb19301 Mon Sep 17 00:00:00 2001 From: darwintree <17946284+darwintree@users.noreply.github.com> Date: Thu, 21 Nov 2024 10:19:01 +0800 Subject: [PATCH 1/4] feat: transfer on Conflux (conflux-plugin) --- .env.example | 6 + agent/package.json | 1 + agent/src/index.ts | 4 + packages/plugin-conflux/README.md | 25 +++ packages/plugin-conflux/package.json | 15 ++ .../plugin-conflux/src/actions/transfer.ts | 147 ++++++++++++++++++ packages/plugin-conflux/src/index.ts | 9 ++ .../plugin-conflux/src/templates/transfer.ts | 7 + packages/plugin-conflux/tsconfig.json | 8 + packages/plugin-conflux/tsup.config.ts | 13 ++ 10 files changed, 235 insertions(+) create mode 100644 packages/plugin-conflux/README.md create mode 100644 packages/plugin-conflux/package.json create mode 100644 packages/plugin-conflux/src/actions/transfer.ts create mode 100644 packages/plugin-conflux/src/index.ts create mode 100644 packages/plugin-conflux/src/templates/transfer.ts create mode 100644 packages/plugin-conflux/tsconfig.json create mode 100644 packages/plugin-conflux/tsup.config.ts diff --git a/.env.example b/.env.example index c3e3e820967..fc21e04a1c7 100644 --- a/.env.example +++ b/.env.example @@ -91,6 +91,12 @@ STARKNET_ADDRESS= STARKNET_PRIVATE_KEY= STARKNET_RPC_URL= +# Conflux Configuration +CONFLUX_CORE_PRIVATE_KEY= +CONFLUX_CORE_SPACE_RPC_URL= +CONFLUX_ESPACE_PRIVATE_KEY= +CONFLUX_ESPACE_RPC_URL= + # Coinbase COINBASE_COMMERCE_KEY= # from coinbase developer portal COINBASE_API_KEY= # from coinbase developer portal diff --git a/agent/package.json b/agent/package.json index 744d39b39f3..8404f5f8035 100644 --- a/agent/package.json +++ b/agent/package.json @@ -21,6 +21,7 @@ "@ai16z/client-twitter": "workspace:*", "@ai16z/eliza": "workspace:*", "@ai16z/plugin-bootstrap": "workspace:*", + "@ai16z/plugin-conflux": "workspace:*", "@ai16z/plugin-image-generation": "workspace:*", "@ai16z/plugin-node": "workspace:*", "@ai16z/plugin-solana": "workspace:*", diff --git a/agent/src/index.ts b/agent/src/index.ts index f76ae1d8889..fd18d45b82b 100644 --- a/agent/src/index.ts +++ b/agent/src/index.ts @@ -23,6 +23,7 @@ import { validateCharacterConfig, } from "@ai16z/eliza"; import { bootstrapPlugin } from "@ai16z/plugin-bootstrap"; +import { confluxPlugin } from "@ai16z/plugin-conflux"; import { solanaPlugin } from "@ai16z/plugin-solana"; import { nodePlugin } from "@ai16z/plugin-node"; import { @@ -252,6 +253,9 @@ export function createAgent( character, plugins: [ bootstrapPlugin, + character.settings.secrets?.CONFLUX_CORE_PRIVATE_KEY + ? confluxPlugin + : null, nodePlugin, character.settings.secrets?.WALLET_PUBLIC_KEY ? solanaPlugin : null, character.settings.secrets?.COINBASE_COMMERCE_KEY || diff --git a/packages/plugin-conflux/README.md b/packages/plugin-conflux/README.md new file mode 100644 index 00000000000..e84f2deda2d --- /dev/null +++ b/packages/plugin-conflux/README.md @@ -0,0 +1,25 @@ +# @ai16z/plugin-conflux + +This plugin provides actions and providers for interacting with the [Conflux network](https://www.confluxdocs.com/docs/general). + +## Actions + +### ConfiPump + +Buy and sell tokens on Conflux's implementation of pump.fun (ConfiPump). + +### Transfer + +Transfer tokens from one address to another within Conflux core space. + +### Bridge Transfer + +Transfer tokens from one address to Conflux eSpace. + +### Sponsor + +Provide gas for Conflux core space contracts so they can be called without the need to have Conflux in user's wallet. + +### Swap + +Swap tokens on Conflux DEXs. diff --git a/packages/plugin-conflux/package.json b/packages/plugin-conflux/package.json new file mode 100644 index 00000000000..59c3ed8f796 --- /dev/null +++ b/packages/plugin-conflux/package.json @@ -0,0 +1,15 @@ +{ + "name": "@ai16z/plugin-conflux", + "version": "0.0.1", + "main": "dist/index.js", + "type": "module", + "types": "dist/index.d.ts", + "dependencies": { + "cive": "^0.7.1", + "@ai16z/eliza": "workspace:*" + }, + "scripts": { + "build": "tsup --format esm --dts", + "dev": "tsup --watch" + } +} diff --git a/packages/plugin-conflux/src/actions/transfer.ts b/packages/plugin-conflux/src/actions/transfer.ts new file mode 100644 index 00000000000..fa5086b879c --- /dev/null +++ b/packages/plugin-conflux/src/actions/transfer.ts @@ -0,0 +1,147 @@ +import { + Action, + IAgentRuntime, + Memory, + State, + HandlerCallback, +} from "@ai16z/eliza"; +import { z } from "zod"; +import { generateObjectV2, composeContext, ModelClass, Content } from "@ai16z/eliza"; +import { createPublicClient, createWalletClient, http, parseCFX } from "cive"; +import { privateKeyToAccount } from "cive/accounts"; +import { testnet } from "cive/chains"; +import { confluxTransferTemplate } from "../templates/transfer"; + +const TransferSchema = z.object({ + to: z.string(), + amount: z.number(), // use number ignoring decimals issue +}); + +interface TransferContent extends Content { + to: string; + amount: number; +} + +const isTransferContent = (object: any): object is TransferContent => { + if (TransferSchema.safeParse(object).success) { + return true; + } + console.error("Invalid content: ", object); + return false; +}; + +const sendCFX = async ( + secretKey: `0x${string}`, + rpcUrl: string, + to: string, + amount: string +) => { + const client = createPublicClient({ + transport: http(rpcUrl), + }); + const networkId = await client.getChainId(); + const account = privateKeyToAccount(secretKey, { networkId }); + + const walletClient = createWalletClient({ + transport: http(rpcUrl), + chain: testnet, + }); + + const hash = await walletClient.sendTransaction({ + account, + to, + value: parseCFX(amount), + chain: testnet, + }); + + await client.waitForTransactionReceipt({ + hash, + }); + return hash; +}; + +export const transfer: Action = { + name: "SEND_CFX", + description: + "Transfer CFX from to another in Conflux Core Space", + similes: ["SEND_CONFLUX", "SEND_CFX_CORE_SPACE", "TRANSFER_CFX"], + examples: [ + [ + { + user: "{{user1}}", + content: { + text: "Send 1 CFX to 0x1234567890abcdef", + }, + }, + { + user: "{{user2}}", + content: { + text: "1 CFX sent to 0x1234567890abcdef: 0x1234567890abcdef", + content: { + to: "0x1234567890abcdef", + amount: "1", + }, + }, + }, + ], + ], + validate: async (runtime: IAgentRuntime, message: Memory) => { + // no extra validation needed + return true; + }, + handler: async ( + runtime: IAgentRuntime, + message: Memory, + state?: State, + options?: { [key: string]: unknown }, + callback?: HandlerCallback + ) => { + if (!state) { + state = (await runtime.composeState(message)) as State; + } else { + state = await runtime.updateRecentMessageState(state); + } + + const context = composeContext({ + state, + template: confluxTransferTemplate, + }); + + const content = await generateObjectV2({ + runtime, + context, + modelClass: ModelClass.SMALL, + schema: TransferSchema, + }); + + if (!isTransferContent(content.object)) { + throw new Error("Invalid content"); + } + + const secretKey = runtime.getSetting("CONFLUX_CORE_PRIVATE_KEY") as `0x${string}`; + const rpcUrl = runtime.getSetting("CONFLUX_CORE_SPACE_RPC_URL"); + + let success = false; + + try { + const hash = await sendCFX(secretKey, rpcUrl, content.object.to, content.object.amount.toString()); + success = true; + if (!callback) { + return success; + } + callback({ + text: `${content.object.amount} CFX sent to ${content.object.to}: ${hash}`, + content: content.object, + }); + } catch (error) { + console.error(`Error sending CFX: ${error}`); + if (!callback) { + return success; + } + callback({ + text: `Failed to send ${content.object.amount} CFX to ${content.object.to}: ${error}`, + }); + } + return success; + }, +}; diff --git a/packages/plugin-conflux/src/index.ts b/packages/plugin-conflux/src/index.ts new file mode 100644 index 00000000000..a010fe076cd --- /dev/null +++ b/packages/plugin-conflux/src/index.ts @@ -0,0 +1,9 @@ +import { Plugin } from "@ai16z/eliza"; +import { transfer } from "./actions/transfer"; + +export const confluxPlugin: Plugin = { + name: "conflux", + description: "Conflux Plugin for Eliza", + actions: [transfer], + providers: [], +}; diff --git a/packages/plugin-conflux/src/templates/transfer.ts b/packages/plugin-conflux/src/templates/transfer.ts new file mode 100644 index 00000000000..57fef7ad0d4 --- /dev/null +++ b/packages/plugin-conflux/src/templates/transfer.ts @@ -0,0 +1,7 @@ +export const confluxTransferTemplate = ` +Extract Conflux Core Space Transfer Parameters from the latest message: + +{{recentMessages}} + +The to address should be the Conflux Core Space address, starting with "cfx:" or "cfxtest:". +`; diff --git a/packages/plugin-conflux/tsconfig.json b/packages/plugin-conflux/tsconfig.json new file mode 100644 index 00000000000..eaa78145aa3 --- /dev/null +++ b/packages/plugin-conflux/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "./src" + }, + "include": ["src"] +} diff --git a/packages/plugin-conflux/tsup.config.ts b/packages/plugin-conflux/tsup.config.ts new file mode 100644 index 00000000000..f63d4d37fcf --- /dev/null +++ b/packages/plugin-conflux/tsup.config.ts @@ -0,0 +1,13 @@ +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: [ + "cive", + // Add other modules you want to externalize + ], +}); From d0494252b6979c2d187483e0988a94dc386135ce Mon Sep 17 00:00:00 2001 From: darwintree <17946284+darwintree@users.noreply.github.com> Date: Thu, 21 Nov 2024 11:20:17 +0800 Subject: [PATCH 2/4] feat(plugin-conflux): support bridge transfer --- .../src/abi/crossSpaceCall.json | 1 + .../src/actions/bridgeTransfer.ts | 141 ++++++++++++++++++ .../plugin-conflux/src/actions/confiPump.ts | 0 .../plugin-conflux/src/actions/sponsor.ts | 0 .../plugin-conflux/src/actions/transfer.ts | 34 +---- packages/plugin-conflux/src/index.ts | 3 +- .../src/templates/bridgeTransfer.ts | 7 + packages/plugin-conflux/src/types.ts | 20 +++ 8 files changed, 179 insertions(+), 27 deletions(-) create mode 100644 packages/plugin-conflux/src/abi/crossSpaceCall.json create mode 100644 packages/plugin-conflux/src/actions/bridgeTransfer.ts create mode 100644 packages/plugin-conflux/src/actions/confiPump.ts create mode 100644 packages/plugin-conflux/src/actions/sponsor.ts create mode 100644 packages/plugin-conflux/src/templates/bridgeTransfer.ts create mode 100644 packages/plugin-conflux/src/types.ts diff --git a/packages/plugin-conflux/src/abi/crossSpaceCall.json b/packages/plugin-conflux/src/abi/crossSpaceCall.json new file mode 100644 index 00000000000..441774637d0 --- /dev/null +++ b/packages/plugin-conflux/src/abi/crossSpaceCall.json @@ -0,0 +1 @@ +[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes20","name":"sender","type":"bytes20"},{"indexed":true,"internalType":"bytes20","name":"receiver","type":"bytes20"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"Call","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes20","name":"sender","type":"bytes20"},{"indexed":true,"internalType":"bytes20","name":"contract_address","type":"bytes20"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"init","type":"bytes"}],"name":"Create","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"success","type":"bool"}],"name":"Outcome","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes20","name":"sender","type":"bytes20"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[{"internalType":"bytes","name":"init","type":"bytes"}],"name":"createEVM","outputs":[{"internalType":"bytes20","name":"","type":"bytes20"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes20","name":"to","type":"bytes20"}],"name":"transferEVM","outputs":[{"internalType":"bytes","name":"output","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes20","name":"to","type":"bytes20"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"callEVM","outputs":[{"internalType":"bytes","name":"output","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes20","name":"to","type":"bytes20"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"staticCallEVM","outputs":[{"internalType":"bytes","name":"output","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deployEip1820","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"withdrawFromMapped","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"mappedBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"mappedNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/packages/plugin-conflux/src/actions/bridgeTransfer.ts b/packages/plugin-conflux/src/actions/bridgeTransfer.ts new file mode 100644 index 00000000000..8b8363f6de6 --- /dev/null +++ b/packages/plugin-conflux/src/actions/bridgeTransfer.ts @@ -0,0 +1,141 @@ +import { + Action, + IAgentRuntime, + Memory, + State, + HandlerCallback, +} from "@ai16z/eliza"; +import { generateObjectV2, composeContext, ModelClass, Content } from "@ai16z/eliza"; +import { createPublicClient, createWalletClient, http, parseCFX, encodeFunctionData } from "cive"; +import { hexAddressToBase32 } from "cive/utils"; +import { privateKeyToAccount } from "cive/accounts"; +import { testnet } from "cive/chains"; +import { confluxBridgeTransferTemplate } from "../templates/bridgeTransfer"; +import { TransferSchema, isTransferContent } from "../types"; +import crossSpaceCallAbi from "../abi/crossSpaceCall.json"; + +const bridgeSendCFX = async ( + secretKey: `0x${string}`, + rpcUrl: string, + espaceTo: `0x${string}`, + amount: string +) => { + const client = createPublicClient({ + transport: http(rpcUrl), + }); + const networkId = await client.getChainId(); + const account = privateKeyToAccount(secretKey, { networkId }); + + const walletClient = createWalletClient({ + transport: http(rpcUrl), + chain: testnet, + }); + + const toAddress = hexAddressToBase32({ + hexAddress: "0x0888000000000000000000000000000000000006", + networkId, + }); // crossSpaceCall Address + + const hash = await walletClient.sendTransaction({ + account, + to: toAddress, + value: parseCFX(amount), + chain: testnet, + data: encodeFunctionData({ + abi: crossSpaceCallAbi, + functionName: "transferEVM", + args: [espaceTo], + }), + }); + + // await client.waitForTransactionReceipt({ + // hash, + // }); + return hash; +}; + +export const bridgeTransfer: Action = { + name: "BRIDGE_SEND_CFX", + description: + "Bridge transfer CFX from Conflux Core Space to another in Conflux eSpace. The address is a 0x-prefix address", + similes: ["BRIDGE_SEND_CONFLUX", "CROSS_SPACE_SEND_CFX", "BRIDGE_TRANSFER_CFX", "CROSS_SPACE_TRANSFER_CFX"], + examples: [ + [ + { + user: "{{user1}}", + content: { + text: "Send 1 CFX to eSpace Address 0x119DA8bbe74B1C5c987D0c64D10eC1dB301d4752", + }, + }, + { + user: "{{user2}}", + content: { + text: "1 CFX sent to espace Address 0x119DA8bbe74B1C5c987D0c64D10eC1dB301d4752: 0x1234567890abcdef", + content: { + to: "0x119DA8bbe74B1C5c987D0c64D10eC1dB301d4752", + amount: "1", + }, + }, + }, + ], + ], + validate: async (runtime: IAgentRuntime, message: Memory) => { + // no extra validation needed + return true; + }, + handler: async ( + runtime: IAgentRuntime, + message: Memory, + state?: State, + options?: { [key: string]: unknown }, + callback?: HandlerCallback + ) => { + if (!state) { + state = (await runtime.composeState(message)) as State; + } else { + state = await runtime.updateRecentMessageState(state); + } + + const context = composeContext({ + state, + template: confluxBridgeTransferTemplate, + }); + + const content = await generateObjectV2({ + runtime, + context, + modelClass: ModelClass.SMALL, + schema: TransferSchema, + }); + + if (!isTransferContent(content.object)) { + throw new Error("Invalid content"); + } + + const secretKey = runtime.getSetting("CONFLUX_CORE_PRIVATE_KEY") as `0x${string}`; + const rpcUrl = runtime.getSetting("CONFLUX_CORE_SPACE_RPC_URL"); + + let success = false; + + try { + const hash = await bridgeSendCFX(secretKey, rpcUrl, content.object.to as `0x${string}`, content.object.amount.toString()); + success = true; + if (!callback) { + return success; + } + callback({ + text: `${content.object.amount} CFX sent to ${content.object.to}: ${hash}`, + content: content.object, + }); + } catch (error) { + console.error(`Error sending CFX: ${error}`); + if (!callback) { + return success; + } + callback({ + text: `Failed to send ${content.object.amount} CFX to ${content.object.to}: ${error}`, + }); + } + return success; + }, +}; diff --git a/packages/plugin-conflux/src/actions/confiPump.ts b/packages/plugin-conflux/src/actions/confiPump.ts new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/plugin-conflux/src/actions/sponsor.ts b/packages/plugin-conflux/src/actions/sponsor.ts new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/plugin-conflux/src/actions/transfer.ts b/packages/plugin-conflux/src/actions/transfer.ts index fa5086b879c..d24749492ae 100644 --- a/packages/plugin-conflux/src/actions/transfer.ts +++ b/packages/plugin-conflux/src/actions/transfer.ts @@ -5,30 +5,12 @@ import { State, HandlerCallback, } from "@ai16z/eliza"; -import { z } from "zod"; import { generateObjectV2, composeContext, ModelClass, Content } from "@ai16z/eliza"; import { createPublicClient, createWalletClient, http, parseCFX } from "cive"; import { privateKeyToAccount } from "cive/accounts"; import { testnet } from "cive/chains"; import { confluxTransferTemplate } from "../templates/transfer"; - -const TransferSchema = z.object({ - to: z.string(), - amount: z.number(), // use number ignoring decimals issue -}); - -interface TransferContent extends Content { - to: string; - amount: number; -} - -const isTransferContent = (object: any): object is TransferContent => { - if (TransferSchema.safeParse(object).success) { - return true; - } - console.error("Invalid content: ", object); - return false; -}; +import { TransferSchema, isTransferContent } from "../types"; const sendCFX = async ( secretKey: `0x${string}`, @@ -54,31 +36,31 @@ const sendCFX = async ( chain: testnet, }); - await client.waitForTransactionReceipt({ - hash, - }); + // await client.waitForTransactionReceipt({ + // hash, + // }); return hash; }; export const transfer: Action = { name: "SEND_CFX", description: - "Transfer CFX from to another in Conflux Core Space", + "Transfer CFX to another address in Conflux Core Space. The address starts with `cfx:` or `cfxtest:`", similes: ["SEND_CONFLUX", "SEND_CFX_CORE_SPACE", "TRANSFER_CFX"], examples: [ [ { user: "{{user1}}", content: { - text: "Send 1 CFX to 0x1234567890abcdef", + text: "Send 1 CFX to cfx:aaejuaaaaaaaaaaaaaaaaaaaaaaaaaaaa2eaeg85p5", }, }, { user: "{{user2}}", content: { - text: "1 CFX sent to 0x1234567890abcdef: 0x1234567890abcdef", + text: "1 CFX sent to cfx:aaejuaaaaaaaaaaaaaaaaaaaaaaaaaaaa2eaeg85p5: 0x1234567890abcdef", content: { - to: "0x1234567890abcdef", + to: "cfx:aaejuaaaaaaaaaaaaaaaaaaaaaaaaaaaa2eaeg85p5", amount: "1", }, }, diff --git a/packages/plugin-conflux/src/index.ts b/packages/plugin-conflux/src/index.ts index a010fe076cd..12acf8bce4e 100644 --- a/packages/plugin-conflux/src/index.ts +++ b/packages/plugin-conflux/src/index.ts @@ -1,9 +1,10 @@ import { Plugin } from "@ai16z/eliza"; import { transfer } from "./actions/transfer"; +import { bridgeTransfer } from "./actions/bridgeTransfer"; export const confluxPlugin: Plugin = { name: "conflux", description: "Conflux Plugin for Eliza", - actions: [transfer], + actions: [transfer, bridgeTransfer], providers: [], }; diff --git a/packages/plugin-conflux/src/templates/bridgeTransfer.ts b/packages/plugin-conflux/src/templates/bridgeTransfer.ts new file mode 100644 index 00000000000..ca5fdea32ba --- /dev/null +++ b/packages/plugin-conflux/src/templates/bridgeTransfer.ts @@ -0,0 +1,7 @@ +export const confluxBridgeTransferTemplate = ` +Extract Conflux Cross Space Transfer Parameters from the latest message: + +{{recentMessages}} + +The to address should be the Conflux eSpace address, starting with "0x". +`; diff --git a/packages/plugin-conflux/src/types.ts b/packages/plugin-conflux/src/types.ts new file mode 100644 index 00000000000..20fb8a57a24 --- /dev/null +++ b/packages/plugin-conflux/src/types.ts @@ -0,0 +1,20 @@ +import { z } from "zod"; +import { Content } from "@ai16z/eliza"; + +export const TransferSchema = z.object({ + to: z.string(), + amount: z.number(), // use number ignoring decimals issue +}); + +export interface TransferContent extends Content { + to: string; + amount: number; +} + +export const isTransferContent = (object: any): object is TransferContent => { + if (TransferSchema.safeParse(object).success) { + return true; + } + console.error("Invalid content: ", object); + return false; +}; \ No newline at end of file From 6bab91305cc65cd959d8c2063914579fb92425c5 Mon Sep 17 00:00:00 2001 From: darwintree <17946284+darwintree@users.noreply.github.com> Date: Thu, 21 Nov 2024 17:33:40 +0800 Subject: [PATCH 3/4] feat(plugin-conflux): support confiPump --- .env.example | 2 + packages/plugin-conflux/README.md | 4 +- .../src/abi/crossSpaceCall.json | 1 - .../plugin-conflux/src/abi/crossSpaceCall.ts | 184 ++ packages/plugin-conflux/src/abi/erc20.ts | 119 ++ packages/plugin-conflux/src/abi/meme.ts | 1671 +++++++++++++++++ .../src/actions/bridgeTransfer.ts | 4 +- .../plugin-conflux/src/actions/confiPump.ts | 331 ++++ .../plugin-conflux/src/actions/sponsor.ts | 0 packages/plugin-conflux/src/index.ts | 3 +- .../plugin-conflux/src/templates/confiPump.ts | 9 + packages/plugin-conflux/src/types.ts | 69 +- 12 files changed, 2389 insertions(+), 8 deletions(-) delete mode 100644 packages/plugin-conflux/src/abi/crossSpaceCall.json create mode 100644 packages/plugin-conflux/src/abi/crossSpaceCall.ts create mode 100644 packages/plugin-conflux/src/abi/erc20.ts create mode 100644 packages/plugin-conflux/src/abi/meme.ts delete mode 100644 packages/plugin-conflux/src/actions/sponsor.ts create mode 100644 packages/plugin-conflux/src/templates/confiPump.ts diff --git a/.env.example b/.env.example index fc21e04a1c7..4be3e5a8385 100644 --- a/.env.example +++ b/.env.example @@ -96,6 +96,7 @@ CONFLUX_CORE_PRIVATE_KEY= CONFLUX_CORE_SPACE_RPC_URL= CONFLUX_ESPACE_PRIVATE_KEY= CONFLUX_ESPACE_RPC_URL= +CONFLUX_MEME_CONTRACT_ADDRESS= # Coinbase COINBASE_COMMERCE_KEY= # from coinbase developer portal @@ -104,3 +105,4 @@ COINBASE_PRIVATE_KEY= # from coinbase developer portal # if not configured it will be generated and written to runtime.character.settings.secrets.COINBASE_GENERATED_WALLET_ID and runtime.character.settings.secrets.COINBASE_GENERATED_WALLET_HEX_SEED COINBASE_GENERATED_WALLET_ID= # not your address but the wallet id from generating a wallet through the plugin COINBASE_GENERATED_WALLET_HEX_SEED= # not your address but the wallet hex seed from generating a wallet through the plugin and calling export + diff --git a/packages/plugin-conflux/README.md b/packages/plugin-conflux/README.md index e84f2deda2d..faa68cfa76a 100644 --- a/packages/plugin-conflux/README.md +++ b/packages/plugin-conflux/README.md @@ -16,10 +16,10 @@ Transfer tokens from one address to another within Conflux core space. Transfer tokens from one address to Conflux eSpace. -### Sponsor +### Sponsor (TBD) Provide gas for Conflux core space contracts so they can be called without the need to have Conflux in user's wallet. -### Swap +### Swap (TBD) Swap tokens on Conflux DEXs. diff --git a/packages/plugin-conflux/src/abi/crossSpaceCall.json b/packages/plugin-conflux/src/abi/crossSpaceCall.json deleted file mode 100644 index 441774637d0..00000000000 --- a/packages/plugin-conflux/src/abi/crossSpaceCall.json +++ /dev/null @@ -1 +0,0 @@ -[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes20","name":"sender","type":"bytes20"},{"indexed":true,"internalType":"bytes20","name":"receiver","type":"bytes20"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"Call","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes20","name":"sender","type":"bytes20"},{"indexed":true,"internalType":"bytes20","name":"contract_address","type":"bytes20"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"init","type":"bytes"}],"name":"Create","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"success","type":"bool"}],"name":"Outcome","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes20","name":"sender","type":"bytes20"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[{"internalType":"bytes","name":"init","type":"bytes"}],"name":"createEVM","outputs":[{"internalType":"bytes20","name":"","type":"bytes20"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes20","name":"to","type":"bytes20"}],"name":"transferEVM","outputs":[{"internalType":"bytes","name":"output","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes20","name":"to","type":"bytes20"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"callEVM","outputs":[{"internalType":"bytes","name":"output","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes20","name":"to","type":"bytes20"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"staticCallEVM","outputs":[{"internalType":"bytes","name":"output","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deployEip1820","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"withdrawFromMapped","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"mappedBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"mappedNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/packages/plugin-conflux/src/abi/crossSpaceCall.ts b/packages/plugin-conflux/src/abi/crossSpaceCall.ts new file mode 100644 index 00000000000..f9ad2a67a07 --- /dev/null +++ b/packages/plugin-conflux/src/abi/crossSpaceCall.ts @@ -0,0 +1,184 @@ +const CrossSpaceCallAbi = [ + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "bytes20", + name: "sender", + type: "bytes20", + }, + { + indexed: true, + internalType: "bytes20", + name: "receiver", + type: "bytes20", + }, + { + indexed: false, + internalType: "uint256", + name: "value", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "nonce", + type: "uint256", + }, + { + indexed: false, + internalType: "bytes", + name: "data", + type: "bytes", + }, + ], + name: "Call", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "bytes20", + name: "sender", + type: "bytes20", + }, + { + indexed: true, + internalType: "bytes20", + name: "contract_address", + type: "bytes20", + }, + { + indexed: false, + internalType: "uint256", + name: "value", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "nonce", + type: "uint256", + }, + { + indexed: false, + internalType: "bytes", + name: "init", + type: "bytes", + }, + ], + name: "Create", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "bool", + name: "success", + type: "bool", + }, + ], + name: "Outcome", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "bytes20", + name: "sender", + type: "bytes20", + }, + { + indexed: true, + internalType: "address", + name: "receiver", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "value", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "nonce", + type: "uint256", + }, + ], + name: "Withdraw", + type: "event", + }, + { + inputs: [{ internalType: "bytes", name: "init", type: "bytes" }], + name: "createEVM", + outputs: [{ internalType: "bytes20", name: "", type: "bytes20" }], + stateMutability: "payable", + type: "function", + }, + { + inputs: [{ internalType: "bytes20", name: "to", type: "bytes20" }], + name: "transferEVM", + outputs: [{ internalType: "bytes", name: "output", type: "bytes" }], + stateMutability: "payable", + type: "function", + }, + { + inputs: [ + { internalType: "bytes20", name: "to", type: "bytes20" }, + { internalType: "bytes", name: "data", type: "bytes" }, + ], + name: "callEVM", + outputs: [{ internalType: "bytes", name: "output", type: "bytes" }], + stateMutability: "payable", + type: "function", + }, + { + inputs: [ + { internalType: "bytes20", name: "to", type: "bytes20" }, + { internalType: "bytes", name: "data", type: "bytes" }, + ], + name: "staticCallEVM", + outputs: [{ internalType: "bytes", name: "output", type: "bytes" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "deployEip1820", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "value", type: "uint256" }], + name: "withdrawFromMapped", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "addr", type: "address" }], + name: "mappedBalance", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "addr", type: "address" }], + name: "mappedNonce", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, +]; + +export default CrossSpaceCallAbi; diff --git a/packages/plugin-conflux/src/abi/erc20.ts b/packages/plugin-conflux/src/abi/erc20.ts new file mode 100644 index 00000000000..fa3a4262668 --- /dev/null +++ b/packages/plugin-conflux/src/abi/erc20.ts @@ -0,0 +1,119 @@ +const ERC20ABI = [ + { + constant: true, + inputs: [], + name: 'name', + outputs: [{ name: '', type: 'string' }], + payable: false, + stateMutability: 'view', + type: 'function', + }, + { + constant: false, + inputs: [ + { name: '_spender', type: 'address' }, + { name: '_value', type: 'uint256' }, + ], + name: 'approve', + outputs: [{ name: '', type: 'bool' }], + payable: false, + stateMutability: 'view', + type: 'function', + }, + { + constant: true, + inputs: [], + name: 'totalSupply', + outputs: [{ name: '', type: 'uint256' }], + payable: false, + stateMutability: 'view', + type: 'function', + }, + { + constant: false, + inputs: [ + { name: '_from', type: 'address' }, + { name: '_to', type: 'address' }, + { name: '_value', type: 'uint256' }, + ], + name: 'transferFrom', + outputs: [{ name: '', type: 'bool' }], + payable: false, + stateMutability: 'nonpayable', + type: 'function', + }, + { + constant: true, + inputs: [], + name: 'decimals', + outputs: [{ name: '', type: 'uint8' }], + payable: false, + stateMutability: 'view', + type: 'function', + }, + { + constant: true, + inputs: [{ name: '_owner', type: 'address' }], + name: 'balanceOf', + outputs: [{ name: 'balance', type: 'uint256' }], + payable: false, + stateMutability: 'view', + type: 'function', + }, + { + constant: true, + inputs: [], + name: 'symbol', + outputs: [{ name: '', type: 'string' }], + payable: false, + stateMutability: 'view', + type: 'function', + }, + { + constant: false, + inputs: [ + { name: '_to', type: 'address' }, + { name: '_value', type: 'uint256' }, + ], + name: 'transfer', + outputs: [{ name: '', type: 'bool' }], + payable: false, + stateMutability: 'nonpayable', + type: 'function', + }, + { + constant: true, + inputs: [ + { name: '_owner', type: 'address' }, + { name: '_spender', type: 'address' }, + ], + name: 'allowance', + outputs: [{ name: '', type: 'uint256' }], + payable: false, + stateMutability: 'view', + type: 'function', + }, + { payable: true, stateMutability: 'payable', type: 'fallback' }, + { + anonymous: false, + inputs: [ + { indexed: true, name: 'owner', type: 'address' }, + { indexed: true, name: 'spender', type: 'address' }, + { indexed: false, name: 'value', type: 'uint256' }, + ], + name: 'Approval', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { indexed: true, name: 'from', type: 'address' }, + { indexed: true, name: 'to', type: 'address' }, + { indexed: false, name: 'value', type: 'uint256' }, + ], + name: 'Transfer', + type: 'event', + }, +] as const; + +export default ERC20ABI; \ No newline at end of file diff --git a/packages/plugin-conflux/src/abi/meme.ts b/packages/plugin-conflux/src/abi/meme.ts new file mode 100644 index 00000000000..0a1e5044154 --- /dev/null +++ b/packages/plugin-conflux/src/abi/meme.ts @@ -0,0 +1,1671 @@ +const MEMEABI = [ + { + inputs: [ + { + components: [ + { + internalType: "address", + name: "tokenImpl_", + type: "address", + }, + { + internalType: "address", + name: "tokenImplV2_", + type: "address", + }, + { + internalType: "uint256", + name: "feeRate_", + type: "uint256", + }, + { + internalType: "address", + name: "feeReceiver_", + type: "address", + }, + { + internalType: "address", + name: "dexLauncher_", + type: "address", + }, + { + internalType: "enum IConfiPumpTypes.DexThreshType", + name: "defaultDexThreshType_", + type: "uint8", + }, + { + internalType: "enum IConfiPumpTypes.CurveType", + name: "defaultCurveType_", + type: "uint8", + }, + { + internalType: "enum IConfiPumpTypes.TokenVersion", + name: "defaultTokenVersion_", + type: "uint8", + }, + { + internalType: "address", + name: "v2Factory_", + type: "address", + }, + { + internalType: "bytes32", + name: "v2InitCodeHash_", + type: "bytes32", + }, + { + internalType: "address", + name: "weth_", + type: "address", + }, + { + internalType: "uint256", + name: "creation_fee_", + type: "uint256", + }, + { + internalType: "uint256", + name: "lpEth_", + type: "uint256", + }, + { + internalType: "uint256", + name: "lpEthTokenCreator_", + type: "uint256", + }, + ], + internalType: "struct ConfiPumpBase.ConfiPumpInitParams", + name: "params", + type: "tuple", + }, + ], + stateMutability: "nonpayable", + type: "constructor", + }, + { + inputs: [ + { + internalType: "uint256", + name: "actualAmount", + type: "uint256", + }, + { + internalType: "uint256", + name: "amount1", + type: "uint256", + }, + ], + name: "ActualAmountMustLTEAmount", + type: "error", + }, + { + inputs: [ + { + internalType: "uint256", + name: "amount", + type: "uint256", + }, + ], + name: "AmountTooSmall", + type: "error", + }, + { + inputs: [], + name: "CallReverted", + type: "error", + }, + { + inputs: [], + name: "FeatureDisabled", + type: "error", + }, + { + inputs: [], + name: "GameNotLive", + type: "error", + }, + { + inputs: [], + name: "GameNotPaused", + type: "error", + }, + { + inputs: [], + name: "GameNotPending", + type: "error", + }, + { + inputs: [], + name: "GameNotStarted", + type: "error", + }, + { + inputs: [], + name: "InvalidDEXSupplyThreshold", + type: "error", + }, + { + inputs: [ + { + internalType: "uint256", + name: "threshold", + type: "uint256", + }, + ], + name: "InvalidDexThreshold", + type: "error", + }, + { + inputs: [ + { + internalType: "enum IConfiPumpTypes.DexThreshType", + name: "threshold", + type: "uint8", + }, + ], + name: "InvalidDexThresholdType", + type: "error", + }, + { + inputs: [], + name: "InvalidGameSupplyThreshold", + type: "error", + }, + { + inputs: [], + name: "InvalidLocks", + type: "error", + }, + { + inputs: [ + { + internalType: "uint256", + name: "expected", + type: "uint256", + }, + { + internalType: "uint256", + name: "actual", + type: "uint256", + }, + ], + name: "InvalidPiggybackLength", + type: "error", + }, + { + inputs: [ + { + internalType: "uint256", + name: "id", + type: "uint256", + }, + ], + name: "InvalidRoundID", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "signer", + type: "address", + }, + ], + name: "InvalidSigner", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "token", + type: "address", + }, + ], + name: "InvalidTokenForBattle", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "token", + type: "address", + }, + { + internalType: "enum IConfiPumpTypes.TokenMode", + name: "mode", + type: "uint8", + }, + ], + name: "InvalidTokenModeForGame", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "token", + type: "address", + }, + { + internalType: "enum IConfiPumpTypes.TokenMode", + name: "from", + type: "uint8", + }, + { + internalType: "enum IConfiPumpTypes.TokenMode", + name: "to", + type: "uint8", + }, + ], + name: "InvalidTokenModeTransition", + type: "error", + }, + { + inputs: [], + name: "LastRoundNotResolved", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "expected", + type: "address", + }, + { + internalType: "address", + name: "actual", + type: "address", + }, + ], + name: "MismatchedAddressInProof", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "srcToken", + type: "address", + }, + { + internalType: "address", + name: "dstToken", + type: "address", + }, + ], + name: "NoConversionPath", + type: "error", + }, + { + inputs: [ + { + internalType: "uint256", + name: "created", + type: "uint256", + }, + { + internalType: "uint256", + name: "max", + type: "uint256", + }, + ], + name: "NoQuotaForCreator", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "collection", + type: "address", + }, + ], + name: "NonPositionNFTReceived", + type: "error", + }, + { + inputs: [], + name: "NotImplemented", + type: "error", + }, + { + inputs: [], + name: "NotRoller", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "sender", + type: "address", + }, + ], + name: "NotUniswapV3Pool", + type: "error", + }, + { + inputs: [], + name: "PermissionlessCreateDisabled", + type: "error", + }, + { + inputs: [ + { + internalType: "uint160", + name: "sqrtPriceA", + type: "uint160", + }, + { + internalType: "uint160", + name: "sqrtPriceB", + type: "uint160", + }, + ], + name: "PriceAMustLTPriceB", + type: "error", + }, + { + inputs: [], + name: "ProtocolDisabled", + type: "error", + }, + { + inputs: [ + { + internalType: "uint256", + name: "requiredToken", + type: "uint256", + }, + { + internalType: "uint256", + name: "reserveToken", + type: "uint256", + }, + ], + name: "RequiredTokenMustLTE", + type: "error", + }, + { + inputs: [ + { + internalType: "uint256", + name: "id", + type: "uint256", + }, + ], + name: "RoundNotFound", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "tokenA", + type: "address", + }, + ], + name: "SameToken", + type: "error", + }, + { + inputs: [ + { + internalType: "uint256", + name: "seq", + type: "uint256", + }, + ], + name: "SeqNotFound", + type: "error", + }, + { + inputs: [ + { + internalType: "uint256", + name: "actualAmount", + type: "uint256", + }, + { + internalType: "uint256", + name: "minAmount", + type: "uint256", + }, + ], + name: "SlippageTooHigh", + type: "error", + }, + { + inputs: [], + name: "StakingDisabled", + type: "error", + }, + { + inputs: [ + { + internalType: "uint256", + name: "newSupply", + type: "uint256", + }, + ], + name: "SupplyExceedsTotalSupply", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "token", + type: "address", + }, + ], + name: "TokenAlreadyDEXed", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "token", + type: "address", + }, + ], + name: "TokenAlreadyInGame", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "token", + type: "address", + }, + ], + name: "TokenInDuel", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "token", + type: "address", + }, + ], + name: "TokenKilled", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "token", + type: "address", + }, + ], + name: "TokenNotDEXed", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "token", + type: "address", + }, + ], + name: "TokenNotFound", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "token", + type: "address", + }, + ], + name: "TokenNotKilled", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "token", + type: "address", + }, + ], + name: "TokenNotTradable", + type: "error", + }, + { + inputs: [], + name: "TradeDisabled", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "pool", + type: "address", + }, + { + internalType: "uint256", + name: "liquidity", + type: "uint256", + }, + ], + name: "UniswapV2PoolNotZero", + type: "error", + }, + { + inputs: [], + name: "UniswapV3Slot0Failed", + type: "error", + }, + { + inputs: [ + { + internalType: "uint256", + name: "next", + type: "uint256", + }, + ], + name: "cannotCheckInUntil", + type: "error", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "oldFlags", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "newFlags", + type: "uint256", + }, + ], + name: "BitFlagsChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "user", + type: "address", + }, + ], + name: "CheckedIn", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "token", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "newSupply", + type: "uint256", + }, + ], + name: "FlapTokenCirculatingSupplyChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint8", + name: "version", + type: "uint8", + }, + ], + name: "Initialized", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "token", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "pool", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "amount", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "eth", + type: "uint256", + }, + ], + name: "LaunchedToDEX", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "bytes32", + name: "role", + type: "bytes32", + }, + { + indexed: true, + internalType: "bytes32", + name: "previousAdminRole", + type: "bytes32", + }, + { + indexed: true, + internalType: "bytes32", + name: "newAdminRole", + type: "bytes32", + }, + ], + name: "RoleAdminChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "bytes32", + name: "role", + type: "bytes32", + }, + { + indexed: true, + internalType: "address", + name: "account", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "sender", + type: "address", + }, + ], + name: "RoleGranted", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "bytes32", + name: "role", + type: "bytes32", + }, + { + indexed: true, + internalType: "address", + name: "account", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "sender", + type: "address", + }, + ], + name: "RoleRevoked", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "ts", + type: "uint256", + }, + { + indexed: false, + internalType: "address", + name: "token", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "buyer", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "amount", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "eth", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "fee", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "postPrice", + type: "uint256", + }, + ], + name: "TokenBought", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "ts", + type: "uint256", + }, + { + indexed: false, + internalType: "address", + name: "creator", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "nonce", + type: "uint256", + }, + { + indexed: false, + internalType: "address", + name: "token", + type: "address", + }, + { + indexed: false, + internalType: "string", + name: "name", + type: "string", + }, + { + indexed: false, + internalType: "string", + name: "symbol", + type: "string", + }, + { + indexed: false, + internalType: "string", + name: "meta", + type: "string", + }, + ], + name: "TokenCreated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "token", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "curve", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "curveParameter", + type: "uint256", + }, + ], + name: "TokenCurveSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "token", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "dexSupplyThresh", + type: "uint256", + }, + ], + name: "TokenDexSupplyThreshSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "ts", + type: "uint256", + }, + { + indexed: false, + internalType: "address", + name: "srcToken", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "dstToken", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "srcAmount", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "dstAmount", + type: "uint256", + }, + { + indexed: false, + internalType: "address", + name: "who", + type: "address", + }, + ], + name: "TokenRedeemed", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "ts", + type: "uint256", + }, + { + indexed: false, + internalType: "address", + name: "token", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "seller", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "amount", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "eth", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "fee", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "postPrice", + type: "uint256", + }, + ], + name: "TokenSold", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "token", + type: "address", + }, + { + indexed: false, + internalType: "enum IConfiPumpTypes.TokenVersion", + name: "version", + type: "uint8", + }, + ], + name: "TokenVersionSet", + type: "event", + }, + { + stateMutability: "nonpayable", + type: "fallback", + }, + { + inputs: [], + name: "DEFAULT_ADMIN_ROLE", + outputs: [ + { + internalType: "bytes32", + name: "", + type: "bytes32", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "token", + type: "address", + }, + { + internalType: "address", + name: "recipient", + type: "address", + }, + { + internalType: "uint256", + name: "minAmount", + type: "uint256", + }, + { + internalType: "bool", + name: "isCreator", + type: "bool", + }, + ], + name: "buy", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "payable", + type: "function", + }, + { + inputs: [], + name: "checkIn", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "bytes32", + name: "role", + type: "bytes32", + }, + ], + name: "getRoleAdmin", + outputs: [ + { + internalType: "bytes32", + name: "", + type: "bytes32", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "token", + type: "address", + }, + ], + name: "getToken", + outputs: [ + { + components: [ + { + internalType: "enum IConfiPumpTypes.TokenStatus", + name: "status", + type: "uint8", + }, + { + internalType: "uint256", + name: "reserve", + type: "uint256", + }, + { + internalType: "uint256", + name: "circulatingSupply", + type: "uint256", + }, + { + internalType: "uint256", + name: "price", + type: "uint256", + }, + { + internalType: "bool", + name: "inGame", + type: "bool", + }, + { + internalType: "uint256", + name: "seqInGame", + type: "uint256", + }, + ], + internalType: "struct IConfiPumpTypes.TokenState", + name: "", + type: "tuple", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "token", + type: "address", + }, + ], + name: "getTokenEx", + outputs: [ + { + components: [ + { + internalType: "enum IConfiPumpTypes.TokenStatus", + name: "status", + type: "uint8", + }, + { + internalType: "uint256", + name: "reserve", + type: "uint256", + }, + { + internalType: "uint256", + name: "circulatingSupply", + type: "uint256", + }, + { + internalType: "uint256", + name: "price", + type: "uint256", + }, + { + internalType: "bool", + name: "inGame", + type: "bool", + }, + { + internalType: "uint256", + name: "seqInGame", + type: "uint256", + }, + { + internalType: "enum IConfiPumpTypes.TokenMode", + name: "mode", + type: "uint8", + }, + ], + internalType: "struct IConfiPumpTypes.TokenStateEx", + name: "", + type: "tuple", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "token", + type: "address", + }, + ], + name: "getTokenV2", + outputs: [ + { + components: [ + { + internalType: "enum IConfiPumpTypes.TokenStatus", + name: "status", + type: "uint8", + }, + { + internalType: "uint256", + name: "reserve", + type: "uint256", + }, + { + internalType: "uint256", + name: "circulatingSupply", + type: "uint256", + }, + { + internalType: "uint256", + name: "price", + type: "uint256", + }, + { + internalType: "enum IConfiPumpTypes.TokenVersion", + name: "tokenVersion", + type: "uint8", + }, + { + internalType: "uint256", + name: "r", + type: "uint256", + }, + { + internalType: "uint256", + name: "dexSupplyThresh", + type: "uint256", + }, + ], + internalType: "struct IConfiPumpTypes.TokenStateV2", + name: "state", + type: "tuple", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "bytes32", + name: "role", + type: "bytes32", + }, + { + internalType: "address", + name: "account", + type: "address", + }, + ], + name: "grantRole", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "bytes32", + name: "role", + type: "bytes32", + }, + { + internalType: "address", + name: "account", + type: "address", + }, + ], + name: "hasRole", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "admin", + type: "address", + }, + ], + name: "initialize", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "account", + type: "address", + }, + ], + name: "lastCheckIn", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "string", + name: "name", + type: "string", + }, + { + internalType: "string", + name: "symbol", + type: "string", + }, + { + internalType: "string", + name: "meta", + type: "string", + }, + ], + name: "newToken", + outputs: [ + { + internalType: "address", + name: "token", + type: "address", + }, + ], + stateMutability: "payable", + type: "function", + }, + { + inputs: [ + { + internalType: "string", + name: "name", + type: "string", + }, + { + internalType: "string", + name: "symbol", + type: "string", + }, + { + internalType: "string", + name: "meta", + type: "string", + }, + ], + name: "newTokenNoDuel", + outputs: [ + { + internalType: "address", + name: "token", + type: "address", + }, + ], + stateMutability: "payable", + type: "function", + }, + { + inputs: [ + { + internalType: "string", + name: "name", + type: "string", + }, + { + internalType: "string", + name: "symbol", + type: "string", + }, + { + internalType: "string", + name: "meta", + type: "string", + }, + { + internalType: "enum IConfiPumpTypes.DexThreshType", + name: "dexTreshType", + type: "uint8", + }, + ], + name: "newTokenWithDexSupplyThresh", + outputs: [ + { + internalType: "address", + name: "token", + type: "address", + }, + ], + stateMutability: "payable", + type: "function", + }, + { + inputs: [], + name: "nonce", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "token", + type: "address", + }, + { + internalType: "uint256", + name: "eth", + type: "uint256", + }, + ], + name: "previewBuy", + outputs: [ + { + internalType: "uint256", + name: "amount", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "srcToken", + type: "address", + }, + { + internalType: "address", + name: "dstToken", + type: "address", + }, + { + internalType: "uint256", + name: "srcAmount", + type: "uint256", + }, + ], + name: "previewRedeem", + outputs: [ + { + internalType: "uint256", + name: "dstAmount", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "token", + type: "address", + }, + { + internalType: "uint256", + name: "amount", + type: "uint256", + }, + ], + name: "previewSell", + outputs: [ + { + internalType: "uint256", + name: "eth", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "srcToken", + type: "address", + }, + { + internalType: "address", + name: "dstToken", + type: "address", + }, + { + internalType: "uint256", + name: "srcAmount", + type: "uint256", + }, + ], + name: "redeem", + outputs: [ + { + internalType: "uint256", + name: "dstAmount", + type: "uint256", + }, + ], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "bytes32", + name: "role", + type: "bytes32", + }, + { + internalType: "address", + name: "account", + type: "address", + }, + ], + name: "renounceRole", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "bytes32", + name: "role", + type: "bytes32", + }, + { + internalType: "address", + name: "account", + type: "address", + }, + ], + name: "revokeRole", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "token", + type: "address", + }, + { + internalType: "uint256", + name: "amount", + type: "uint256", + }, + { + internalType: "uint256", + name: "minEth", + type: "uint256", + }, + ], + name: "sell", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "flags", + type: "uint256", + }, + ], + name: "setBitFlags", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "bytes4", + name: "interfaceId", + type: "bytes4", + }, + ], + name: "supportsInterface", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + name: "tokenCreators", + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + name: "tokenCreatorsFeeBalance", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + stateMutability: "payable", + type: "receive", + }, +] as const; + +export default MEMEABI; diff --git a/packages/plugin-conflux/src/actions/bridgeTransfer.ts b/packages/plugin-conflux/src/actions/bridgeTransfer.ts index 8b8363f6de6..347b8b980e1 100644 --- a/packages/plugin-conflux/src/actions/bridgeTransfer.ts +++ b/packages/plugin-conflux/src/actions/bridgeTransfer.ts @@ -12,7 +12,7 @@ import { privateKeyToAccount } from "cive/accounts"; import { testnet } from "cive/chains"; import { confluxBridgeTransferTemplate } from "../templates/bridgeTransfer"; import { TransferSchema, isTransferContent } from "../types"; -import crossSpaceCallAbi from "../abi/crossSpaceCall.json"; +import CrossSpaceCallAbi from "../abi/crossSpaceCall"; const bridgeSendCFX = async ( secretKey: `0x${string}`, @@ -42,7 +42,7 @@ const bridgeSendCFX = async ( value: parseCFX(amount), chain: testnet, data: encodeFunctionData({ - abi: crossSpaceCallAbi, + abi: CrossSpaceCallAbi, functionName: "transferEVM", args: [espaceTo], }), diff --git a/packages/plugin-conflux/src/actions/confiPump.ts b/packages/plugin-conflux/src/actions/confiPump.ts index e69de29bb2d..a852b96227e 100644 --- a/packages/plugin-conflux/src/actions/confiPump.ts +++ b/packages/plugin-conflux/src/actions/confiPump.ts @@ -0,0 +1,331 @@ +import { + Action, + IAgentRuntime, + Memory, + State, + HandlerCallback, +} from "@ai16z/eliza"; +import { + generateObjectV2, + composeContext, + ModelClass, +} from "@ai16z/eliza"; +import { + createPublicClient, + createWalletClient, + http, + parseEther, + encodeFunctionData, + WalletClient, + Account +} from "viem"; +import { privateKeyToAccount } from "viem/accounts"; +import { confluxESpaceTestnet, confluxESpace } from "viem/chains"; +import { parseUnits, getAddress } from "viem/utils"; +import { confluxTransferTemplate } from "../templates/transfer"; +import { + PumpSchema, + isPumpContent, + isPumpBuyContent, + isPumpCreateContent, + isPumpSellContent, +} from "../types"; +import MEMEABI from "../abi/meme"; +import ERC20ABI from "../abi/erc20"; + +// Helper function to check and approve token allowance if needed +async function ensureAllowance( + walletClient: WalletClient, + rpcUrl: string, + account: Account, + tokenAddress: `0x${string}`, + memeAddress: `0x${string}`, + amount: bigint +) { + console.log(`Checking allowance: token: ${tokenAddress} meme: ${memeAddress} amount: ${amount}`); + + const publicClient = createPublicClient({ + transport: http(rpcUrl), + chain: confluxESpaceTestnet, + }); + + const allowance = await publicClient.readContract({ + address: tokenAddress, + abi: ERC20ABI, + functionName: "allowance", + args: [account.address, memeAddress], + }); + + console.log("allowance:", allowance); + + if (allowance < amount) { + console.log(`allowance(${allowance}) is less than amount(${amount}), approving...`); + + const hash = await walletClient.sendTransaction({ + account, + to: tokenAddress, + data: encodeFunctionData({ + abi: ERC20ABI, + functionName: "approve", + args: [memeAddress, amount - allowance], + }), + chain: confluxESpaceTestnet, + kzg: null, + }); + + console.log(`Approving hash: ${hash}`); + await publicClient.waitForTransactionReceipt({ hash }); + console.log(`Approving success: ${hash}`); + } else { + console.log(`No need to approve`); + } +} + +// Main ConfiPump action definition +export const confiPump: Action = { + name: "CONFI_PUMP", + description: "Perform actions on ConfiPump, for example create a new token, buy a token, or sell a token.", + similes: ["SELL_TOKEN", "BUY_TOKEN", "CREATE_TOKEN"], + examples: [ + // Create token example + [ + { + user: "{{user1}}", + content: { + text: "Create a new token called GLITCHIZA with symbol GLITCHIZA and generate a description about it.", + }, + }, + { + user: "{{user2}}", + content: { + text: "Token GLITCHIZA (GLITCHIZA) created successfully!\nContract Address: 0x1234567890abcdef\n", + action: "CREATE_TOKEN", + content: { + tokenInfo: { + symbol: "GLITCHIZA", + address: "EugPwuZ8oUMWsYHeBGERWvELfLGFmA1taDtmY8uMeX6r", + creator: "9jW8FPr6BSSsemWPV22UUCzSqkVdTp6HTyPqeqyuBbCa", + name: "GLITCHIZA", + description: "A GLITCHIZA token", + }, + amount: "1", + }, + }, + }, + ], + // Buy token example + [ + { + user: "{{user1}}", + content: { + text: "Buy 0.00069 CFX worth of GLITCHIZA(0x1234567890abcdef)", + }, + }, + { + user: "{{user2}}", + content: { + text: "0.00069 CFX bought successfully!", + action: "BUY_TOKEN", + content: { + address: "0x1234567890abcdef", + amount: "0.00069", + }, + }, + }, + ], + // Sell token example + [ + { + user: "{{user1}}", + content: { + text: "Sell 0.00069 CFX worth of GLITCHIZA(0x1234567890abcdef)", + }, + }, + { + user: "{{user2}}", + content: { + text: "0.00069 CFX sold successfully: 0x1234567890abcdef", + action: "SELL_TOKEN", + content: { + address: "0x1234567890abcdef", + amount: "0.00069", + }, + }, + }, + ], + ], + + validate: async (runtime: IAgentRuntime, message: Memory) => { + return true; // No extra validation needed + }, + + handler: async ( + runtime: IAgentRuntime, + message: Memory, + state?: State, + options?: { [key: string]: unknown }, + callback?: HandlerCallback + ) => { + let success = false; + + // Initialize or update state + if (!state) { + state = (await runtime.composeState(message)) as State; + } else { + state = await runtime.updateRecentMessageState(state); + } + + // Generate content based on template + const context = composeContext({ + state, + template: confluxTransferTemplate, + }); + + const content = await generateObjectV2({ + runtime, + context, + modelClass: ModelClass.LARGE, + schema: PumpSchema, + }); + + if (!isPumpContent(content.object)) { + throw new Error("Invalid content"); + } + + // Setup clients and account + const rpcUrl = runtime.getSetting("CONFLUX_ESPACE_RPC_URL"); + const account = privateKeyToAccount( + runtime.getSetting("CONFLUX_ESPACE_PRIVATE_KEY") as `0x${string}` + ); + const walletClient = createWalletClient({ + transport: http(rpcUrl), + }); + + const contentObject = content.object; + let data: any; + let value: bigint; + + try { + // Handle different action types + switch (contentObject.action) { + case "CREATE_TOKEN": + if (!isPumpCreateContent(contentObject)) { + throw new Error("Invalid content"); + } + console.log( + "creating: ", + contentObject.params.name, + contentObject.params.symbol, + contentObject.params.description + ); + data = encodeFunctionData({ + abi: MEMEABI, + functionName: "newToken", + args: [ + contentObject.params.name, + contentObject.params.symbol, + contentObject.params.description, + ], + }); + value = parseEther("10"); + break; + + case "BUY_TOKEN": + if (!isPumpBuyContent(contentObject)) { + throw new Error("Invalid content"); + } + value = parseUnits(contentObject.params.value.toString(), 18); + console.log("buying: ", contentObject.params.tokenAddress, value); + data = encodeFunctionData({ + abi: MEMEABI, + functionName: "buy", + args: [ + contentObject.params.tokenAddress as `0x${string}`, + account.address, + 0n, + false, + ], + }); + break; + + case "SELL_TOKEN": + if (!isPumpSellContent(contentObject)) { + throw new Error("Invalid content"); + } + const tokenAddress = getAddress( + contentObject.params.tokenAddress as `0x${string}` + ); + console.log( + "selling: ", + tokenAddress, + account.address, + contentObject.params.value + ); + const amountUnits = parseUnits( + contentObject.params.value.toString(), + 18 + ); + + await ensureAllowance( + walletClient, + rpcUrl, + account, + tokenAddress as `0x${string}`, + runtime.getSetting("CONFLUX_MEME_CONTRACT_ADDRESS") as `0x${string}`, + amountUnits + ); + + data = encodeFunctionData({ + abi: MEMEABI, + functionName: "sell", + args: [tokenAddress, amountUnits, 0n], + }); + value = 0n; + break; + } + + // Simulate and execute transaction + const publicClient = createPublicClient({ + transport: http(rpcUrl), + chain: confluxESpaceTestnet, + }); + + const memeContractAddress = runtime.getSetting("CONFLUX_MEME_CONTRACT_ADDRESS") as `0x${string}`; + + const simulate = await publicClient.call({ + to: memeContractAddress, + data, + value, + account, + }); + console.log("simulate: ", simulate); + + const hash = await walletClient.sendTransaction({ + account, + to: memeContractAddress, + data, + chain: confluxESpaceTestnet, + kzg: null, + value, + }); + + success = true; + + if (callback) { + callback({ + text: `Perform the action successfully: ${content.object.action}: ${hash}`, + content: content.object, + }); + } + } catch (error) { + console.error(`Error performing the action: ${error}`); + if (callback) { + callback({ + text: `Failed to perform the action: ${content.object.action}: ${error}`, + }); + } + } + + return success; + }, +}; diff --git a/packages/plugin-conflux/src/actions/sponsor.ts b/packages/plugin-conflux/src/actions/sponsor.ts deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/packages/plugin-conflux/src/index.ts b/packages/plugin-conflux/src/index.ts index 12acf8bce4e..1c6e65989e3 100644 --- a/packages/plugin-conflux/src/index.ts +++ b/packages/plugin-conflux/src/index.ts @@ -1,10 +1,11 @@ import { Plugin } from "@ai16z/eliza"; import { transfer } from "./actions/transfer"; import { bridgeTransfer } from "./actions/bridgeTransfer"; +import { confiPump } from "./actions/confiPump"; export const confluxPlugin: Plugin = { name: "conflux", description: "Conflux Plugin for Eliza", - actions: [transfer, bridgeTransfer], + actions: [transfer, bridgeTransfer, confiPump], providers: [], }; diff --git a/packages/plugin-conflux/src/templates/confiPump.ts b/packages/plugin-conflux/src/templates/confiPump.ts new file mode 100644 index 00000000000..b3047fc8027 --- /dev/null +++ b/packages/plugin-conflux/src/templates/confiPump.ts @@ -0,0 +1,9 @@ +export const confiPumpTemplate = ` +Extract Conflux ConfiPump Parameters, including token creation, buy, and sell, from the latest messages: + +{{recentMessages}} + +For token creation, should come up with a name, symbol, and description. +For token buy, should come up with the amount of CFX to buy which token (with token address starting with 0x). +For token sell, should come up with the amount of token to sell (with token address starting with 0x). +`; diff --git a/packages/plugin-conflux/src/types.ts b/packages/plugin-conflux/src/types.ts index 20fb8a57a24..5f033da3f47 100644 --- a/packages/plugin-conflux/src/types.ts +++ b/packages/plugin-conflux/src/types.ts @@ -6,7 +6,7 @@ export const TransferSchema = z.object({ amount: z.number(), // use number ignoring decimals issue }); -export interface TransferContent extends Content { +export interface TransferContent { to: string; amount: number; } @@ -17,4 +17,69 @@ export const isTransferContent = (object: any): object is TransferContent => { } console.error("Invalid content: ", object); return false; -}; \ No newline at end of file +}; + +export const PumpCreateSchema = z.object({ + action: z.literal("CREATE_TOKEN"), + params: z.object({ + symbol: z.string(), + name: z.string(), + description: z.string(), + }), +}); + +export const PumpBuySchema = z.object({ + action: z.literal("BUY_TOKEN"), + params: z.object({ + tokenAddress: z.string(), + value: z.number(), + }), +}); + +export const PumpSellSchema = z.object({ + action: z.literal("SELL_TOKEN"), + params: z.object({ + tokenAddress: z.string(), + value: z.number(), + }), +}); + +export const PumpSchema = z.union([PumpCreateSchema, PumpBuySchema, PumpSellSchema]); + +export type PumpContent = z.infer<typeof PumpSchema>; +export type PumpCreateContent = z.infer<typeof PumpCreateSchema>; +export type PumpBuyContent = z.infer<typeof PumpBuySchema>; +export type PumpSellContent = z.infer<typeof PumpSellSchema>; + +export function isPumpContent(object: any): object is PumpContent { + if (PumpSchema.safeParse(object).success) { + return true; + } + console.error("Invalid content: ", object); + return false; +} + +export function isPumpCreateContent(object: any): object is PumpCreateContent { + if (PumpCreateSchema.safeParse(object).success) { + return true; + } + console.error("Invalid content: ", object); + return false; +} + +export function isPumpBuyContent(object: any): object is PumpBuyContent { + if (PumpBuySchema.safeParse(object).success) { + return true; + } + console.error("Invalid content: ", object); + return false; +} + +export function isPumpSellContent(object: any): object is PumpSellContent { + if (PumpSellSchema.safeParse(object).success) { + return true; + } + console.error("Invalid content: ", object); + return false; +} + From 7a2af46b9d6ed6bf34645c671516a56b9e98bc71 Mon Sep 17 00:00:00 2001 From: darwintree <17946284+darwintree@users.noreply.github.com> Date: Thu, 21 Nov 2024 18:19:41 +0800 Subject: [PATCH 4/4] fix: missed build option --- scripts/build.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/build.sh b/scripts/build.sh index 9fbbe5f2fb0..a6cb245aeef 100644 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -24,6 +24,7 @@ PACKAGES=( "plugin-trustdb" "plugin-solana" "plugin-starknet" + "plugin-conflux" "adapter-postgres" "adapter-sqlite" "adapter-sqljs"