Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add Conflux plugin #481

Merged
merged 4 commits into from
Nov 26, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
feat: transfer on Conflux (conflux-plugin)
  • Loading branch information
darwintree committed Nov 25, 2024
commit e9d343d8a7a42b855dedecd982f672d32cb19301
6 changes: 6 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -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
1 change: 1 addition & 0 deletions agent/package.json
Original file line number Diff line number Diff line change
@@ -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:*",
4 changes: 4 additions & 0 deletions agent/src/index.ts
Original file line number Diff line number Diff line change
@@ -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 ||
25 changes: 25 additions & 0 deletions packages/plugin-conflux/README.md
Original file line number Diff line number Diff line change
@@ -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.
15 changes: 15 additions & 0 deletions packages/plugin-conflux/package.json
Original file line number Diff line number Diff line change
@@ -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"
}
}
147 changes: 147 additions & 0 deletions packages/plugin-conflux/src/actions/transfer.ts
Original file line number Diff line number Diff line change
@@ -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;
},
};
9 changes: 9 additions & 0 deletions packages/plugin-conflux/src/index.ts
Original file line number Diff line number Diff line change
@@ -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: [],
};
7 changes: 7 additions & 0 deletions packages/plugin-conflux/src/templates/transfer.ts
Original file line number Diff line number Diff line change
@@ -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:".
`;
8 changes: 8 additions & 0 deletions packages/plugin-conflux/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "./src"
},
"include": ["src"]
}
13 changes: 13 additions & 0 deletions packages/plugin-conflux/tsup.config.ts
Original file line number Diff line number Diff line change
@@ -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
],
});