Skip to content

Add withdraw template for wallet-to-exchange transfers - #2

Open
antb123 wants to merge 66 commits into
mainfrom
django
Open

Add withdraw template for wallet-to-exchange transfers#2
antb123 wants to merge 66 commits into
mainfrom
django

Conversation

@antb123

@antb123 antb123 commented Jan 16, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Adds withdraw template enabling Wallet → Exchange transfers (reverse of deposit flow)
  • New get_exchange_deposit_address() function in meshc core library
  • Navigation links between deposit and withdraw pages

New Routes

Route Method Purpose
/meshc/withdraw/ GET Withdraw form UI
/meshc/api/withdraw-token/ POST Generate link token for withdrawal

Flow

  1. User completes deposit with "Easy Relogin" → stores exchange auth token
  2. User navigates to withdraw page
  3. Selects exchange (Coinbase/Binance), symbol (ETH/USDC), amount
  4. Backend fetches user's exchange deposit address using stored token
  5. Backend creates link token with toAddresses = exchange deposit address
  6. User connects wallet (MetaMask) in Mesh Link UI and confirms transfer

Files Changed

  • withdraw.html - New withdraw form template (pink gradient theme)
  • link.html - Added nav link to withdraw
  • views.py - Added withdraw() and api_withdraw_token() handlers
  • urls.py - Added withdraw routes
  • core.py - Added get_exchange_deposit_address() and ExchangeDepositAddress
  • __init__.py - Exported new function and dataclass
  • docs/WITHDRAW-TEMPLATE.md - Documentation

Test plan

  • Start Django server: cd meshc_django && python manage.py runserver
  • Complete deposit at /meshc/ with "Easy Relogin" enabled
  • Navigate to /meshc/withdraw/
  • Fill form and click "Withdraw to Exchange"
  • Verify Mesh Link UI opens for wallet connection
  • Confirm transfer and check result

antb123 and others added 30 commits January 13, 2026 11:51
- Create meshsbox Django app with self-service form for link tokens
- Export create_sandbox_wallet_token from meshc public API
- Add Django 4.2 as optional dependency in pyproject.toml
- Include 6 unit tests using SimpleTestCase (no database needed)

Design: No DRF, No Auth, No Database - minimal sandbox/dev tool.
See docs/django-migration-1.md for full specification.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Document Django self-service frontend with quick start
- Add API endpoint usage example
- Include deployment guide: dev setup, production, Docker
- Add test accounts table for sandbox testing

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Search cwd and up to 3 parent directories for local_settings.py.
This allows Django apps in subdirs (meshc_django/) to find
local_settings.py placed in the project root.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add django-log-reader to django optional dependencies
- Enable Django admin with auth, sessions, messages
- Configure file-based logging to logs/django.log
- Add LOG_READER_* settings for log file pattern/limits
- Create logs directory with .gitkeep
- Add .gitignore for db.sqlite3 and log files

Access logs at /admin/ after running migrations and createsuperuser.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add gunicorn>=21.0 to django optional dependencies
- Create gunicorn.conf.py with configurable bind/workers
- Add run.sh convenience script for quick startup

Usage: cd meshc_django && ./run.sh [port]

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Script handles:
- Stop existing gunicorn (graceful then forced)
- Check/use correct venv Python
- Install dependencies (uv or pip)
- Run database migrations
- Collect static files
- Start gunicorn as daemon with PID file

Environment variables:
- MESHC_PORT (default: 10409)
- MESHC_WORKERS (default: 2)
- MESHC_PIDFILE (default: /tmp/meshc-gunicorn.pid)

Usage: ./deploy.sh [--no-restart]

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace text input with select dropdown showing XLM and USDC options.
Inline SVG icons update dynamically when selection changes.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Source: https://github.com/0xa3k5/web3icons
- XLM: mono version with black circle background
- USDC: branded version with official blue

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- ETH icon from web3icons branded collection
- Add Resources section to README with web3icons link

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Stellar tokens (XLM, USDC) use G... address
- Ethereum tokens (SEPOLIAETH) use 0x... address
- Only swaps if user hasn't entered a custom address

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add 127.0.0.1 to default WEBHOOK_ALLOWED_IPS for local dev
- Update WEBHOOK_SPEC.md with correct test server (meshcdev.bpventures.us)
- Use port 10409 for local testing (matches deploy.sh)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Uses RotatingFileHandler to prevent logs from filling disk.
Max ~60MB total log storage (10MB x 6 files).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
TimedRotatingFileHandler rotates at midnight.
backupCount=0 means unlimited - logs are never deleted.
Files: django.log, django.log.2025-01-13, django.log.2025-01-12, etc.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Delete web/link.html (replaced by Django template)
- Move web/examples/ to docs/front-end-examples/
- Remove --local flag and HTTP server code from CLI (~40 lines)
- Update django-migration-1.md design decisions

Django at meshcdev.bpventures.us/meshc/ replaces the CLI --local flag.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Replace Peewee with Django ORM in storage.py (shared DB with web)
- Add IntegrationToken model and admin to meshsbox
- Add Easy Relogin checkbox to web form (default checked)
- Save integration tokens after successful transfers for MMT flow
- New endpoint: POST /meshc/api/save-token/

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add favicon.ico and favicon-512.png to meshsbox static files
- Update link.html template with favicon links
- Fix token-store command syntax in testing docs

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Log all API calls to ~/.meshc/mesh_api.log with daily rotation
- Format: INFO timestamp meshc.api file:line func() :: method url
- Request JSON and response with status/timing logged
- Uses stacklevel=2 to show caller function in log

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Set backupCount=0 to never delete old logs
- Add rotator/namer to gzip logs after daily rotation
- Result: mesh_api.log.2026-01-14.gz, etc.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Log location priority:
1. MESH_API_LOG_DIR from local_settings.py or env
2. meshc_django/logs/ if exists (auto-detected)
3. ~/.meshc/ fallback

All logs now in one place: meshc_django/logs/

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previously defaulted to 'web-user' for all anonymous users. Now sends
the Stellar/Ethereum address, enabling per-user session tracking and
Easy Relogin functionality.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Security fixes:
- Add CsrfViewMiddleware to Django middleware stack
- Remove @csrf_exempt from /api/link-token/ and /api/save-token/
- Keep @csrf_exempt on /api/webhook/ (external Mesh servers)
- Fix get_client_ip() to not trust spoofable X-Forwarded-For header
- Add CSRF token meta tag to template
- Include X-CSRFToken header in all same-origin fetch calls

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Ignore all *.log and *.log.* files
- Ignore meshc_django/logs/* but keep .gitkeep
- Ignore meshc_django/db.sqlite3 and staticfiles/
- Remove accidentally committed log file

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Security fix:
- Validate Stellar addresses: G + 55 base32 characters
- Validate Ethereum addresses: 0x + 40 hex characters
- Reject malformed addresses before sending to Mesh API
- Add tests for invalid addresses and SQL injection attempts

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
antb123 and others added 30 commits January 16, 2026 14:00
Logs full payload structure to browser console to diagnose
token extraction issue with get_exchange_deposit_address.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Pass the broker type from onIntegrationConnected callback to
get_exchange_deposit_address instead of hardcoded value.
This ensures token type matches API type parameter.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add info box explaining the two-step process
- Update status messages to show Step 1/Step 2 progress
- Clarify that exchange connection is for getting deposit address

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Split api_withdraw_token into two endpoints:
  - api_withdraw_token: checks for stored token, returns auth_token
  - api_deposit_token: fetches exchange deposit address
- Fix broker type extraction from nested accessToken structure
- Add binanceInternationalDirect to exchange type mapping
- Close Mesh Link after getting auth token to prevent deposit flow
- Update tests for new two-endpoint flow

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update sandbox UI branding from "Mesh Connect" to "StellarMesh" and add
BPV Stellar logo as header icon and favicon.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Document secure storage strategy for Mesh Managed Tokens:
- Hash+encrypt architecture for searchable encrypted fields
- Django Fernet field-level encryption
- Migration strategy for existing plaintext tokens
- Key rotation support

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Mesh tokens are ~400+ characters, exceeding the previous 255 limit.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Mesh SDK expects the internal brokerType (e.g., "binanceInternationalDirect")
for skip-auth relogin, not the display name (e.g., "Binance").

- Frontend now captures and saves brokerType from Mesh response
- Backend returns accessToken + brokerType format for SDK compatibility
- Old tokens with display names won't work; re-auth required

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
SQLite with USE_TZ=False doesn't support timezone-aware datetimes.
Convert to naive datetime before storing.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Mesh SDK expects:
  { tokenId: "...", type: "Coinbase" }
Not:
  { accessToken: "...", brokerType: "binanceInternationalDirect" }

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement complete Easy Relogin flow to skip re-authentication for returning users
by storing and reusing Mesh integration tokens across sessions.

Changes:
- Add link.html: Standalone link token generator with full Easy Relogin support
  - Fetches stored tokens from backend API
  - Passes accountTokens to Mesh SDK createLink()
  - Auto-saves new tokens when user connects integrations
  - Supports both CEX and Wallet modes with modern UI

- Update views.py:
  - Add link() view to render link token generator page
  - Enhance api_link_token() to retrieve and return stored tokens for users
  - Token lookup by user_id with active status filter

- Update urls.py:
  - Add /meshc/link/ route for link token generator page

- Fix deposit.html:
  - Remove duplicate createLink() declaration
  - Clean up dead code after accountTokens assignment

How Easy Relogin works:
1. First visit: User authenticates with Coinbase → token saved to database
2. Return visit: Backend retrieves token → frontend passes to createLink()
3. Mesh SDK skips login screen → user goes straight to transfer UI

Implementation follows Mesh documentation:
https://docs.meshconnect.com/advanced/mesh-managed-tokens#3-reuse-tokenids-with-mesh-sdk
For Stellar and some exchanges, a memo is required to credit deposits
correctly. Now displays memo with warning styling and minimum deposit
amount when returned by the Mesh API.
Changed integration_type field from brokerName (display name like "Binance")
to brokerType (internal identifier like "binanceInternationalDirect") in both
deposit.html and link.html. Mesh SDK requires the internal brokerType when
matching accountTokens for relogin.
Changed API responses to use accessToken key instead of tokenId in
accountTokens array. Mesh SDK requires the format:
{accessToken: "...", type: "binanceInternationalDirect"}

Combined with previous brokerType fix, Easy Relogin should now work.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants