Sealed autonomous trading agents on 0G. Every decision is signed inside an Intel TDX TEE, every action is attested on-chain, every operator is slashable.
Built for the 0G APAC Hackathon 2026.
- App: https://pilow-trade.vercel.app
- Code: https://github.com/fozagtx/pilow
- Chain: 0G Galileo Testnet (chain id 16602)
- TEE: Phala Cloud CVM (Intel TDX, dstack)
Autonomous trading agents have a trust problem on both sides of the market.
- Strategy authors cannot share a profitable strategy without leaking it. The moment the code, prompts, or model weights are visible to a renter or hoster, the alpha is gone — there is no way to rent out an agent while keeping the strategy sealed.
- Renters cannot trust an agent's actions. A hosted agent could silently swap the model, alter the prompt, or front-run the user, and on-chain logs alone don't prove which binary actually produced a given trade.
- Protocols have no slashing primitive for misbehavior, because nothing binds an on-chain action to the exact attested binary that produced it.
Pilow fixes this by minting each strategy as a sealed iNFT, running it inside an Intel TDX enclave whose signing key is derived from the image measurement, and recording a hash of the TDX remote-attestation quote on-chain for every tick. Anyone can challenge an action whose quote does not verify against the attested binary, and post a slashable bond. Authors get rentable, sealed strategies; renters get verifiable execution; the protocol gets a working dispute primitive.
| 0G primitive | Used? | Where in Pilow |
|---|---|---|
| 0G Chain | ✅ | Four contracts deployed on Galileo (chain id 16602): StrategyINFT, AgentWalletFactory, RentalAndRevenue, DisputeResolver. solc 0.8.24, evmVersion: "cancun". See Deployed contracts. |
| 0G Compute | ✅ | Sealed inference per tick via provider 0xa48f01287233509FD694a22Bf840225062E67836 running qwen/qwen-2.5-7b-instruct. Settlement via processResponse(providerAddress, chatID, usageData) after every call. Broker reports verified=true. Code: agent/src/inference.ts. |
| 0G Storage | ✅ | Strategy artifacts uploaded on mint; returned storage root hash is written on-chain in StrategyINFT.mintStrategy. Download path re-verifies the merkle root before the agent parses the artifact. Code: agent/src/storage.ts. Proof tx: 0xe14554…d51d0. |
| Agent ID (iNFT) | ✅ | Every strategy is an intelligent NFT (StrategyINFT, ERC-721). Each tokenId is the agent identity and binds 1:1 to a per-strategy AgentWallet deployed by AgentWalletFactory, and to a TEE-derived signer authorized on DisputeResolver. |
| Privacy / Secure Execution | ✅ | Agent runs inside an Intel TDX CVM on Phala Cloud. Signing key is derived from the image measurement via @phala/dstack-sdk — the key never exists outside the enclave. Each tick produces a TDX RA quote whose keccak256 hash is recorded on-chain via DisputeResolver.recordAction. Code: agent/src/tee.ts. |
| Other | ✅ | Slashable challenge market: DisputeResolver accepts a bond (min 0.01 OG) for anyone to challenge a recorded action whose quote hash does not verify against the attested binary. |
Every claim above maps to a transaction or address on Galileo — see the Live end-to-end proof on chain section below for clickable tx hashes covering strategy mint (Storage + Chain), agent wallet deployment, compute ledger funding, sealed inference run, attested tick recorded on DisputeResolver, and TEE agent authorization.
flowchart LR
User[User wallet] -->|mint / rent| FE[Next.js frontend]
FE -->|wagmi v2| Chain[0G Galileo Testnet]
Chain --> SINFT[StrategyINFT]
Chain --> AWF[AgentWalletFactory]
Chain --> RR[RentalAndRevenue]
Chain --> DR[DisputeResolver]
TEE[Agent in Phala CVM<br/>Intel TDX + dstack] -->|recordAction quote hash| DR
TEE -->|inference| Compute[0G Compute provider<br/>qwen-2.5-7b]
Compute -->|processResponse settlement| Chain
sequenceDiagram
participant Agent as Agent (CVM)
participant DStack as dstack SDK
participant Compute as 0G Compute
participant DR as DisputeResolver
Agent->>DStack: derive signing key from image measurement
Agent->>Compute: inference request
Compute-->>Agent: response + chatID
Agent->>Compute: processResponse(provider, chatID, usage)
Agent->>DStack: get TDX RA quote (report_data binds action)
DStack-->>Agent: quote bytes
Agent->>DR: recordAction(keccak256(quote))
Note over DR: anyone can challenge later — only CVM-attested actions are trusted
| Network name | 0G-Galileo-Testnet |
| Chain ID | 16602 |
| RPC URL | https://evmrpc-testnet.0g.ai |
| Block explorer | https://chainscan-galileo.0g.ai |
| Native currency | OG (18 decimals) |
| Faucets | https://faucet.0g.ai · https://cloud.google.com/application/web3/faucet/0g/galileo |
The pipeline below is not a sketch — every line points at a transaction you can click and verify on Galileo.
| What | Tx / address | Result |
|---|---|---|
| Strategy #1 minted (real 0G Storage upload) | 0xe14554…d51d0 |
tokenId=1, storageRoot 0x229b3f9e…0e18e79 |
Per-strategy AgentWallet deployed |
0x731eb3…19413 |
wallet 0xf93B757dbD2C1dc300C948aFAA54fc0cAB667f9c |
First real attested tick — qwen-2.5-7b returned sell, agent hashed attestation, wrote it on chain |
0x85f1851f…4c49d |
block 33329274, ActionRecorded event emitted |
| 0G Compute ledger created (3 OG) | 0x15b16fde…6883c |
inference paid from this ledger |
Sealed inference run, broker confirmed verified=true |
0xf80f6293…becd530 |
model returned SHORT ETH 0.5X | LONG SOL 1.5X |
Phala TEE-derived agent authorized on DisputeResolver |
0xb559b8ad…f065a0 |
CVM agent 0xA2c6ACb4…f986 can now recordAction |
Network: 0G Galileo Testnet (chain id 16602). Pilow is not deployed to a 0G mainnet — at the time of the hackathon submission, 0G is in testnet phase, so all live contracts and proofs below are on Galileo testnet. The same deployment script (npm -w contracts run deploy:testnet) is the path that will be used for mainnet once 0G mainnet is available; only the RPC URL and chain id in contracts/hardhat.config.ts need to change.
Deployer: 0x74CeCe8C927587620FF5171cEd3FA852185252A2
| Contract | Address | Explorer |
|---|---|---|
StrategyINFT |
0x8D1AB23bEee17e58FB437cDcC35c75B89276fc26 |
open |
AgentWalletFactory |
0x4eD99BAf8efB12215b65514D235C8dA637F062a6 |
open |
RentalAndRevenue |
0x01A906558623edfF2ac416256eb832F74f09fd81 |
open |
DisputeResolver |
0x9f73cB87A43deAe721cbf69cfb8a356e2C7275FA |
open |
Deployment manifest: contracts/deployments/0g-testnet.json
StrategyINFT(initialOwner = deployer)
AgentWalletFactory(strategyContract = StrategyINFT)
RentalAndRevenue(
strategies = StrategyINFT,
feeRecipient = deployer,
protocolFeeBps = 1000, // 10% protocol fee
initialOwner = deployer
)
DisputeResolver(
minBond = 0.01 ether, // 0.01 OG minimum dispute bond
initialOwner = deployer,
initialAgent = deployer // bootstrap; rotate to TEE agent address
)
| Provider address | 0xa48f01287233509FD694a22Bf840225062E67836 |
| Service type | chatbot |
| Model | qwen/qwen-2.5-7b-instruct |
| Minimum ledger balance | 3 OG |
| Settlement | processResponse(providerAddress, chatID, usageData) after each inference |
The /app/providers page surfaces this provider after filtering listService() tuples down to teeVerified=true:
- Compiler:
solc 0.8.24 - Optimizer: enabled, 200 runs
evmVersion: "cancun"(required for 0G Chain). Seecontracts/hardhat.config.ts.
Next.js 16, App Router, Tailwind v4. Wallet via ConnectKit + wagmi v2 on chain 16602.
- Local:
npm run frontend:dev→ http://localhost:3000 - Wallet-gated:
/app,/app/agents/new,/app/account - Open:
/app/providers,/app/market
Contract wiring:
| Surface | Reads | Writes |
|---|---|---|
| Dashboard | balanceOf, tokenOfOwnerByIndex, strategies |
— |
| Mint | — | mintStrategy → createWallet |
| Market | — | rent (native value) |
| Agent detail | — | setActive, challenge |
- Node.js
>= 22 - Docker (only required to deploy the agent to a Phala CVM)
- A funded 0G Galileo testnet key — fund at https://faucet.0g.ai
- Phala Cloud account +
phalaCLI (only required for the TEE deployment step)
git clone https://github.com/fozagtx/pilow.git && cd pilow
npm install # installs workspaces: contracts, agent, frontend
cp .env.example .env # fill in PRIVATE_KEY=0x... and any RPC overridesnpm -w contracts run compile
npm -w contracts run deploy:testnet
# writes addresses to contracts/deployments/0g-testnet.jsonnpm -w agent run list-providers # discover live providers
# edit .env: set PROVIDER_ADDRESS=0x... (use the listed qwen-2.5-7b provider)
npm -w agent run setup-ledger 3 # create compute ledger w/ 3 OG
npm -w agent run smoke-inference # end-to-end sealed inference (no TEE yet)npm run frontend:dev # http://localhost:3000Wallet-gated routes: /app, /app/agents/new, /app/account. Open routes: /app/providers, /app/market.
npm i -g phala
phala login
phala deploy -c docker-compose.yml -n pilow-agent --wait
# Grab the TEE-derived agent address from CVM logs
phala logs pilow-agent | grep "Address :"
# Authorize that TEE address on DisputeResolver (from deployer wallet, idempotent)
AGENT=0xTEE_ADDR npm -w contracts run authorize-agentnode scripts/smoke-test.mjsSee LOCAL_TESTING.md for the full test plan and BUILD.md for build-system notes.
The agent ships to a Phala Cloud CVM so the signing key is derived inside the enclave from the image measurement (no key in any env var), and each tick produces a TDX RA quote whose hash is recorded via DisputeResolver.recordAction(...).
Files:
| File | Role |
|---|---|
agent/Dockerfile |
Image, node:22-slim base |
agent/src/tee.ts |
@phala/dstack-sdk wrapper with local dev fallback |
docker-compose.yml |
What the Phala CLI deploys |
.dockerignore |
Excludes .env, caches, node_modules |
Deploy:
# 0. Install Phala CLI (one-time, global)
npm i -g phala
# 1. Authenticate
phala login
# 2. Build + deploy the CVM
phala deploy -c docker-compose.yml -n pilow-agent --wait
# 3. Get the TEE-derived agent address from CVM logs
phala logs pilow-agent | grep "Address :"
# prints: Address : 0x... (different from your deployer wallet)
# 4. Authorize that TEE address on DisputeResolver (from deployer wallet, idempotent)
AGENT=0xTEE_ADDR npm -w contracts run authorize-agentnpm -w agent run report works in both modes — the local script falls back to the .env wallet when dstack is unavailable.

