Skip to content

Commit

Permalink
Merge branch 'develop' into sif-dev
Browse files Browse the repository at this point in the history
  • Loading branch information
actions-user committed Jan 8, 2025
2 parents 6f35cb9 + 07da475 commit ba0c7fa
Show file tree
Hide file tree
Showing 15 changed files with 915 additions and 0 deletions.
1 change: 1 addition & 0 deletions agent/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"@elizaos/plugin-goat": "workspace:*",
"@elizaos/plugin-icp": "workspace:*",
"@elizaos/plugin-image-generation": "workspace:*",
"@elizaos/plugin-movement": "workspace:*",
"@elizaos/plugin-nft-generation": "workspace:*",
"@elizaos/plugin-node": "workspace:*",
"@elizaos/plugin-solana": "workspace:*",
Expand Down
6 changes: 6 additions & 0 deletions packages/plugin-movement/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
*

!dist/**
!package.json
!readme.md
!tsup.config.ts
3 changes: 3 additions & 0 deletions packages/plugin-movement/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import eslintGlobalConfig from "../../eslint.config.mjs";

export default [...eslintGlobalConfig];
30 changes: 30 additions & 0 deletions packages/plugin-movement/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "@elizaos/plugin-movement",
"version": "0.1.0",
"main": "dist/index.js",
"type": "module",
"types": "dist/index.d.ts",
"description": "Movement Network Plugin for Eliza",
"dependencies": {
"@elizaos/core": "workspace:*",
"@aptos-labs/ts-sdk": "^1.26.0",
"bignumber": "1.1.0",
"bignumber.js": "9.1.2",
"node-cache": "5.1.2"
},
"devDependencies": {
"tsup": "8.3.5",
"vitest": "2.1.4",
"typescript": "^5.0.0"
},
"scripts": {
"build": "tsup",
"dev": "tsup --watch",
"lint": "eslint --fix --cache .",
"test": "vitest run"
},
"peerDependencies": {
"form-data": "4.0.1",
"whatwg-url": "7.1.0"
}
}
43 changes: 43 additions & 0 deletions packages/plugin-movement/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# @elizaos/plugin-movement

Movement Network plugin for Eliza OS. This plugin enables Movement Network blockchain functionality for your Eliza agent.

## Features

- Send MOVE tokens
- Check wallet balances
- Support for Movement Network transactions

## Installation

```bash
pnpm add @elizaos/plugin-movement
```

## Instructions

1. First, ensure you have a Movement Network wallet and private key.

2. Add the Movement plugin to your character's configuration:

```json
{
"name": "Movement Agent",
"plugins": ["@elizaos/plugin-movement"],
"settings": {
"secrets": {
"MOVEMENT_PRIVATE_KEY": "your_private_key_here",
"MOVEMENT_NETWORK": "bardock"
}
}
}
```

Set up your environment variables in the `.env` file:

```bash
MOVEMENT_PRIVATE_KEY=your_private_key_here
MOVEMENT_NETWORK=bardock
```


261 changes: 261 additions & 0 deletions packages/plugin-movement/src/actions/transfer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
import { elizaLogger } from "@elizaos/core";
import {
ActionExample,
Content,
HandlerCallback,
IAgentRuntime,
Memory,
ModelClass,
State,
type Action,
} from "@elizaos/core";
import { composeContext } from "@elizaos/core";
import { generateObjectDeprecated } from "@elizaos/core";
import {
Account,
Aptos,
AptosConfig,
Ed25519PrivateKey,
Network,
PrivateKey,
PrivateKeyVariants,
} from "@aptos-labs/ts-sdk";
import { walletProvider } from "../providers/wallet";
import { MOVEMENT_NETWORK_CONFIG, MOVE_DECIMALS, MOVEMENT_EXPLORER_URL } from "../constants";

export interface TransferContent extends Content {
recipient: string;
amount: string | number;
}

function isTransferContent(content: any): content is TransferContent {
elizaLogger.debug("Validating transfer content:", content);
return (
typeof content.recipient === "string" &&
(typeof content.amount === "string" ||
typeof content.amount === "number")
);
}

const transferTemplate = `You are processing a token transfer request. Extract the recipient address and amount from the message.
Example request: "can you send 1 move to 0x123..."
Example response:
\`\`\`json
{
"recipient": "0x123...",
"amount": "1"
}
\`\`\`
Rules:
1. The recipient address always starts with "0x"
2. The amount is typically a number less than 100
3. Return exact values found in the message
Recent messages:
{{recentMessages}}
Extract and return ONLY the following in a JSON block:
- recipient: The wallet address starting with 0x
- amount: The number of tokens to send
Return ONLY the JSON block with these two fields.`;

export default {
name: "TRANSFER_MOVE",
similes: [
"SEND_TOKEN",
"TRANSFER_TOKEN",
"TRANSFER_TOKENS",
"SEND_TOKENS",
"SEND_MOVE",
"PAY",
],
triggers: [
"send move",
"send 1 move",
"transfer move",
"send token",
"transfer token",
"can you send",
"please send",
"send"
],
shouldHandle: (message: Memory) => {
const text = message.content?.text?.toLowerCase() || "";
return text.includes("send") && text.includes("move") && text.includes("0x");
},
validate: async (runtime: IAgentRuntime, message: Memory) => {
elizaLogger.debug("Starting transfer validation for user:", message.userId);
elizaLogger.debug("Message text:", message.content?.text);
return true; // Let the handler do the validation
},
priority: 1000, // High priority for transfer actions
description: "Transfer Move tokens from the agent's wallet to another address",
handler: async (
runtime: IAgentRuntime,
message: Memory,
state: State,
_options: { [key: string]: unknown },
callback?: HandlerCallback
): Promise<boolean> => {
elizaLogger.debug("Starting TRANSFER_MOVE handler...");
elizaLogger.debug("Message:", {
text: message.content?.text,
userId: message.userId,
action: message.content?.action
});

try {
const privateKey = runtime.getSetting("MOVEMENT_PRIVATE_KEY");
elizaLogger.debug("Got private key:", privateKey ? "Present" : "Missing");

const network = runtime.getSetting("MOVEMENT_NETWORK");
elizaLogger.debug("Network config:", network);
elizaLogger.debug("Available networks:", Object.keys(MOVEMENT_NETWORK_CONFIG));

const movementAccount = Account.fromPrivateKey({
privateKey: new Ed25519PrivateKey(
PrivateKey.formatPrivateKey(
privateKey,
PrivateKeyVariants.Ed25519
)
),
});
elizaLogger.debug("Created Movement account:", movementAccount.accountAddress.toStringLong());

const aptosClient = new Aptos(
new AptosConfig({
network: Network.CUSTOM,
fullnode: MOVEMENT_NETWORK_CONFIG[network].fullnode
})
);
elizaLogger.debug("Created Aptos client with network:", MOVEMENT_NETWORK_CONFIG[network].fullnode);

const walletInfo = await walletProvider.get(runtime, message, state);
state.walletInfo = walletInfo;

// Initialize or update state
if (!state) {
state = (await runtime.composeState(message)) as State;
} else {
state = await runtime.updateRecentMessageState(state);
}

// Compose transfer context
const transferContext = composeContext({
state,
template: transferTemplate,
});

// Generate transfer content
const content = await generateObjectDeprecated({
runtime,
context: transferContext,
modelClass: ModelClass.SMALL,
});

// Validate transfer content
if (!isTransferContent(content)) {
console.error("Invalid content for TRANSFER_TOKEN action.");
if (callback) {
callback({
text: "Unable to process transfer request. Invalid content provided.",
content: { error: "Invalid transfer content" },
});
}
return false;
}

const adjustedAmount = BigInt(
Number(content.amount) * Math.pow(10, MOVE_DECIMALS)
);
console.log(
`Transferring: ${content.amount} tokens (${adjustedAmount} base units)`
);

const tx = await aptosClient.transaction.build.simple({
sender: movementAccount.accountAddress.toStringLong(),
data: {
function: "0x1::aptos_account::transfer",
typeArguments: [],
functionArguments: [content.recipient, adjustedAmount],
},
});
const committedTransaction =
await aptosClient.signAndSubmitTransaction({
signer: movementAccount,
transaction: tx,
});
const executedTransaction = await aptosClient.waitForTransaction({
transactionHash: committedTransaction.hash,
});

const explorerUrl = `${MOVEMENT_EXPLORER_URL}/${executedTransaction.hash}?network=${MOVEMENT_NETWORK_CONFIG[network].explorerNetwork}`;
elizaLogger.debug("Transfer successful:", {
hash: executedTransaction.hash,
amount: content.amount,
recipient: content.recipient,
explorerUrl
});

if (callback) {
callback({
text: `Successfully transferred ${content.amount} MOVE to ${content.recipient}\nTransaction: ${executedTransaction.hash}\nView on Explorer: ${explorerUrl}`,
content: {
success: true,
hash: executedTransaction.hash,
amount: content.amount,
recipient: content.recipient,
explorerUrl
},
});
}

return true;
} catch (error) {
console.error("Error during token transfer:", error);
if (callback) {
callback({
text: `Error transferring tokens: ${error.message}`,
content: { error: error.message },
});
}
return false;
}
},

examples: [
[
{
user: "{{user1}}",
content: {
text: "can you send 1 move to 0xa07ab7d3739dc793f9d538f7d7163705176ba59f7a8c994a07357a3a7d97d843",
},
},
{
user: "{{user2}}",
content: {
text: "I'll help you transfer 1 Move token...",
action: "TRANSFER_MOVE",
},
},
],
[
{
user: "{{user1}}",
content: {
text: "send 1 move to 0xa07ab7d3739dc793f9d538f7d7163705176ba59f7a8c994a07357a3a7d97d843",
},
},
{
user: "{{user2}}",
content: {
text: "Processing Move token transfer...",
action: "TRANSFER_MOVE",
},
},
]
] as ActionExample[][],
} as Action;
19 changes: 19 additions & 0 deletions packages/plugin-movement/src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export const MOVE_DECIMALS = 8;

export const MOVEMENT_NETWORK_CONFIG = {
mainnet: {
fullnode: 'https://mainnet.movementnetwork.xyz/v1',
chainId: '126',
name: 'Movement Mainnet',
explorerNetwork: 'mainnet'
},
bardock: {
fullnode: 'https://aptos.testnet.bardock.movementlabs.xyz/v1',
chainId: '250',
name: 'Movement Bardock Testnet',
explorerNetwork: 'bardock+testnet'
}
} as const;

export const DEFAULT_NETWORK = 'bardock';
export const MOVEMENT_EXPLORER_URL = 'https://explorer.movementnetwork.xyz/txn';
Loading

0 comments on commit ba0c7fa

Please sign in to comment.