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
1 change: 1 addition & 0 deletions packages/plugin-conflux/src/abi/crossSpaceCall.json
Original file line number Diff line number Diff line change
@@ -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"}]
141 changes: 141 additions & 0 deletions packages/plugin-conflux/src/actions/bridgeTransfer.ts
Original file line number Diff line number Diff line change
@@ -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;
},
};
Empty file.
Empty file.
34 changes: 8 additions & 26 deletions packages/plugin-conflux/src/actions/transfer.ts
Original file line number Diff line number Diff line change
@@ -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",
},
},
3 changes: 2 additions & 1 deletion packages/plugin-conflux/src/index.ts
Original file line number Diff line number Diff line change
@@ -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: [],
};
7 changes: 7 additions & 0 deletions packages/plugin-conflux/src/templates/bridgeTransfer.ts
Original file line number Diff line number Diff line change
@@ -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".
`;
20 changes: 20 additions & 0 deletions packages/plugin-conflux/src/types.ts
Original file line number Diff line number Diff line change
@@ -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;
};