App allowing users to execute real-time strategies with agents, while still retaining max security
People have crypto sitting on their Ledger doing nothing. We let them deploy AI agents that autonomously manage that money, trading on price movements, rebalancing LP positions, reacting to news and real time data, while the Ledger device remains the ultimate security gate for large transactions.
Problem Cold wallets, which Ledger devices fall under, account for approximately 22% of total wallet usage, where hot wallets account for the remainder. It's clear that hot wallets have cold wallets beat on usage. However an argument can be made that assets stored on cold wallets are, on average, larger amounts. We can conclude that globally a large portion of dormant, inactive money is sitting on physical Ledger devices. These assets are offline by design to maximize security. This design feature, while being highly secure, does come with its unique drawbacks. In case of a black or white swan event, where one may want to move, sell, or add to their portfolio, this is only possible if said person has the physical hardware wallet on them. Another big issue is that inactive assets sitting inside hardware wallets are subject to long term effects of the global economy, things like inflation. We have solved both of these issues while keeping the hardware wallet secure, letting it react to market events and execute DeFi strategies to counteract things like inflation. We do this through AI agents with restricted, policy-bound access to your wallet, running strategies based on live price feeds, Twitter sentiment, or Polymarket data.
Our Solution A user connects their Ledger to our platform by signing a smart contract. This contract is extremely restrictive and only permits specific whitelisted actions like swaps, with hard security measures baked in at the contract level. Even if a malicious actor somehow got access to our platform, the wallet remains safe. Once connected, the user can start deploying agents that execute strategies using their funds, always within the boundaries they have defined.
Agents An agent is created in 3 steps. First you give it a name, description and image. Then comes the policy, which is the first and most critical security layer. Agents without constraints are unpredictable, and an agent with open access to your funds off of a single misinterpretation could mean real disaster. The policy applies hard constraints to prevent this. You select which smart contracts the agent can interact with, Uniswap for example and nothing else. You choose which assets it can trade, preventing it from buying into worthless coins. You set minimum and maximum trade sizes, protecting against edge cases like ETH spiking to $100,000 for a single second. You set a maximum number of transactions per 24 hours to prevent any bad actor from spamming and draining funds, and a hard cap per single trade on top of that.
Once the policy is set, the user chooses a strategy. Three options currently: live price feed for technical trading, Polymarket data for positioning around major political and world events, and Twitter feed for sentiment driven plays. The user picks one, then describes in plain English what they want the agent to do, and it runs it continuously, without emotion, reacting to everything all the time.
Security The agent never holds your keys. Every single trade is validated against the on-chain contract before it can execute. Anything outside the policy is rejected unconditionally, not by software judgment, not by the agent, but mathematically at the contract level. Even in a worst case scenario where our servers are hacked, our database is leaked, and the agent's private key is fully exposed, it is cryptographically impossible to steal your funds. The worst outcome is a handful of bad trades within your own policy limits. The upside is an agent running advanced strategies 24/7 with access to your full capital.
Product All of this is managed through a single webapp. You can deploy agents, monitor performance, inspect full trade history and statistics, and review any out of policy escalations. Every sensitive action, deploying a new agent or updating a policy, requires a physical hardware signature from your Ledger. The interface is straightforward and the security underneath does not compromise.
Here's the deep technical overview updated to reflect the actual code:
Technical Architecture Overview
This namespacing prevents collisions across users while keeping names human-readable. ENS Record Schema Records are stored as text key-value pairs on the subname: owner → "0xUserWalletAddress" strategy → "Buy ETH when the BTC resolution market on Polymarket exceeds 0.75..." policy → JSON blob (see below) record_sig → EIP-712 signature over the record payload (integrity check) contract_address → deployed LeAgentExecutor address description → optional human-readable agent description avatar → optional image URI The policy field is a JSON-serialized struct controlling all on-chain enforcement parameters: json{ "tokens": ["0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", "0xC02aaa..."], "contracts": ["0xE592427A0AEce92De3Edee1F18E0157C05861564"], "rate_limit_24h": 10, "value_limit_24h": 5000 } Record Integrity Every create/update requires a record_sig: an EIP-712 signature over the record payload, signed by the owner's wallet. The backend verifies this before writing to Namespace: pythonpayload = build_record_payload(name, strategy, policy, description, image_uri) verify_record_sig(payload, body.record_sig, user) # ecrecover must match user This means ENS records cannot be forged or tampered with by the backend — the user's wallet is the authority for content integrity, even though Namespace holds the offchain storage. Agent Wallet Derivation Each agent has a deterministically derived hot wallet, keyed from the ENS name: pythonwallet = derive_wallet(ens_name) This wallet is stored as the ETH address record on the subname (coin type 60), and is registered in LeAgentExecutor as the agent address. Derivation is deterministic — the agent wallet can be reconstructed from the ENS name alone, no database lookup needed.
await create_agent_subname(owner=user, agent_name=body.name, data=..., record_sig=...)
start_runner(ens_name) Ownership enforcement is consistent across all mutating operations: pythonasync def _get_owned(ens_name: str, user: str) -> dict: agent = await get_subname(ens_name) if agent["owner"] != user.lower(): raise HTTPException(status_code=403) The backend never trusts a caller-supplied owner field — it resolves the ENS record and compares. Runner Lifecycle start_runner(ens_name) / stop_runner(ens_name) manage a process/task registry keyed by ENS name. The runner is stateless — on start it re-resolves the ENS name to get current policy and strategy. This means a policy update (PATCH /agents/{name}) takes effect on the next runner cycle without restart.
triggerActive — Polymarket condition must be met whitelistedTokens[tokenIn] — token must be in policy whitelistedTargets[swapTarget] — router must be in policy amountIn <= maxValuePerTrade — per-trade size cap Rolling 24h window check — _tradesThisWindow < maxTradesPerDay
Only after all five checks pass: solidityIERC20(tokenIn).transferFrom(owner, address(this), amountIn); IERC20(tokenIn).approve(swapTarget, amountIn); (bool ok,) = swapTarget.call{value: swapValue}(swapData); if (!ok) revert SwapFailed(); The swap calldata originates from the Uniswap Trading API, requested with:
swapper = address(this) — contract is the token spender recipient = owner — output tokens go directly to user, never touch the contract balance
The agent wallet only pays gas. It never holds tokens, never receives tokens, and has no approval relationship with any ERC-20. Rate Limit Implementation solidityif (block.timestamp >= _windowStart + 1 days) { _windowStart = block.timestamp; _tradesThisWindow = 0; } if (_tradesThisWindow >= maxTradesPerDay) revert RateLimitExceeded(...); _tradesThisWindow++; Rolling window resets on the first trade after 24 hours have elapsed since the window opened, not on a fixed calendar boundary. This is simpler and cheaper than a circular buffer but means a burst of trades at window boundary is technically possible — acceptable for the current use case.
Step 2: for each market_id in policy.polymarket_markets: GET https://clob.polymarket.com/markets/{market_id} → extract yes_price
Step 3: evaluate trigger condition (e.g. yes_price > 0.70)
Step 4: call LeAgentExecutor.updatePolicy(..., triggerActive=result, ...) The CRE workflow URL is static: it always points to {agent-ens-name}/policy. The ENS record it resolves is mutable. The ENS record is the moving part; the workflow is not. One CRE workflow deployment handles all future policy configuration changes. Trust Chain for Polymarket Data Polymarket CLOB API ↓ (fetched by CRE off-chain) Chainlink DON (threshold-signed attestation) ↓ (written on-chain via onlyCRE) LeAgentExecutor.triggerActive ↓ (checked in executeSwap) Swap either proceeds or reverts At no point does the agent's LLM runtime have any ability to set or influence triggerActive. The agent may observe the same Polymarket data and factor it into its reasoning, but the on-chain gate is set exclusively by the CRE DON. Even if the agent is fully compromised and instructed to trade against its policy, it cannot override this.
Security Model — Threat Matrix ThreatMechanismMitigationAgent key compromiseAttacker steals hot wallet keyKey can only call executeSwap() — all five policy checks still apply; nothing outside whitelist executesPrompt injectionMalicious token name/data poisons LLM, outputs bad swapTargetwhitelistedTargets check reverts unconditionally; LLM output is never directly executedHallucinated contractLLM outputs wrong tokenIn/swapTargetToken and target whitelists in contract; non-whitelisted address revertsOracle manipulationFake Polymarket data fed to agentAgent reads oracle from on-chain DON-attested triggerActive; cannot be set by agentENS record poisoningAttacker modifies policy recordsrecord_sig is EIP-712 over content, verified against owner before every write; backend cannot forgeBackend breachServer compromised, attacker updates ENSStill requires valid record_sig from owner wallet; no key stored server-sideOver-allowance drainAgent calls token contract directlyAgent wallet has no approval relationship with ERC-20s; only LeAgentExecutor doesRate limit bypassAgent submits many transactions quicklyOn-chain counter in contract storage; agent cannot manipulate itPolicy driftStale whitelist after updateCRE fully clears and rewrites both whitelist arrays on every updatePolicy() callCross-user agent impersonationAgent uses another user's contractonlyAgent checks derived wallet against registered address; wallets are per-ENS-name
Full Data Flow User Wallet │ ├─ ERC-20.approve(LeAgentExecutor, amount) ────────────► Token Contract │ ├─ POST /agents {strategy, policy, record_sig} ────────► FastAPI Backend │ │ │ │ │ verify_record_sig() │ │ │ │ │ Namespace API (gasless) │ │ │ │ │ ENS Subname Created │ │ "abcdef-name.leagent.eth" │ │ texts: strategy, policy, │ │ record_sig, wallet │ │ │ │ └─ start_runner(ens_name) ───────────────► Agent Runner Process │ │ │ resolves ENS on start │ polls market data │ calls LLM with strategy │ builds TradeIntent │ │ │ ┌────────────────────────┘ │ ▼ │ LeAgentExecutor.executeSwap() │ │ │ ┌───────────────┼───────────────────┐ │ ▼ ▼ ▼ │ triggerActive? token/target rate limit │ (set by CRE DON) whitelisted? not exceeded? │ │ │ │ │ └───────────────┴───────────────────┘ │ │ all pass │ ▼ │ transferFrom(owner → contract) │ approve(swapTarget, amount) │ swapTarget.call(swapData) │ │ │ ▼ │ tokenOut → owner directly │ └─ (parallel) CRE Workflow (static URL → ENS → Polymarket) │ ├─ fetch {ens-name}/policy → get polymarket market IDs ├─ fetch Polymarket CLOB API for each market ID ├─ evaluate trigger condition └─ LeAgentExecutor.updatePolicy(tokens, targets, triggerActive, ...) (onlyCRE enforced) Every trust boundary crossing terminates at a cryptographic check: record_sig for ENS writes, onlyCRE for policy updates, onlyAgent for swap execution, and the five-step policy validation inside executeSwap. The agent runtime is in the untrusted zone throughout — its outputs are proposals that the contract either accepts or reverts.

