Skip to content
Merged
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
53 changes: 53 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
version: 2

updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
commit-message:
prefix: "ci"
groups:
actions:
patterns: ["*"]

- package-ecosystem: npm
directory: /
schedule:
interval: weekly
commit-message:
prefix: "chore"
prefix-development: "chore"
groups:
release-tooling:
patterns: ["semantic-release", "@semantic-release/*"]

- package-ecosystem: npm
directory: /frontend
schedule:
interval: weekly
commit-message:
prefix: "chore"
groups:
# Next/React move together; a split bump usually fails to build.
next:
patterns: ["next", "react", "react-dom", "eslint-config-next"]
viem:
patterns: ["viem", "wagmi", "@wagmi/*"]

- package-ecosystem: npm
directory: /keeper
schedule:
interval: weekly
commit-message:
prefix: "chore"

- package-ecosystem: gomod
directory: /extension
schedule:
interval: weekly
commit-message:
prefix: "chore"
groups:
go-deps:
patterns: ["*"]
39 changes: 39 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: CI

on:
push:
branches: [main]
pull_request:

permissions:
contents: read

jobs:
contracts:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
Comment on lines +15 to +17

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Disable persisted checkout credentials.

Both checkout steps leave the read-scoped GitHub token in local Git configuration for later steps. Set persist-credentials: false on both actions.

Proposed fix
       - uses: actions/checkout@v4
         with:
           submodules: recursive
+          persist-credentials: false
@@
-      - uses: actions/checkout@v4
+      - uses: actions/checkout@v4
+        with:
+          persist-credentials: false

Also applies to: 29-29

🧰 Tools
🪛 zizmor (1.29.0)

[warning] 15-17: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci.yml around lines 15 - 17, Update both
actions/checkout@v4 steps in the workflow to set persist-credentials to false
alongside the existing checkout options, ensuring neither checkout retains the
GitHub token in local Git configuration.

Source: Linters/SAST tools

- uses: foundry-rs/foundry-toolchain@v1
- name: Build
run: forge build
working-directory: contracts
- name: Test
run: forge test -vvv
working-directory: contracts

extension:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: extension/go.mod
cache-dependency-path: extension/go.sum
- name: Vet
run: go vet ./...
working-directory: extension
- name: Test
run: go test ./... -race
working-directory: extension
Comment on lines +11 to +39

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the frontend commands that CI must invoke.
test -f frontend/package.json
rg -n -C 3 '"(build|typecheck|lint)"' frontend/package.json

# Confirm that no existing CI step validates the frontend.
rg -n -C 3 'frontend|npm ci|npm run (build|typecheck)' .github/workflows/ci.yml

Repository: LSUDOKO/Wraith

Length of output: 367


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- frontend files ---'
git ls-files frontend | sed -n '1,80p'

printf '%s\n' '--- frontend package metadata ---'
cat frontend/package.json
printf '%s\n' '--- lockfiles ---'
find frontend -maxdepth 1 -type f \( -name 'package-lock.json' -o -name 'npm-shrinkwrap.json' -o -name 'yarn.lock' -o -name 'pnpm-lock.yaml' \) -print

printf '%s\n' '--- workflow ---'
cat -n .github/workflows/ci.yml

printf '%s\n' '--- frontend references in workflow ---'
if rg -n -C 3 'frontend|npm|yarn|pnpm|bun' .github/workflows/ci.yml; then
  :
else
  printf '%s\n' 'No frontend or package-manager commands found in .github/workflows/ci.yml'
fi

Repository: LSUDOKO/Wraith

Length of output: 2567


Add frontend validation to CI.

CI does not install dependencies or build frontend/. Add a job that runs npm ci and npm run build in frontend/.

🧰 Tools
🪛 zizmor (1.29.0)

[warning] 15-17: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[warning] 29-29: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci.yml around lines 11 - 39, Add a dedicated frontend CI
job alongside contracts and extension that checks out the repository, installs
dependencies with npm ci, and runs npm run build with frontend as the working
directory.

26 changes: 26 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Release

on:
push:
branches: [main]

permissions:
contents: write
issues: write
pull-requests: write

jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
persist-credentials: false
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npm ci
- run: npx semantic-release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
35 changes: 35 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Dependencies
node_modules/
.pnpm-store/

# Secrets — never commit
.env
.env.*
!.env.example
config/extension.env
config/proxy/*.toml
!config/proxy/*.toml.example

# Foundry
contracts/out/
contracts/cache/
contracts/broadcast/
# contracts/lib/ is a git submodule (forge-std) — tracked, not ignored.

# Go
extension/bin/
*.test

# Frontend
frontend/.next/
frontend/out/
frontend/build/

# Release
CHANGELOG.md.bak

# Editors / OS
.DS_Store
.idea/
.vscode/
*.swp
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "contracts/lib/forge-std"]
path = contracts/lib/forge-std
url = https://github.com/foundry-rs/forge-std
21 changes: 21 additions & 0 deletions .releaserc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"branches": ["main"],
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
[
"@semantic-release/changelog",
{
"changelogFile": "CHANGELOG.md"
}
],
"@semantic-release/github",
[
"@semantic-release/git",
{
"assets": ["CHANGELOG.md"],
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
}
]
]
}
76 changes: 76 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Wraith

**Private cross-chain trigger engine on Flare.** Encrypted conditions in, attested execution out.

Built for the Flare Summer Signal hackathon — submitted to **Bounty 1 (Interoperable Asset Products)** and **Bounty 2 (Confidential Compute Apps)**.

---

## The problem

Every onchain automation protocol today — Gelato, Chainlink Automation, onchain limit-order books, DeFi stop-losses — publishes the **trigger condition in the clear**. A standing order sits onchain for hours or days announcing exactly what you will do and exactly when.

The best-documented consequence is **stop-loss hunting**. Because your stop price is public, price gets deliberately pushed to it. This is why serious traders keep stops off-exchange or mental: today the only way to hide your trigger is to hand custody to someone else, or to not automate at all.

Wraith is the third option.

## How it works

Your trigger condition is encrypted to a TEE's public key and stored onchain as ciphertext. A Flare Compute Extension running inside a Trusted Execution Environment is the only party that can read it. The TEE evaluates the condition against live FTSO prices (and, for cross-chain triggers, FDC-attested external-chain events), and emits a signed result **only when the condition fires**. A Flare smart contract verifies that signature and settles.

Nobody — not a searcher, not an indexer, not the keeper that pokes the system — can see what you are waiting for.

```
User → encrypt order to TEE pubkey → WraithOrders.createOrder(bytes)
↓ ciphertext onchain
Keeper → WraithOrders.tick(orderId) → TeeExtensionRegistry.sendInstructions()
↓ relayed
ext-proxy → TEE → extension POST /action
decrypt in-enclave → read FTSO → evaluate threshold
↓ triggered
TEE-signed ActionResult → polled from proxy
Anyone → WraithOrders.execute(...) → ecrecover == teeAddress → swap / redeem FXRP
```
Comment on lines +23 to +35

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add a language label to the diagram block.

The unlabeled fence fails MD040. Use text because this block is an architecture diagram.

Proposed fix
-```
+```text
 User → encrypt order to TEE pubkey → WraithOrders.createOrder(bytes)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
```
User → encrypt order to TEE pubkey → WraithOrders.createOrder(bytes)
↓ ciphertext onchain
Keeper → WraithOrders.tick(orderId) → TeeExtensionRegistry.sendInstructions()
↓ relayed
ext-proxy → TEE → extension POST /action
decrypt in-enclave → read FTSO → evaluate threshold
↓ triggered
TEE-signed ActionResult → polled from proxy
Anyone → WraithOrders.execute(...) → ecrecover == teeAddress → swap / redeem FXRP
```
🧰 Tools
🪛 markdownlint-cli2 (0.23.2)

[warning] 23-23: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` around lines 23 - 35, Label the fenced architecture diagram in the
README with the text language by changing its opening fence to ```text, while
leaving the diagram content unchanged.

Source: Linters/SAST tools


## Flare integration

| Protocol | Role |
| --- | --- |
| **FCC** (Confidential Compute) | Runs the private condition evaluation inside a TEE. The order plaintext exists nowhere else. |
| **FTSO** | Price triggers — block-latency feeds read from inside the enclave, so the keeper is not in the trust path. |
| **FDC** | Cross-chain triggers: XRPL payment attestation (`Payment`), and Web2 JSON attestation for off-chain data. |
| **FAssets / FXRP** | Settlement. A fired trigger can swap FXRP or redeem it to native XRP on the XRPL, closing the cross-chain loop. |

## What Wraith does *not* claim

Wraith hides **standing intent**. It does not hide the execution transaction — that lands onchain and is as visible as any trade. Execution-moment MEV is out of scope. The value is that the condition was never public, so it could never be hunted.

Full trust assumptions are in [`docs/TRUST.md`](docs/TRUST.md).

## Repository layout

| Path | What |
| --- | --- |
| `contracts/` | `WraithOrders.sol` and tests (Foundry) |
| `extension/` | Flare Compute Extension (Go) — the TEE-side evaluator |
| `keeper/` | Minimal loop that ticks live orders and relays signed results |
| `frontend/` | Order creation UI (Next.js + viem) |

## Status

Coston2 testnet. Flare Confidential Compute is itself "in the final stages of development and is not yet a fully public production system", so this runs against Coston2 with `SIMULATED_TEE=true`.

## Development

```bash
npm install
npm test # forge tests + go tests
```

Releases are automated with [semantic-release](https://semantic-release.gitbook.io/semantic-release) — commit messages follow [Conventional Commits](https://www.conventionalcommits.org/), and merging to `main` cuts the version, changelog, and GitHub release. Dependencies are kept current by Dependabot.

## License

Apache-2.0
8 changes: 8 additions & 0 deletions contracts/foundry.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"lib/forge-std": {
"tag": {
"name": "v1.16.2",
"rev": "bf647bd6046f2f7da30d0c2bf435e5c76a780c1b"
}
}
}
8 changes: 8 additions & 0 deletions contracts/foundry.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[profile.default]
src = "src"
out = "out"
libs = ["lib"]
test = "test"
solc = "0.8.27"
optimizer = true
optimizer_runs = 200
1 change: 1 addition & 0 deletions contracts/lib/forge-std
Submodule forge-std added at bf647b
Loading
Loading