Skip to content

Commit 91d26a1

Browse files
committed
Merge branch 'develop' of https://github.com/PumpChat-AI/eliza into develop
2 parents 7137194 + 9fa7076 commit 91d26a1

File tree

12 files changed

+700
-39818
lines changed

12 files changed

+700
-39818
lines changed

.env.example

+4
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,10 @@ NEAR_NETWORK=testnet # or mainnet
281281
ZKSYNC_ADDRESS=
282282
ZKSYNC_PRIVATE_KEY=
283283

284+
# Ton
285+
TON_PRIVATE_KEY= # Ton Mnemonic Seed Phrase Join With Empty String
286+
TON_RPC_URL= # ton rpc
287+
284288
# AWS S3 Configuration Settings for File Upload
285289
AWS_ACCESS_KEY_ID=
286290
AWS_SECRET_ACCESS_KEY=

agent/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
"@ai16z/plugin-node": "workspace:*",
4141
"@ai16z/plugin-solana": "workspace:*",
4242
"@ai16z/plugin-starknet": "workspace:*",
43+
"@ai16z/plugin-ton": "workspace:*",
4344
"@ai16z/plugin-tee": "workspace:*",
4445
"@ai16z/plugin-multiversx": "workspace:*",
4546
"@ai16z/plugin-near": "workspace:*",

agent/src/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import { createNodePlugin } from "@ai16z/plugin-node";
4545
import { solanaPlugin } from "@ai16z/plugin-solana";
4646
import { teePlugin, TEEMode } from "@ai16z/plugin-tee";
4747
import { aptosPlugin, TransferAptosToken } from "@ai16z/plugin-aptos";
48+
import { tonPlugin } from "@ai16z/plugin-ton";
4849
import { flowPlugin } from "@ai16z/plugin-flow";
4950
import { multiversxPlugin } from "@ai16z/plugin-multiversx";
5051
import { nearPlugin } from "@ai16z/plugin-near";
@@ -515,6 +516,7 @@ export async function createAgent(
515516
getSecret(character, "APTOS_PRIVATE_KEY") ? aptosPlugin : null,
516517
getSecret(character, "MVX_PRIVATE_KEY") ? multiversxPlugin : null,
517518
getSecret(character, "ZKSYNC_PRIVATE_KEY") ? zksyncEraPlugin : null,
519+
getSecret(character, "TON_PRIVATE_KEY") ? tonPlugin : null,
518520
].filter(Boolean),
519521
providers: [],
520522
actions: [],

packages/plugin-ton/package.json

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"name": "@ai16z/plugin-ton",
3+
"version": "0.1.5-alpha.5",
4+
"main": "dist/index.js",
5+
"type": "module",
6+
"types": "dist/index.d.ts",
7+
"dependencies": {
8+
"@ai16z/eliza": "workspace:*",
9+
"@ai16z/plugin-trustdb": "workspace:*",
10+
"bignumber": "1.1.0",
11+
"bignumber.js": "9.1.2",
12+
"node-cache": "5.1.2",
13+
"@ton/ton": "15.1.0",
14+
"@ton/crypto": "3.3.0",
15+
"tsup": "8.3.5"
16+
},
17+
"scripts": {
18+
"build": "tsup --format esm --dts",
19+
"dev": "tsup --format esm --dts --watch",
20+
"test": "vitest run"
21+
},
22+
"peerDependencies": {
23+
"whatwg-url": "7.1.0"
24+
}
25+
}
+220
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
import {
2+
elizaLogger,
3+
composeContext,
4+
Content,
5+
HandlerCallback,
6+
ModelClass,
7+
generateObjectV2,
8+
type IAgentRuntime,
9+
type Memory,
10+
type State,
11+
} from "@ai16z/eliza";
12+
import { z } from "zod";
13+
14+
import { initWalletProvider, WalletProvider, nativeWalletProvider } from "../providers/wallet";
15+
import { internal } from "@ton/ton";
16+
17+
export interface TransferContent extends Content {
18+
recipient: string;
19+
amount: string | number;
20+
}
21+
22+
function isTransferContent(content: Content): content is TransferContent {
23+
console.log("Content for transfer", content);
24+
return (
25+
typeof content.recipient === "string" &&
26+
(typeof content.amount === "string" ||
27+
typeof content.amount === "number")
28+
);
29+
}
30+
31+
const transferTemplate = `Respond with a JSON markdown block containing only the extracted values. Use null for any values that cannot be determined.
32+
33+
Example response:
34+
\`\`\`json
35+
{
36+
"recipient": "EQCGScrZe1xbyWqWDvdI6mzP-GAcAWFv6ZXuaJOuSqemxku4",
37+
"amount": "1"
38+
}
39+
\`\`\`
40+
41+
{{recentMessages}}
42+
43+
Given the recent messages, extract the following information about the requested token transfer:
44+
- Recipient wallet address
45+
- Amount to transfer
46+
47+
Respond with a JSON markdown block containing only the extracted values.`;
48+
49+
export class TransferAction {
50+
constructor(private walletProvider: WalletProvider) {}
51+
52+
async transfer(params: TransferContent): Promise<string> {
53+
console.log(
54+
`Transferring: ${params.amount} tokens to (${params.recipient})`
55+
);
56+
57+
const walletClient = this.walletProvider.getWalletClient();
58+
const contract = walletClient.open(this.walletProvider.wallet);
59+
60+
try {
61+
// Create a transfer
62+
const seqno: number = await contract.getSeqno();
63+
const transfer = await contract.createTransfer({
64+
seqno,
65+
secretKey: this.walletProvider.keypair.secretKey,
66+
messages: [internal({
67+
value: params.amount.toString(),
68+
to: params.recipient,
69+
body: 'eliza ton wallet plugin',
70+
})]
71+
});
72+
73+
await contract.send(transfer);
74+
75+
// await this.waitForTransaction(seqno, contract);
76+
77+
return transfer.hash().toString('hex');
78+
79+
} catch (error) {
80+
throw new Error(`Transfer failed: ${error.message}`);
81+
}
82+
}
83+
}
84+
85+
const buildTransferDetails = async (
86+
runtime: IAgentRuntime,
87+
message: Memory,
88+
state: State,
89+
): Promise<TransferContent> => {
90+
const walletInfo = await nativeWalletProvider.get(runtime, message, state);
91+
state.walletInfo = walletInfo;
92+
93+
// Initialize or update state
94+
if (!state) {
95+
state = (await runtime.composeState(message)) as State;
96+
} else {
97+
state = await runtime.updateRecentMessageState(state);
98+
}
99+
100+
// Define the schema for the expected output
101+
const transferSchema = z.object({
102+
recipient: z.string(),
103+
amount: z.union([z.string(), z.number()]),
104+
});
105+
106+
// Compose transfer context
107+
const transferContext = composeContext({
108+
state,
109+
template: transferTemplate,
110+
});
111+
112+
// Generate transfer content with the schema
113+
const content = await generateObjectV2({
114+
runtime,
115+
context: transferContext,
116+
schema: transferSchema,
117+
modelClass: ModelClass.SMALL,
118+
});
119+
120+
const transferContent = content.object as TransferContent;
121+
122+
return transferContent;
123+
};
124+
125+
export default {
126+
name: "SEND_TOKEN",
127+
similes: [
128+
"SEND_TOKENS",
129+
"TOKEN_TRANSFER",
130+
"MOVE_TOKENS",
131+
"SEND_TON"
132+
],
133+
description: "Transfer tokens from the agent's wallet to another",
134+
handler: async (
135+
runtime: IAgentRuntime,
136+
message: Memory,
137+
state: State,
138+
options: any,
139+
callback?: HandlerCallback
140+
) => {
141+
elizaLogger.log("Starting SEND_TOKEN handler...");
142+
143+
const transferDetails = await buildTransferDetails(
144+
runtime,
145+
message,
146+
state,
147+
);
148+
149+
// Validate transfer content
150+
if (!isTransferContent(transferDetails)) {
151+
console.error("Invalid content for TRANSFER_TOKEN action.");
152+
if (callback) {
153+
callback({
154+
text: "Unable to process transfer request. Invalid content provided.",
155+
content: { error: "Invalid transfer content" },
156+
});
157+
}
158+
return false;
159+
}
160+
161+
try {
162+
163+
const walletProvider = await initWalletProvider(runtime);
164+
const action = new TransferAction(walletProvider);
165+
const hash = await action.transfer(transferDetails);
166+
167+
if (callback) {
168+
callback({
169+
text: `Successfully transferred ${transferDetails.amount} TON to ${transferDetails.recipient}, Transaction: ${hash}`,
170+
content: {
171+
success: true,
172+
hash: hash,
173+
amount: transferDetails.amount,
174+
recipient: transferDetails.recipient,
175+
},
176+
});
177+
}
178+
179+
return true;
180+
} catch (error) {
181+
console.error("Error during token transfer:", error);
182+
if (callback) {
183+
callback({
184+
text: `Error transferring tokens: ${error.message}`,
185+
content: { error: error.message },
186+
});
187+
}
188+
return false;
189+
}
190+
},
191+
template: transferTemplate,
192+
validate: async (runtime: IAgentRuntime) => {
193+
//console.log("Validating TON transfer from user:", message.userId);
194+
return true;
195+
},
196+
examples: [
197+
[
198+
{
199+
user: "{{user1}}",
200+
content: {
201+
text: "Send 1 TON tokens to EQCGScrZe1xbyWqWDvdI6mzP-GAcAWFv6ZXuaJOuSqemxku4",
202+
action: "SEND_TOKENS",
203+
},
204+
},
205+
{
206+
user: "{{user2}}",
207+
content: {
208+
text: "I'll send 1 TON tokens now...",
209+
action: "SEND_TOKENS",
210+
},
211+
},
212+
{
213+
user: "{{user2}}",
214+
content: {
215+
text: "Successfully sent 1 TON tokens to EQCGScrZe1xbyWqWDvdI6mzP-GAcAWFv6ZXuaJOuSqemxku4, Transaction: c8ee4a2c1bd070005e6cd31b32270aa461c69b927c3f4c28b293c80786f78b43",
216+
},
217+
},
218+
],
219+
],
220+
};

packages/plugin-ton/src/enviroment.ts

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { IAgentRuntime } from "@ai16z/eliza";
2+
import { z } from "zod";
3+
4+
export const envSchema = z.object({
5+
TON_PRIVATE_KEY: z.string().min(1, "Ton private key is required"),
6+
TON_RPC_URL: z.string(),
7+
});
8+
9+
export type EnvConfig = z.infer<typeof envSchema>;
10+
11+
export async function validateEnvConfig(
12+
runtime: IAgentRuntime
13+
): Promise<EnvConfig> {
14+
try {
15+
const config = {
16+
TON_PRIVATE_KEY:
17+
runtime.getSetting("TON_PRIVATE_KEY") ||
18+
process.env.TON_PRIVATE_KEY,
19+
TON_RPC_URL:
20+
runtime.getSetting("TON_RPC_URL") ||
21+
process.env.TON_RPC_URL,
22+
};
23+
24+
return envSchema.parse(config);
25+
} catch (error) {
26+
if (error instanceof z.ZodError) {
27+
const errorMessages = error.errors
28+
.map((err) => `${err.path.join(".")}: ${err.message}`)
29+
.join("\n");
30+
throw new Error(
31+
`Ton configuration validation failed:\n${errorMessages}`
32+
);
33+
}
34+
throw error;
35+
}
36+
}

packages/plugin-ton/src/index.ts

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { Plugin } from "@ai16z/eliza";
2+
import transferAction from "./actions/transfer.ts";
3+
import { WalletProvider, nativeWalletProvider } from "./providers/wallet.ts";
4+
5+
export { WalletProvider, transferAction as TransferTonToken };
6+
7+
export const tonPlugin: Plugin = {
8+
name: "ton",
9+
description: "Ton Plugin for Eliza",
10+
actions: [transferAction],
11+
evaluators: [],
12+
providers: [nativeWalletProvider],
13+
};
14+
15+
export default tonPlugin;

0 commit comments

Comments
 (0)