Skip to content

Commit ed223d3

Browse files
authored
Merge pull request canopy-network#277 from canopy-network/feature/wallet
New Wallet Implementation
2 parents c2eb787 + 7557e71 commit ed223d3

222 files changed

Lines changed: 39457 additions & 8683 deletions

File tree

Some content is hidden

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

.docker/Dockerfile

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,27 @@ FROM golang:1.24-alpine AS builder
22

33
RUN apk update && apk add --no-cache make bash nodejs npm
44

5+
# Wallet-specific build configuration
6+
# Default: / (for simple-stack deployment with direct port access)
7+
ARG VITE_WALLET_BASE_PATH=/
8+
ARG VITE_EXPLORER_BASE_PATH=http://localhost:50001
9+
# RPC proxy targets for chain.json generation
10+
ARG VITE_WALLET_RPC_PROXY_TARGET=http://localhost:50002
11+
ARG VITE_WALLET_ADMIN_RPC_PROXY_TARGET=http://localhost:50003
12+
ARG VITE_ROOT_WALLET_RPC_PROXY_TARGET=http://localhost:50002
13+
14+
515
WORKDIR /go/src/github.com/canopy-network/canopy
616
COPY . /go/src/github.com/canopy-network/canopy
717

18+
# Export build configuration to environment
19+
ENV VITE_WALLET_BASE_PATH=${VITE_WALLET_BASE_PATH}
20+
ENV VITE_EXPLORER_BASE_PATH=${VITE_EXPLORER_BASE_PATH}
21+
ENV VITE_WALLET_RPC_PROXY_TARGET=${VITE_WALLET_RPC_PROXY_TARGET}
22+
ENV VITE_WALLET_ADMIN_RPC_PROXY_TARGET=${VITE_WALLET_ADMIN_RPC_PROXY_TARGET}
23+
ENV VITE_ROOT_WALLET_RPC_PROXY_TARGET=${VITE_ROOT_WALLET_RPC_PROXY_TARGET}
24+
25+
826
RUN make build/wallet
927
RUN make build/explorer
1028
RUN go build -a -o bin ./cmd/main/...

.docker/compose.yaml

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,38 +4,51 @@ services:
44
build:
55
context: ..
66
dockerfile: .docker/Dockerfile
7+
args:
8+
VITE_WALLET_BASE_PATH: /
9+
VITE_EXPLORER_BASE_PATH: http://localhost:50001
10+
VITE_WALLET_RPC_PROXY_TARGET: http://localhost:50002
11+
VITE_WALLET_ADMIN_RPC_PROXY_TARGET: http://localhost:50003
12+
VITE_ROOT_WALLET_RPC_PROXY_TARGET: http://localhost:50002
713
ports:
814
- 50000:50000 # Wallet
915
- 50001:50001 # Explorer
1016
- 50002:50002 # RPC
1117
- 50003:50003 # Admin RPC
12-
- 9001:9001 # TCP P2P
13-
- 6060:6060 # Debug
14-
- 9090:9090 # Metrics
18+
- 9001:9001 # TCP P2P
19+
- 6060:6060 # Debug
20+
- 9090:9090 # Metrics
1521
networks:
1622
- canopy
1723
command: ["start"]
1824
volumes:
1925
- ./volumes/node_1:/root/.canopy
20-
# deploy:
21-
# resources:
22-
# limits:
23-
# memory: 2G
24-
# cpus: "1.0"
26+
# deploy:
27+
# resources:
28+
# limits:
29+
# memory: 2G
30+
# cpus: "1.0"
2531

2632
node-2:
2733
container_name: node-2
2834
build:
2935
context: ..
3036
dockerfile: .docker/Dockerfile
37+
args:
38+
VITE_WALLET_BASE_PATH: /
39+
VITE_EXPLORER_BASE_PATH: http://localhost:40001
40+
VITE_WALLET_RPC_PROXY_TARGET: http://localhost:40002
41+
VITE_WALLET_ADMIN_RPC_PROXY_TARGET: http://localhost:40003
42+
VITE_ROOT_WALLET_RPC_PROXY_TARGET: http://localhost:50002
43+
3144
ports:
3245
- 40000:40000 # Wallet
3346
- 40001:40001 # Explorer
3447
- 40002:40002 # RPC
3548
- 40003:40003 # Admin RPC
36-
- 9002:9002 # TCP P2P
37-
- 6061:6060 # Debug
38-
- 9091:9091 # Metrics
49+
- 9002:9002 # TCP P2P
50+
- 6061:6060 # Debug
51+
- 9091:9091 # Metrics
3952
networks:
4053
- canopy
4154
command: ["start"]
@@ -72,4 +85,4 @@ services:
7285

7386
networks:
7487
canopy:
75-
driver: bridge
88+
driver: bridge

Dockerfile

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
FROM golang:1.24-alpine AS builder
2+
3+
RUN apk update && apk add --no-cache make bash nodejs npm
4+
5+
ARG BIN_PATH
6+
# Wallet-specific build configuration
7+
# Default: /wallet/ (for monitoring-stack deployment with Traefik reverse proxy)
8+
# Override with: docker build --build-arg VITE_WALLET_BASE_PATH=/
9+
ARG VITE_WALLET_BASE_PATH=/wallet/
10+
# RPC proxy targets for chain.json generation
11+
# For monitoring-stack, these should be Traefik URLs
12+
ARG VITE_WALLET_RPC_PROXY_TARGET=/wallet/rpc
13+
ARG VITE_WALLET_ADMIN_RPC_PROXY_TARGET=/wallet/adminrpc
14+
ARG VITE_ROOT_WALLET_RPC_PROXY_TARGET=/wallet/rootrpc
15+
16+
WORKDIR /go/src/github.com/canopy-network/canopy
17+
COPY . /go/src/github.com/canopy-network/canopy
18+
19+
# Export build configuration to environment
20+
# These are available during npm build for wallet and explorer
21+
ENV VITE_WALLET_BASE_PATH=${VITE_WALLET_BASE_PATH}
22+
ENV VITE_WALLET_RPC_PROXY_TARGET=${VITE_WALLET_RPC_PROXY_TARGET}
23+
ENV VITE_WALLET_ADMIN_RPC_PROXY_TARGET=${VITE_WALLET_ADMIN_RPC_PROXY_TARGET}
24+
ENV VITE_ROOT_WALLET_RPC_PROXY_TARGET=${VITE_ROOT_WALLET_RPC_PROXY_TARGET}
25+
26+
RUN make build/wallet
27+
RUN make build/explorer
28+
RUN CGO_ENABLED=0 GOOS=linux go build -a -o bin ./cmd/auto-update/.
29+
30+
# Only build if the file at ${BIN_PATH} doesn't already exist
31+
RUN if [ ! -f "${BIN_PATH}" ]; then \
32+
echo "File ${BIN_PATH} not found. Building it..."; \
33+
CGO_ENABLED=0 GOOS=linux go build -a -o "${BIN_PATH}" ./cmd/main/...; \
34+
else \
35+
echo "File ${BIN_PATH} already exists. Skipping build."; \
36+
fi
37+
38+
FROM alpine:3.19
39+
40+
RUN apk add --no-cache pigz ca-certificates
41+
42+
ARG BIN_PATH
43+
44+
WORKDIR /app
45+
COPY --from=builder /go/src/github.com/canopy-network/canopy/bin ./
46+
COPY --from=builder /go/src/github.com/canopy-network/canopy/${BIN_PATH} ${BIN_PATH}
47+
RUN chmod +x ${BIN_PATH}
48+
ENTRYPOINT ["/app/bin"]

cmd/rpc/server.go

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ var explorerFS embed.FS
341341
//go:embed all:web/wallet/out
342342
var walletFS embed.FS
343343

344-
// runStaticFileServer creates a web server serving static files
344+
// runStaticFileServer creates a web server serving static files with SPA fallback
345345
func (s *Server) runStaticFileServer(fileSys fs.FS, dir, port string, conf lib.Config) {
346346
// Attempt to get a sub-filesystem rooted at the specified directory
347347
distFS, err := fs.Sub(fileSys, dir)
@@ -352,13 +352,16 @@ func (s *Server) runStaticFileServer(fileSys fs.FS, dir, port string, conf lib.C
352352

353353
// Create a new ServeMux to handle incoming HTTP requests
354354
mux := http.NewServeMux()
355-
fileServer := http.FileServer(http.FS(distFS))
356355

357356
// Define a handler function for the root path
358357
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
359-
serveIndex := func() {
358+
requestedPath := r.URL.Path
359+
360+
// Helper function to serve index.html with config injection
361+
serveIndexHTML := func() {
360362
// Construct the file path for `index.html`
361363
filePath := path.Join(dir, "index.html")
364+
362365
// Read the content of `index.html` into a byte slice
363366
htmlBytes, e := fs.ReadFile(fileSys, filePath)
364367
if e != nil {
@@ -372,26 +375,40 @@ func (s *Server) runStaticFileServer(fileSys fs.FS, dir, port string, conf lib.C
372375
// Set the response header as HTML and write the injected content to the response
373376
w.Header().Set("Content-Type", "text/html")
374377
w.WriteHeader(http.StatusOK)
375-
_, _ = w.Write([]byte(injectedHTML))
378+
w.Write([]byte(injectedHTML))
376379
}
377380

378-
// Serve `index.html` with dynamic config injection
379-
if r.URL.Path == "/" || r.URL.Path == "/index.html" {
380-
serveIndex()
381+
// Serve index.html for root path
382+
if requestedPath == "/" || requestedPath == "/index.html" {
383+
serveIndexHTML()
381384
return
382385
}
383386

384-
// Serve real static assets if they exist.
385-
requestPath := strings.TrimPrefix(path.Clean(r.URL.Path), "/")
386-
if requestPath != "" {
387-
if _, e := fs.Stat(distFS, requestPath); e == nil {
388-
fileServer.ServeHTTP(w, r)
387+
// Check if the requested path has a file extension (indicates static asset)
388+
// Common static asset extensions: .js, .css, .svg, .png, .jpg, .jpeg, .gif, .ico, .woff, .woff2, .ttf, .eot, .map
389+
ext := path.Ext(requestedPath)
390+
isStaticAsset := ext != ""
391+
392+
if isStaticAsset {
393+
// Try to serve the static asset from the file system
394+
// Remove leading slash for fs.Open
395+
assetPath := strings.TrimPrefix(requestedPath, "/")
396+
397+
// Check if the file exists in the embedded filesystem
398+
if _, err := distFS.Open(assetPath); err == nil {
399+
// File exists, serve it
400+
http.FileServer(http.FS(distFS)).ServeHTTP(w, r)
389401
return
390402
}
403+
404+
// Static asset not found, return 404
405+
http.NotFound(w, r)
406+
return
391407
}
392408

393-
// SPA fallback: unknown client-side routes resolve to index.html.
394-
serveIndex()
409+
// For all other requests (no file extension = HTML navigation),
410+
// serve index.html to enable SPA client-side routing
411+
serveIndexHTML()
395412
})
396413

397414
// Start the HTTP server in a new goroutine and listen on the specified port

cmd/rpc/web/wallet/.env.example

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Wallet Base Path Configuration
2+
# This sets the base URL path for the wallet in production builds
3+
#
4+
# Examples:
5+
# - For deployment at https://example.com/wallet/ use: VITE_WALLET_BASE_PATH=/wallet/
6+
# - For deployment at https://wallet.example.com/ use: VITE_WALLET_BASE_PATH=/
7+
# - For deployment at root domain use: VITE_WALLET_BASE_PATH=/
8+
#
9+
# Default: /wallet/
10+
VITE_WALLET_BASE_PATH=/wallet/
11+
12+
# RPC Proxy Targets (Development Server Only)
13+
# Used by Vite dev server proxy configuration
14+
VITE_WALLET_RPC_PROXY_TARGET=http://localhost:50002
15+
VITE_WALLET_ADMIN_RPC_PROXY_TARGET=http://localhost:50003
16+
# Root chain RPC target - used for cross-chain order queries (available orders, orders to fulfill)
17+
VITE_ROOT_WALLET_RPC_PROXY_TARGET=http://localhost:50002
18+
19+
# Node Environment
20+
# Options: development | production
21+
# Default: development
22+
VITE_NODE_ENV=development

cmd/rpc/web/wallet/.gitignore

Lines changed: 10 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,12 @@
1-
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2-
3-
# dependencies
4-
/node_modules
5-
/.pnp
6-
.pnp.js
7-
8-
# testing
9-
/coverage
10-
11-
# next.js
12-
/.next/
13-
/out/
14-
15-
# production
16-
/build
17-
18-
# misc
19-
.DS_Store
20-
*.pem
21-
22-
# debug
23-
npm-debug.log*
24-
yarn-debug.log*
25-
yarn-error.log*
26-
27-
# local env files
28-
.env*.local
29-
30-
# Docker environment
31-
.docker/.env
32-
.docker/volumes
33-
34-
# vercel
35-
.vercel
36-
37-
# typescript
1+
.agents/*
2+
.claude/*
3+
node_modules
4+
out
5+
vite.config.ts.*
6+
.idea
7+
dist
388
*.tsbuildinfo
39-
next-env.d.ts
409

41-
.idea
10+
# Compiled JS files (TypeScript generates these)
11+
src/**/*.js
12+
src/**/*.jsx

cmd/rpc/web/wallet/.prettierrc

Lines changed: 0 additions & 8 deletions
This file was deleted.

cmd/rpc/web/wallet/AGENTS.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Repository Guidelines
2+
3+
## Project Structure & Module Organization
4+
- `src/` contains application code.
5+
- `src/app/` holds routing, page shells, and providers.
6+
- `src/components/` contains feature UI and reusable primitives (`src/components/ui`).
7+
- `src/actions/` implements the dynamic action/form runtime.
8+
- `src/core/` and `src/hooks/` contain DS fetch logic, RPC helpers, and data hooks.
9+
- `src/manifest/` contains manifest loaders and types.
10+
- `public/plugin/canopy/` is the config surface (`chain.json`, `manifest.json`, `chain.json.template`).
11+
- `scripts/generate-chain-config.js` is executed before production builds.
12+
- `docs/declarative-actions-and-chain.md` documents the config-first architecture.
13+
- Build artifacts are emitted to `out/`.
14+
15+
## Build, Test, and Development Commands
16+
- `npm install` installs dependencies (a `pnpm-lock.yaml` is also present if you use pnpm).
17+
- `npm run dev` starts the Vite dev server on `http://localhost:5173`.
18+
- `npm run build` runs prebuild config generation, TypeScript project checks, and Vite production build.
19+
- `npm run preview` serves the production bundle locally.
20+
- No `npm test` script exists in this package yet; use `npm run build` as the minimum validation step.
21+
22+
## Coding Style & Naming Conventions
23+
- TypeScript is strict (`"strict": true`); keep all new code fully typed.
24+
- Prefer React function components and hooks.
25+
- Naming conventions:
26+
- Components: `PascalCase.tsx` (example: `ValidatorList.tsx`)
27+
- Hooks: `useX.ts`/`useX.tsx` (example: `useValidators.ts`)
28+
- Utilities: `camelCase.ts`
29+
- Use the `@/` alias for imports rooted at `src`.
30+
- Preserve the config-first model: new chain actions/endpoints should be defined in `public/plugin/canopy/*.json`, not hardcoded in UI flows.
31+
- Follow local formatting in the file you touch (quote style is mixed across the repo).
32+
33+
## Testing Guidelines
34+
- Automated tests are currently not configured in this workspace.
35+
- Before opening a PR, run `npm run build` and manually verify affected flows in `npm run dev`.
36+
- If you add tests, colocate them as `*.test.ts`/`*.test.tsx` near the implementation and prioritize action runtime, DS fetching, and critical page paths.
37+
38+
## Commit & Pull Request Guidelines
39+
- Follow Conventional Commit style used in history: `feat:`, `fix:`, `chore:`.
40+
- Keep commits small and focused; avoid mixing unrelated refactors with feature work.
41+
- PRs should include:
42+
- a concise summary and rationale,
43+
- linked issue/task,
44+
- screenshots or short recordings for UI changes,
45+
- notes on `chain.json`/`manifest.json` compatibility impacts.

0 commit comments

Comments
 (0)