Skip to content

Commit baf5a77

Browse files
authored
Merge branch 'develop' into feature/105-network-mismatch-detection
2 parents 1a30848 + 9b7b856 commit baf5a77

52 files changed

Lines changed: 2012 additions & 348 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -26,25 +26,3 @@ jobs:
2626
- run: pnpm install --frozen-lockfile
2727
- run: pnpm format:check
2828
- run: pnpm build
29-
30-
# Playwright E2E is currently non-blocking. The test files inherited
31-
# from wave-6 PRs use a mixed structure (tests/ + e2e/) that trips
32-
# Playwright's test-collection ('did not expect test.describe() to
33-
# be called here'). Track green build + typecheck for now; a follow-up
34-
# PR will realign the playwright config with the actual test dirs
35-
# and re-enable this step as blocking.
36-
- name: Install Playwright Browsers
37-
run: pnpm exec playwright install --with-deps
38-
continue-on-error: true
39-
40-
- name: Run Playwright E2E tests
41-
run: pnpm test:e2e
42-
continue-on-error: true
43-
44-
- name: Upload Playwright Report
45-
uses: actions/upload-artifact@v4
46-
if: always()
47-
with:
48-
name: playwright-report
49-
path: playwright-report/
50-
retention-days: 30
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
name: Retarget PRs against main
2+
3+
on:
4+
pull_request_target:
5+
types: [opened, reopened]
6+
branches: [main]
7+
8+
permissions:
9+
pull-requests: write
10+
issues: write
11+
contents: read
12+
13+
jobs:
14+
retarget:
15+
# Skip release PRs (develop -> main); catch everything else that targets main.
16+
if: github.event.pull_request.head.ref != 'develop'
17+
runs-on: ubuntu-latest
18+
steps:
19+
- name: Retarget to develop and comment
20+
env:
21+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
22+
run: |
23+
PR=${{ github.event.pull_request.number }}
24+
REPO=${{ github.repository }}
25+
gh pr edit "$PR" --repo "$REPO" --base develop
26+
gh pr comment "$PR" --repo "$REPO" --body "Auto-retargeted this PR from \`main\` to \`develop\`. Wave PRs merge into \`develop\`; \`main\` is only for release cuts. If you meant to target main deliberately (rare), reply here and we can revert this."

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"@walletconnect/core": "^2.23.10",
3838
"@walletconnect/sign-client": "^2.23.10",
3939
"@wraith-protocol/sdk": "^1.4.5",
40+
"@zxing/browser": "0.0.7",
4041
"bs58": "^6.0.0",
4142
"buffer": "^6.0.3",
4243
"i18next": "^24.2.3",
@@ -69,6 +70,7 @@
6970
"@types/react-dom": "^19.0.0",
7071
"@vitejs/plugin-react": "^4.5.0",
7172
"@vitest/coverage-v8": "^4.1.9",
73+
"ajv": "^8.18.0",
7274
"autoprefixer": "^10.4.20",
7375
"concurrently": "^9.2.1",
7476
"http-server": "^14.1.1",

pnpm-lock.yaml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/App.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import Vault from '@/pages/Vault';
1010
import Schedule from '@/pages/Schedule';
1111
import StellarSplit from '@/pages/StellarSplit';
1212
import Names from '@/pages/Names';
13+
import Activity from '@/pages/Activity';
14+
import Debug from '@/pages/Debug';
1315

1416
export function App() {
1517
return (
@@ -27,6 +29,9 @@ export function App() {
2729
<Route path="/stellar/split" element={<StellarSplit />} />
2830
<Route path="/pay" element={<Send />} />
2931
<Route path="/names" element={<Names />} />
32+
<Route path="/activity" element={<Activity />} />
33+
<Route path="/history" element={<Activity />} />
34+
<Route path="/debug" element={<Debug />} />
3035
<Route path="*" element={<Navigate to="/send" replace />} />
3136
</Routes>
3237
</main>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Illustration License
2+
3+
All SVG illustrations in this directory are original works created for the Wraith Protocol Demo.
4+
5+
## Terms
6+
7+
These illustrations are provided under the MIT License.
8+
9+
Copyright (c) 2026 Wraith Protocol
10+
11+
Permission is hereby granted, free of charge, to any person obtaining a copy
12+
of this software and associated documentation files (the "Software"), to deal
13+
in the Software without restriction, including without limitation the rights
14+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15+
copies of the Software, and to permit persons to whom the Software is
16+
furnished to do so, subject to the following conditions:
17+
18+
The above copyright notice and this permission notice shall be included in all
19+
copies or substantial portions of the Software.
20+
21+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27+
SOFTWARE.
Lines changed: 8 additions & 0 deletions
Loading
Lines changed: 10 additions & 0 deletions
Loading
Lines changed: 6 additions & 0 deletions
Loading

src/components/ActivityRow.tsx

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
import { ActivityEntry } from '@/stores/activityStore';
2+
import { stellarTxUrl, horizenTxUrl, solanaTxUrl, ckbTxUrl } from '@/lib/explorer';
3+
import { StellarLink } from '@/components/StellarLink';
4+
5+
interface ActivityRowProps {
6+
entry: ActivityEntry;
7+
}
8+
9+
export function ActivityRow({ entry }: ActivityRowProps) {
10+
const isStellarAccount =
11+
entry.chain === 'stellar' && !!entry.recipient && /^[GM][A-Z2-7]+$/.test(entry.recipient);
12+
const getExplorerUrl = () => {
13+
switch (entry.chain) {
14+
case 'stellar':
15+
return stellarTxUrl(entry.id);
16+
case 'horizen':
17+
return horizenTxUrl(entry.id);
18+
case 'solana':
19+
return solanaTxUrl(entry.id);
20+
case 'ckb':
21+
return ckbTxUrl(entry.id);
22+
default:
23+
return '#';
24+
}
25+
};
26+
27+
const getChainIcon = () => {
28+
switch (entry.chain) {
29+
case 'stellar':
30+
return (
31+
<svg className="h-4 w-4" viewBox="0 0 16 16" fill="currentColor">
32+
<circle cx="8" cy="8" r="7" fill="currentColor" opacity="0.2" />
33+
<path d="M8 2L9.5 6.5L14 8L9.5 9.5L8 14L6.5 9.5L2 8L6.5 6.5L8 2Z" fill="currentColor" />
34+
</svg>
35+
);
36+
case 'horizen':
37+
return (
38+
<svg className="h-4 w-4" viewBox="0 0 16 16" fill="currentColor">
39+
<circle cx="8" cy="8" r="7" fill="currentColor" opacity="0.2" />
40+
<path
41+
d="M8 3V13M5 6L8 3L11 6M5 10L8 13L11 10"
42+
stroke="currentColor"
43+
strokeWidth="1.5"
44+
strokeLinecap="round"
45+
/>
46+
</svg>
47+
);
48+
case 'solana':
49+
return (
50+
<svg className="h-4 w-4" viewBox="0 0 16 16" fill="currentColor">
51+
<circle cx="8" cy="8" r="7" fill="currentColor" opacity="0.2" />
52+
<path
53+
d="M3 8H13M8 3V13"
54+
stroke="currentColor"
55+
strokeWidth="1.5"
56+
strokeLinecap="round"
57+
/>
58+
</svg>
59+
);
60+
case 'ckb':
61+
return (
62+
<svg className="h-4 w-4" viewBox="0 0 16 16" fill="currentColor">
63+
<circle cx="8" cy="8" r="7" fill="currentColor" opacity="0.2" />
64+
<rect x="5" y="5" width="6" height="6" rx="1" fill="currentColor" />
65+
</svg>
66+
);
67+
default:
68+
return null;
69+
}
70+
};
71+
72+
return (
73+
<div className="group flex flex-col gap-3 rounded-xl border border-outline-variant bg-surface-container p-4 transition-colors hover:border-outline">
74+
<div className="flex items-center justify-between gap-4">
75+
<div className="flex items-center gap-2">
76+
{getChainIcon()}
77+
<span
78+
className={`h-2 w-2 rounded-full ${
79+
entry.status === 'confirmed'
80+
? 'bg-secondary'
81+
: entry.status === 'pending'
82+
? 'bg-tertiary animate-pulse'
83+
: 'bg-error'
84+
}`}
85+
/>
86+
<span className="font-mono text-[10px] uppercase tracking-widest text-on-surface">
87+
{entry.status}{entry.kind.replace('-', ' ')}
88+
</span>
89+
</div>
90+
<span className="font-mono text-[10px] text-outline">
91+
{new Date(entry.timestamp).toLocaleString()}
92+
</span>
93+
</div>
94+
95+
<div className="flex flex-col gap-1">
96+
<div className="flex items-center justify-between gap-4">
97+
<span className="font-mono text-[10px] uppercase tracking-widest text-outline">
98+
Direction
99+
</span>
100+
<span className="font-mono text-[10px] text-on-surface">
101+
{entry.direction === 'in' ? 'Incoming (Received)' : 'Outgoing (Sent)'}
102+
</span>
103+
</div>
104+
105+
{entry.amount && (
106+
<div className="flex items-center justify-between gap-4">
107+
<span className="font-mono text-[10px] uppercase tracking-widest text-outline">
108+
Amount
109+
</span>
110+
<span className="font-mono text-[10px] text-on-surface">
111+
{entry.amount} {entry.token || 'XLM'}
112+
</span>
113+
</div>
114+
)}
115+
116+
{entry.recipient && (
117+
<div className="flex items-center justify-between gap-4">
118+
<span className="font-mono text-[10px] uppercase tracking-widest text-outline">
119+
Recipient / Address
120+
</span>
121+
{isStellarAccount ? (
122+
<StellarLink
123+
value={entry.recipient!}
124+
type="account"
125+
className="max-w-[240px]"
126+
linkClassName="text-[10px]"
127+
/>
128+
) : (
129+
<span
130+
className="max-w-[200px] truncate font-mono text-[10px] text-on-surface"
131+
title={entry.recipient}
132+
>
133+
{entry.recipient.length > 30
134+
? `${entry.recipient.slice(0, 12)}...${entry.recipient.slice(-12)}`
135+
: entry.recipient}
136+
</span>
137+
)}
138+
</div>
139+
)}
140+
141+
{entry.kind !== 'stealth-receive' && (
142+
<div className="flex items-center justify-between gap-4">
143+
<span className="font-mono text-[10px] uppercase tracking-widest text-outline">
144+
Hash
145+
</span>
146+
{entry.chain === 'stellar' ? (
147+
<StellarLink value={entry.id} type="tx" linkClassName="text-[10px]" />
148+
) : (
149+
<a
150+
href={getExplorerUrl()}
151+
target="_blank"
152+
rel="noopener noreferrer"
153+
className="font-mono text-[10px] text-tertiary hover:underline"
154+
>
155+
{entry.id.slice(0, 12)}...{entry.id.slice(-12)}
156+
</a>
157+
)}
158+
</div>
159+
)}
160+
</div>
161+
</div>
162+
);
163+
}

0 commit comments

Comments
 (0)