-
Notifications
You must be signed in to change notification settings - Fork 0
feat: Wraith MVP — private conditional orders on Flare #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
35c8e76
50ccb32
2777770
67f99c3
0227c99
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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: ["*"] |
| 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 | ||
| - 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
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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.ymlRepository: 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'
fiRepository: LSUDOKO/Wraith Length of output: 2567 Add frontend validation to CI. CI does not install dependencies or build 🧰 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 |
||
| 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 }} |
| 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 |
| 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 |
| 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}" | ||
| } | ||
| ] | ||
| ] | ||
| } |
| 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
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 Proposed fix-```
+```text
User → encrypt order to TEE pubkey → WraithOrders.createOrder(bytes)📝 Committable suggestion
Suggested change
🧰 Tools🪛 markdownlint-cli2 (0.23.2)[warning] 23-23: Fenced code blocks should have a language specified (MD040, fenced-code-language) 🤖 Prompt for AI AgentsSource: 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 | ||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| { | ||
| "lib/forge-std": { | ||
| "tag": { | ||
| "name": "v1.16.2", | ||
| "rev": "bf647bd6046f2f7da30d0c2bf435e5c76a780c1b" | ||
| } | ||
| } | ||
| } |
| 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 |
There was a problem hiding this comment.
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: falseon 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: falseAlso 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
Source: Linters/SAST tools