Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
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
837 changes: 474 additions & 363 deletions Cargo.lock

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ wasi = "0.14.2"
wavs-wasi-utils = "=1.2.0"

# WAVS (https://github.com/Lay3rLabs/wavs-tools/pull/123)
wavs-llm = { git = "https://github.com/Lay3rLabs/wavs-tools", rev = "cd1c4271deb7686a7d995b5b41bc226d8185df6e", package = "wavs-llm"}
wavs-eas = { git = "https://github.com/Lay3rLabs/wavs-tools", rev = "cd1c4271deb7686a7d995b5b41bc226d8185df6e", package = "wavs-eas" }
wavs-indexer-api = { git = "https://github.com/Lay3rLabs/wavs-tools", rev = "cd1c4271deb7686a7d995b5b41bc226d8185df6e", package = "wavs-indexer-api" }
wavs-merkle-sources = { git = "https://github.com/Lay3rLabs/wavs-tools", rev = "cd1c4271deb7686a7d995b5b41bc226d8185df6e", package = "wavs-merkle-sources" }
wavs-ipfs = { git = "https://github.com/Lay3rLabs/wavs-tools", rev = "cd1c4271deb7686a7d995b5b41bc226d8185df6e", package = "wavs-ipfs"}
wavs-llm = { git = "https://github.com/Lay3rLabs/wavs-tools", rev = "5cba6bb758a6c64bbae4b58cbf22ab5f91ed2404", package = "wavs-llm"}
wavs-eas = { git = "https://github.com/Lay3rLabs/wavs-tools", rev = "5cba6bb758a6c64bbae4b58cbf22ab5f91ed2404", package = "wavs-eas" }
wavs-indexer-api = { git = "https://github.com/Lay3rLabs/wavs-tools", rev = "5cba6bb758a6c64bbae4b58cbf22ab5f91ed2404", package = "wavs-indexer-api" }
wavs-merkle-sources = { git = "https://github.com/Lay3rLabs/wavs-tools", rev = "5cba6bb758a6c64bbae4b58cbf22ab5f91ed2404", package = "wavs-merkle-sources" }
wavs-ipfs = { git = "https://github.com/Lay3rLabs/wavs-tools", rev = "5cba6bb758a6c64bbae4b58cbf22ab5f91ed2404", package = "wavs-ipfs"}

# Local packages
wavs-merkler = { path = "packages/wavs-merkler" }
Expand Down
45 changes: 4 additions & 41 deletions PLAN.md
Original file line number Diff line number Diff line change
@@ -1,52 +1,15 @@
# The Plan

Figma: https://www.figma.com/proto/uGHgh87RIFS0GUlLR68hCs/TrustGraph-Wireframes?node-id=20-134
Copy: https://www.notion.so/opencivics/TrustGraph-Copy-28606d2570f2805a8f08dfa3e64c559e?source=copy_link

TODO: explore configuration...

- Network overview on network page
- Add copy, new landing page
- Make network info config with copy

- Contact support button
- update site metadata
- need a graph visualization

Needs discussion:
- Calibrate math so scores are right? (open questions about this)

Potential Bugs (need testing):
- Don't allow self-attestations, these shouldn't account
- Handle multiple attestations from the same account to the same account
- Set max 100 on confidence level

Test:
- ENS support

# Deploying
- Deploy somewhere so people can try
- Clean git history
- Open Source
- Deploy on Celo
- Publish WAVS packages


# Clean up
- formatVotingPower is baddly named (kill, it's just using BigInt, there must be a function in one of our packages)
- Remove followers logic from ponder indexer
- Rename component from merkler to trust graph
- Documentation for merkler component
- Refactor to consume upstream packages from WAVS tools
- Docs so people unfamiliar with WAVS can run it
- Make sure tasks are named appropriately
- Rename dao-agent -> actor
- Fix deployment
- Trigger actor based on cron

# Governance extra credit
- A DAO needs to be able to update it's own service configuration (related to Gyser?)
- Experimental notice on governance page
- create proposal doesn't submit amount as big int (it's in wei)
- Add threshold to Merkle Gov Module contract
- Implement and document the fallback mechanism for governance (this should be fairly straightforward with Zodiac hopefully)
- A DAO needs to be able to update it's own service configuration (related to Gyser?)
- Conduct AI audit of contracts
- Add Gov Paper

Expand Down
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,26 @@ task forge:claim-rewards

task forge:query-rewards-balance
```


### LLM Attester Demo

Trigger LLM attester:
```bash
task eas:trigger \
TRIGGER_ADDRESS="$(task config:eas-attest-trigger-addr)" \
SCHEMA_UID="$(task config:statement-schema-id)" \
RECIPIENT="$(task config:wallet-address)" \
MESSAGE="Your statement message here"
```

Query LLM attester attestations:
```bash
task eas:query \
INDEXER_ADDRESS="$(task config:indexer-address)" \
EAS_ADDRESS="$(task config:eas-addr)" \
SCHEMA_UID="$(task config:like-schema-id)" \
RECIPIENT="$(task config:wallet-address)"
```

### Agent Demo
42 changes: 42 additions & 0 deletions components/actor/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
[package]
name = "dao-agent"
edition.workspace = true
version.workspace = true
authors.workspace = true
rust-version.workspace = true
repository.workspace = true

[dependencies]
wavs-llm = { workspace = true }
wavs-wasi-utils = { workspace = true }
wstd = { workspace = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
anyhow = { workspace = true }
wit-bindgen-rt = { workspace = true, features = ["bitflags"] }
alloy-sol-types = { workspace = true }
alloy-primitives = { workspace = true }
alloy-json-abi = { workspace = true }
alloy-dyn-abi = { workspace = true }
alloy-network = { workspace = true }
alloy-provider = { workspace = true }
alloy-rpc-types = { workspace = true }
hex = { workspace = true }
tiny-keccak = { workspace = true }

[dev-dependencies]
mockall = { workspace = true }

[lib]
crate-type = ["cdylib"]

[profile.release]
codegen-units = 1
opt-level = "s"
debug = false
strip = true
lto = true

[package.metadata.component]
package = "component:dao-agent"
target = "wavs:operator@=1.3.0"
9 changes: 9 additions & 0 deletions components/actor/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
OUTPUT_DIR?=../../compiled


## wasi-build: building the WAVS wasi component(s)
wasi-build:
@cargo component build --release; cargo fmt
@mkdir -p $(OUTPUT_DIR)
@cp ../../target/wasm32-wasip1/release/*.wasm $(OUTPUT_DIR)
.PHONY: wasi-build
171 changes: 171 additions & 0 deletions components/actor/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
# DAO Agent Component

A WASI-based agent that controls a Gnosis Safe Module. This component uses an LLM to make financial decisions and execute transactions on behalf of a DAO.

## Overview

The DAO Agent acts as an AI-powered financial controller for a Gnosis Safe wallet. It can:

- Process natural language instructions about financial transactions
- Send ETH to allowlisted addresses
- Transfer ERC20 tokens (e.g., USDC) to allowlisted addresses
- Interact with smart contracts
- Validate transactions based on security rules

## Configuration

The DAO Agent can be configured via a JSON configuration file, which can be loaded from:

- HTTP/HTTPS URLs
- IPFS URLs (using the format `ipfs://HASH`)

The configuration can be passed via the `config_uri` key-value pair when deploying the service:

```bash
SERVICE_CONFIG='{"fuel_limit":100000000,"max_gas":5000000,"host_envs":["WAVS_ENV_OPENAI_API_KEY", "WAVS_ENV_OPENAI_API_URL", "WAVS_ENV_IPFS_GATEWAY_URL", "WAVS_ENV_OLLAMA_API_URL"],"kv":[["config_uri", "ipfs://bafkreigflglas3bfv2qe5dik3lwag5lyuotwzbp5p6fw5cd73ibr5qczc4"]],"workflow_id":"default","component_id":"default"}'
```

If no configuration is provided, the component will use the default settings defined in `context.rs`.

### Configuration Format

The configuration file should follow this structure:

```json
{
"account_address": "0x47937d0d01b7d71201ca10138ebc14d22618ebce",
"allowlisted_addresses": ["0xDf3679681B87fAE75CE185e4f01d98b64Ddb64a3"],
"supported_tokens": [
{
"address": "0x0000000000000000000000000000000000000000",
"symbol": "ETH",
"decimals": 18,
"description": "Native Ethereum token"
},
{
"address": "0xb7278a61aa25c888815afc32ad3cc52ff24fe575",
"symbol": "USDC",
"decimals": 6,
"description": "USD Coin - a stablecoin pegged to the US Dollar"
}
],
"llm_context": {
"model": "llama3.2",
"llm_config": {
"temperature": 0.0,
"top_p": 1.0,
"seed": 42,
"max_tokens": 500,
"context_window": 4096
},
"messages": [
{
"role": "system",
"content": "You are a DAO agent responsible for making and executing financial decisions through a Gnosis Safe Module..."
}
],
"contracts": [
{
"name": "USDC",
"address": "0xb7278a61aa25c888815afc32ad3cc52ff24fe575",
"abi": "[{\"type\":\"function\",\"name\":\"transfer\",\"inputs\":[{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"value\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"nonpayable\"}]",
"description": "USDC is a stablecoin pegged to the US Dollar"
}
],
"config": []
}
}
```

See `agent-config.example.json` for a full example.

## Environment Variables

The DAO Agent requires the following environment variables:

- `WAVS_ENV_OPENAI_API_KEY`: OpenAI API key for LLM access
- `WAVS_ENV_OPENAI_API_URL`: OpenAI API endpoint (default: "https://api.openai.com/v1/chat/completions")
- `WAVS_ENV_IPFS_GATEWAY_URL`: IPFS gateway URL for loading configurations (default: "https://gateway.lighthouse.storage")
- `WAVS_ENV_OLLAMA_API_URL`: Ollama Server API endpoint (default: "http://localhost:localhost:11434")

## Building and Running

### Build the Component

```bash
cd components/dao-agent
cargo component build --release
```

Or use the project-level build command:

```bash
make wasi-build
```

### Run Locally

You can test the DAO Agent locally with:

```bash
COMPONENT_FILENAME="dao_agent.wasm" PROMPT='We should donate 1 ETH to 0xDf3679681B87fAE75CE185e4f01d98b64Ddb64a3.' SERVICE_CONFIG='{"fuel_limit":100000000,"max_gas":5000000,"host_envs":["WAVS_ENV_OPENAI_API_KEY", "WAVS_ENV_OPENAI_API_URL", "WAVS_ENV_IPFS_GATEWAY_URL", "WAVS_ENV_OLLAMA_API_URL"],"kv":[["config_uri", "ipfs://bafkreigflglas3bfv2qe5dik3lwag5lyuotwzbp5p6fw5cd73ibr5qczc4"]],"workflow_id":"default","component_id":"default"}' make wasi-exec
```

## Security Considerations

The DAO Agent includes several security measures:

1. **Allowlisted Addresses**: Only addresses in the allowlist can receive funds
2. **Supported Tokens**: Only explicitly supported tokens can be transferred
3. **Token Amount Limits**: Transfers are limited to prevent large, unauthorized moves
4. **Decimal Handling**: Careful handling of token decimals to avoid mistakes
5. **Balance Checks**: Transactions that would spend more than the current balance are rejected
6. **Suspicious Request Detection**: The agent is programmed to reject unclear or suspicious requests

## Technical Implementation

### Dynamic Balance Fetching

The agent can query current token balances on-chain to verify transactions:

```rust
// Query all supported token balances
let balances = context.query_all_token_balances()?;
```

### Smart Contract Interactions

The agent can interact with smart contracts using their ABIs:

```rust
// Execute a USDC transfer
let transfer_call = ... // Create transfer call from ABI
let transaction = ... // Build transaction
let result = provider.send_transaction(transaction).await?;
```

### Token Decimal Handling

The agent automatically handles token decimal conversion:

- ETH: 18 decimals (1 ETH = 10^18 wei)
- USDC: 6 decimals (1 USDC = 10^6 base units)

All human-readable amounts are converted to the correct base units before transactions are executed.

## Extending the Agent

To add support for new tokens or contracts:

1. Add the token to the `supported_tokens` array in your configuration
2. Add the contract ABI to the `contracts` array
3. Update the system prompt to include instructions for the new token/contract

## Limitations

This is a demonstration agent and has several limitations:

- Limited to pre-defined token types
- No complex DeFi operations
- No governance capabilities
- Simple security rules
Loading
Loading