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"