Skip to content

Commit

Permalink
Add Safe plugin with actions configuration for initializing a safe sm…
Browse files Browse the repository at this point in the history
…art account
  • Loading branch information
DarrenZal committed Feb 6, 2025
1 parent 3de0531 commit 36429a3
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 91 deletions.
1 change: 1 addition & 0 deletions agent/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@
"@elizaos/plugin-dkg": "workspace:*",
"@elizaos/plugin-email": "workspace:*",
"@elizaos/plugin-sei": "workspace:*",
"@elizaos/plugin-safe": "workspace:*",
"@elizaos/plugin-omniflix": "workspace:*",
"@elizaos/plugin-suno": "workspace:*",
"@elizaos/plugin-udio": "workspace:*",
Expand Down
23 changes: 23 additions & 0 deletions packages/plugin-safe/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "@elizaos/plugin-safe",
"version": "0.1.0",
"type": "module",
"main": "dist/index.js",
"module": "dist/index.js",
"types": "dist/index.d.ts",
"files": ["dist"],
"dependencies": {
"@elizaos/core": "workspace:*",
"@safe-global/relay-kit": "^1.0.0"
},
"devDependencies": {
"@safe-global/api-kit": "^2.5.8",
"@safe-global/protocol-kit": "5.2.1-alpha.0",
"@safe-global/safe-core-sdk-types": "^5.1.0",
"tsup": "^7.0.0",
"typescript": "^5.0.0"
},
"scripts": {
"build": "tsup --format esm --dts"
}
}
97 changes: 97 additions & 0 deletions packages/plugin-safe/src/actions/createSafeAction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@




// src/actions/createSafeAction.ts
import {
type Action,
type HandlerCallback,
type IAgentRuntime,
type Memory,
type State
} from '@elizaos/core';
import Safe, {
PredictedSafeProps,
SafeAccountConfig,
SafeDeploymentConfig
} from '@safe-global/protocol-kit';

interface ExtendedSafeDeploymentConfig extends SafeDeploymentConfig {
deploymentType?: 'canonical'; // or a union of acceptable values
}

const RPC_URL = 'https://rpc.ankr.com/eth_sepolia';

export const createSafeAction: Action = {
name: "CREATE_SAFE_ACCOUNT",
description: "Creates a new Safe smart account for the agent using the provided signer credentials.",
similes: ["make a new safe smart account", "create a safe wallet", "set up a new safe account"],
examples: [[
{ user: "{{user}}", content: { text: "create a new safe smart account" }}
]],
validate: async () => true,
handler: async (
runtime: IAgentRuntime,
message: Memory,
state: State | undefined,
options?: Record<string, unknown>,
callback?: HandlerCallback
): Promise<boolean> => {
try {
// Retrieve the signer credentials via runtime.getSetting (or process.env)
const signerAddress: string | undefined =
process.env.SIGNER_ADDRESS || runtime.getSetting("SIGNER_ADDRESS");
const signerPrivateKey: string | undefined =
process.env.SIGNER_PRIVATE_KEY || runtime.getSetting("SIGNER_PRIVATE_KEY");

if (!signerAddress || !signerPrivateKey) {
throw new Error("Missing SIGNER_ADDRESS or SIGNER_PRIVATE_KEY secrets.");
}

// Configure the safe account parameters
const safeAccountConfig: SafeAccountConfig = {
owners: [signerAddress],
threshold: 1,
// You can optionally provide additional parameters:
// to: '0x...', data: '0x', fallbackHandler: '0x...', etc.
};

// Optionally, configure deployment parameters
const safeDeploymentConfig: ExtendedSafeDeploymentConfig = {
saltNonce: '123',
safeVersion: '1.4.1',
deploymentType: 'canonical'
};

// Build the predicted safe configuration
const predictedSafe: PredictedSafeProps = {
safeAccountConfig,
safeDeploymentConfig // This property is optional
};

// Initialize the new safe using the predictedSafe configuration
// Note: Remove any 'safeAddress' parameter. Instead, pass 'predictedSafe'.
const protocolKit = await (Safe as any).init({

Check warning on line 74 in packages/plugin-safe/src/actions/createSafeAction.ts

View check run for this annotation

codefactor.io / CodeFactor

packages/plugin-safe/src/actions/createSafeAction.ts#L74

Unexpected any. Specify a different type. (@typescript-eslint/no-explicit-any)
provider: RPC_URL,
signer: signerPrivateKey, // In production, create a proper signer instance (e.g., via ethers.js)
predictedSafe,
isL1SafeSingleton: true,
// Optionally: contractNetworks, etc.
});

// Optionally, get the computed safe address (if the API provides it)
const safeAddress = protocolKit.getAddress ? await protocolKit.getAddress() : "unknown";

const resultMessage = `Safe smart account created successfully. Address: ${safeAddress}`;
callback?.({ text: resultMessage, content: { safeAddress } });
return true;
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
callback?.({ text: `Error creating safe account: ${errorMessage}`, content: { error: errorMessage } });
return false;
}
},
};

export default createSafeAction;

108 changes: 17 additions & 91 deletions packages/plugin-safe/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,91 +1,17 @@
import { Plugin, Runtime} from '@elizaos/core'
import Safe from '@safe-global/protocol-kit'
import SafeApiKit from '@safe-global/api-kit'
import { MetaTransactionData } from '@safe-global/safe-core-sdk-types'

// Import actions
import {
createSafeAction,
deployNewSafeAction,
proposeTransactionAction,
executeTransactionAction,
batchTransactionsAction,
addOwnerAction,
removeOwnerAction,
changeThresholdAction
} from './actions'

// Import providers
import {
safeBalanceProvider,
safeTransactionProvider,
safeOwnerProvider,
safeConfigProvider
} from './providers'

// Import evaluators
import {
transactionEvaluator,
ownershipEvaluator
} from './evaluators'

export class SafePlugin implements Plugin {
name = 'plugin-safe'
runtime: Runtime
safeSDK: Safe
safeApi: SafeApiKit

constructor(runtime: Runtime) {
this.runtime = runtime
this.initializeSafeSDK()
this.initializeApiKit()

// Register components
this.registerActions()
this.registerProviders()
this.registerEvaluators()
}

private async initializeSafeSDK() {
this.safeSDK = await Safe.create({
ethAdapter: this.runtime.ethAdapter,
safeAddress: this.runtime.config.safeAddress
})
}

private initializeApiKit() {
this.safeApi = new SafeApiKit({
txServiceUrl: this.runtime.config.safeApiUrl,
ethAdapter: this.runtime.ethAdapter
})
}

private registerActions() {
return [
createSafeAction,
deployNewSafeAction,
proposeTransactionAction,
executeTransactionAction,
batchTransactionsAction,
addOwnerAction,
removeOwnerAction,
changeThresholdAction
]
}

private registerProviders() {
return [
safeBalanceProvider,
safeTransactionProvider,
safeOwnerProvider,
safeConfigProvider
]
}

private registerEvaluators() {
return [
transactionEvaluator,
ownershipEvaluator
]
}
}
// src/index.ts
import { type Plugin } from '@elizaos/core';
import { createSafeAction } from './actions/createSafeAction';

console.log("Initializing Safe Plugin...");

export const safePlugin: Plugin = {
name: 'Safe Protocol Integration',
description: 'Plugin for integrating Safe protocol wallet functionality',
providers: [],
evaluators: [],
services: [],
actions: [createSafeAction] // add the action here
};

export const pluginSafe = safePlugin;
export default safePlugin;
3 changes: 3 additions & 0 deletions packages/plugin-safe/test-import.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// test-import.mjs
import plugin from './dist/index.js';
console.log("Plugin loaded:", plugin);
8 changes: 8 additions & 0 deletions packages/plugin-safe/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/**/*"]
}
17 changes: 17 additions & 0 deletions packages/plugin-safe/tsup.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { defineConfig} from 'tsup'

export default defineConfig({
entry: ['src/index.ts'],
outDir: 'dist',
sourcemap: true,
clean: true,
format: ['esm'],
dts: true,
external: [
'@elizaos/core',
'@safe-global/protocol-kit',
'@safe-global/api-kit',
'@safe-global/safe-core-sdk-types',
'@safe-global/relay-kit'
]
})

0 comments on commit 36429a3

Please sign in to comment.