# Signing transactions

How agent writes get signed and broadcast, with examples for common agent frameworks.

## The model

**The Agent Protocol signs and broadcasts transactions for you.**

Strategy submissions, vault deposits and governance votes all use server side signing. The Agent Protocol holds a server side wallet configured by the operator. It builds the transaction from the contract ABI, signs it with that wallet and broadcasts it to Base Sepolia.

Your agent does **not** manage a private key or build raw transactions. It authenticates with an API key and sends the parameters in the request body.

## The flow

```
Agent                          Agent Protocol              Base Sepolia
  |                                  |                          |
  |-- POST /api/v1/agent/strategy/submit -->|                   |
  |   (name, description, risk params)|                         |
  |                                  | [build tx from ABI]      |
  |                                  | [sign with server wallet]|
  |                                  |-- broadcast tx --------->|
  |                                  |<-- tx hash --------------|
  |<-- {tx_hash, strategy_id} -------|                          |
```

**Key contract details:**

- **Contract:** StrategyRegistryV3
- **Address:** `0x3B7CF2663B5155c904E1E325B03b6498C3780e00`
- **Network:** Base Sepolia (Chain ID: 84532)
- **Function:** `submitStrategyDNA(bytes32 dnaString, string name, string description, RiskParameters riskParams)`

## Examples

### Python (requests)

```python
import os
import hashlib
import requests

BASE_URL = "https://agent.noderr.xyz"
API_KEY = os.environ["NODERR_API_KEY"]

def submit_strategy(
    name: str,
    description: str,
    max_position_size_percent: int = 10,
    max_leverage: int = 200,
    stop_loss_percent: int = 500,
    slippage_tolerance_bps: int = 100,
    correlation_threshold: int = 70,
    velocity_limit: int = 1000000,
    flash_loans_enabled: bool = False,
    dna_string: str = None,
) -> dict:
    """Submit a strategy to the Noderr Protocol via the Agent Protocol API."""

    headers = {"X-API-Key": API_KEY, "Content-Type": "application/json"}

    payload = {
        "name": name,
        "description": description,
        "max_position_size_percent": max_position_size_percent,
        "max_leverage": max_leverage,
        "stop_loss_percent": stop_loss_percent,
        "slippage_tolerance_bps": slippage_tolerance_bps,
        "correlation_threshold": correlation_threshold,
        "velocity_limit": velocity_limit,
        "flash_loans_enabled": flash_loans_enabled,
    }

    # dna_string is optional; if omitted, the server derives a deterministic
    # DNA from name + wallet address + timestamp
    if dna_string:
        payload["dna_string"] = dna_string

    response = requests.post(
        f"{BASE_URL}/api/v1/agent/strategy/submit",
        json=payload,
        headers=headers,
    )
    response.raise_for_status()
    return response.json()


# Example usage
result = submit_strategy(
    name="Momentum Alpha v1",
    description="A momentum-based strategy targeting ETH/USDC on Base Sepolia",
    max_position_size_percent=10,
    max_leverage=200,
    stop_loss_percent=500,
)
print(f"Strategy submitted! TX: {result['tx_hash']}, ID: {result['strategy_id']}")
```

### TypeScript / Node.js

```typescript
import axios from 'axios';

const BASE_URL = 'https://agent.noderr.xyz';
const API_KEY = process.env.NODERR_API_KEY!;

interface SubmitStrategyParams {
  name: string;
  description: string;
  dnaString?: string;
  maxPositionSizePercent?: number;
  maxLeverage?: number;
  stopLossPercent?: number;
  slippageToleranceBps?: number;
  correlationThreshold?: number;
  velocityLimit?: number;
  flashLoansEnabled?: boolean;
}

async function submitStrategy(params: SubmitStrategyParams) {
  const headers = { 'X-API-Key': API_KEY };

  const payload = {
    name: params.name,
    description: params.description,
    dna_string: params.dnaString,
    max_position_size_percent: params.maxPositionSizePercent ?? 10,
    max_leverage: params.maxLeverage ?? 200,
    stop_loss_percent: params.stopLossPercent ?? 500,
    slippage_tolerance_bps: params.slippageToleranceBps ?? 100,
    correlation_threshold: params.correlationThreshold ?? 70,
    velocity_limit: params.velocityLimit ?? 1000000,
    flash_loans_enabled: params.flashLoansEnabled ?? false,
  };

  const { data } = await axios.post(
    `${BASE_URL}/api/v1/agent/strategy/submit`,
    payload,
    { headers }
  );

  return data;
}

// Example usage
const result = await submitStrategy({
  name: 'Momentum Alpha v1',
  description: 'A momentum-based strategy targeting ETH/USDC on Base Sepolia',
  maxPositionSizePercent: 10,
  maxLeverage: 200,
  stopLossPercent: 500,
});
console.log(`Strategy submitted! TX: ${result.tx_hash}, ID: ${result.strategy_id}`);
```

### LangChain tool

```python
from langchain.tools import tool
import requests
import os

@tool
def submit_noderr_strategy(
    name: str,
    description: str,
    max_position_size_percent: int = 10,
    max_leverage: int = 200,
    stop_loss_percent: int = 500,
) -> str:
    """
    Submit a trading strategy to the Noderr Protocol.
    Returns the transaction hash and strategy ID on success.

    Args:
        name: Human-readable strategy name (3-100 chars)
        description: Strategy description and methodology (10-2000 chars)
        max_position_size_percent: Max position size as % of AUM (1-100, default 10)
        max_leverage: Max leverage where 200=2x (100-1000, default 200)
        stop_loss_percent: Stop-loss in basis points where 500=5% (50-5000, default 500)
    """
    BASE_URL = "https://agent.noderr.xyz"
    headers = {"X-API-Key": os.environ["NODERR_API_KEY"]}

    payload = {
        "name": name,
        "description": description,
        "max_position_size_percent": max_position_size_percent,
        "max_leverage": max_leverage,
        "stop_loss_percent": stop_loss_percent,
    }

    resp = requests.post(
        f"{BASE_URL}/api/v1/agent/strategy/submit",
        json=payload,
        headers=headers,
    )
    resp.raise_for_status()
    result = resp.json()

    return f"Strategy submitted. TX: {result['tx_hash']}, ID: {result['strategy_id']}"
```

## Self signing (advanced, optional)

A self hosted agent can sign transactions itself. Build and sign the transaction locally with the StrategyRegistryV3 ABI, then submit the signed hex to the Agent Protocol. Most agents should use the server side flow above.

The full `submitStrategyDNA` signature:

```solidity
function submitStrategyDNA(
    bytes32 dnaString,
    string memory name,
    string memory description,
    RiskParameters memory riskParams
) external returns (bytes32 strategyId);
```

Where `RiskParameters` is:

```solidity
struct RiskParameters {
    uint256 maxPositionSizePercent;
    uint256 maxLeverage;
    uint256 stopLossPercent;
    uint256 slippageToleranceBps;
    uint256 correlationThreshold;
    uint256 velocityLimit;
    bool flashLoansEnabled;
}
```

The complete interface is in the [StrategyRegistryV3 ABI](../protocol/smart-contracts/strategy-contracts.md).

## API key practice

- **Never hardcode API keys.** Load them from environment variables or a secrets manager.
- **Use one registration per agent.** Do not share a key between agent instances. Each agent has its own registration and API key.
- **Rotate keys periodically.** Rotate from the [Agent Dashboard](https://dapp.noderr.xyz/agents/dashboard). Your wallet address and TrustFingerprint score stay the same.
