Introduction to Secure Deposit Address Management
In modern cryptocurrency exchange infrastructure, securely generating and managing deposit addresses is a critical component. This article walks you through the process of building a robust system for Ethereum (ETH) deposit address allocation, focusing on secure API design, request validation, and cryptographic signature verification. Whether you're developing a wallet backend or integrating blockchain functionality into a financial application, this guide provides actionable insights into creating a production-ready service.
The core challenge lies not only in generating valid Ethereum addresses but also in ensuring that every interaction with your system is authenticated, tamper-proof, and scalable. We’ll explore how to implement secure RESTful APIs using Go and Gin, validate incoming requests, and protect against unauthorized access using digital signatures.
Validating Incoming API Requests
Once basic wallet functionality is in place, the next step is exposing services securely via RESTful APIs. Given that these endpoints handle sensitive financial operations, request validation is essential.
We use the gin framework to build a high-performance HTTP server. Every incoming request must be authenticated and verified to prevent abuse or fraudulent address generation.
A typical request body includes the following required fields:
var req struct {
AppName string `json:"app_name" binding:"required"`
Nonce string `json:"nonce" binding:"required" validate:"max=40"`
Sign string `json:"sign" binding:"required"`
}app_name: Identifies the registered application making the request.nonce: A unique, one-time-use string to prevent replay attacks.sign: The cryptographic signature used to verify authenticity.
To map app_name to a real application, we store credentials in a database table called t_product. This allows us to retrieve the app-specific secret key (app_sk) used during signature verification.
Database Schema: t_product
CREATE TABLE `t_product` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`app_name` varchar(128) NOT NULL DEFAULT '' COMMENT 'Application name',
`app_sk` varchar(64) NOT NULL DEFAULT '' COMMENT 'Application secret key',
`cb_url` varchar(512) NOT NULL COMMENT 'Callback URL',
`whitelist_ip` varchar(1024) NOT NULL DEFAULT '' COMMENT 'Whitelisted IPs',
PRIMARY KEY (`id`),
UNIQUE KEY `app_name` (`app_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;This schema supports:
- Secure app identification
- IP-based access control
- Configurable webhook callbacks for deposit notifications
Signature Verification: Ensuring Request Integrity
To ensure that each API call comes from an authorized source, we implement a secure signing mechanism based on a method similar to WeChat Pay's signature algorithm. This approach guarantees data integrity and origin authenticity.
Step-by-Step Signature Generation
- Collect Parameters: Gather all non-empty parameters from the request (excluding the
signfield itself). - Sort by ASCII Key Order: Sort the parameters lexicographically by their keys.
- Build StringA: Concatenate the sorted key-value pairs in
key=value&key2=value2format. - Append Secret Key: Append
&key=app_skto formstringSignTemp. - Hash and Uppercase: Apply MD5 hashing and convert the result to uppercase — this is your final
sign.
🔐 The nonce parameter ensures unpredictability. Even if an attacker intercepts a valid request, they cannot reuse it due to the one-time nature of the nonce.Example: Generating a Valid Signature
Suppose the incoming parameters are:
app_name: wxd930ea5d5a258f4fnonce: ibuaiVcKdpRxkhJA
Step 1: Sort and Build StringA
stringA = "app_name=wxd930ea5d5a258f4f&nonce=ibuaiVcKdpRxkhJA"Step 2: Append Key and Hash
Assume the platform’s secret key is: 192006250b4c09247ec02edce69f6a2d
stringSignTemp = stringA + "&key=192006250b4c09247ec02edce69f6a2d"
sign = MD5(stringSignTemp).ToUpper() = "30A40459EB96131C493486D8013C5D96"The resulting signature is sent with the request and validated server-side before any action is taken.
This method supports future extensibility — new fields can be added without breaking existing implementations, as long as they're included in the signature calculation.
Core Functionality: Fetching Deposit Addresses
Now that we’ve secured our API layer, let’s focus on the primary business logic: allocating deposit addresses to users.
Each user or application should receive a unique Ethereum address for receiving funds. To manage this efficiently, we maintain a pool of pre-generated addresses in the database.
Address Pool Structure
| id | address | used_flag |
|---|---|---|
| 1 | 0x1 | -1 |
| 2 | 0x2 | 0 |
| 3 | 0x3 | 0 |
| 4 | 0x4 | 0 |
used_flag = 0: Available for assignmentused_flag = -1: Reserved or inactiveused_flag = [product_id]: Assigned to a specific application
When a valid request arrives:
- Begin a database transaction.
- Select the first available address where
used_flag = 0. - Update its
used_flagto the requesting app’sproduct.id. - Commit the transaction.
- Return the assigned address to the client.
This ensures atomicity — no race conditions occur even under high concurrency, and each address is assigned exactly once.
👉 See how top-tier exchanges handle atomic address allocation at scale.
Implementation Overview
The full implementation is open-sourced on GitHub (code reference removed per guidelines), with the main entry point located at cmd/api/main.go. It demonstrates:
- Gin-based routing
- Middleware for signature validation
- Database interaction using raw SQL or ORM patterns
- Concurrent-safe address allocation
While we won’t reproduce the full code here, key components include:
- Middleware that extracts and verifies
app_name,nonce, andsign - Functions to generate
stringAand compute MD5 signatures - Atomic SQL queries using transactions to prevent duplication
Frequently Asked Questions (FAQ)
Q: Why use MD5 instead of SHA-256 for signing?
A: While SHA-256 is cryptographically stronger, MD5 is still acceptable here when combined with a secret key and nonce. However, for new systems, consider upgrading to HMAC-SHA256 for better security.
Q: How do I prevent IP spoofing?
A: Use the whitelist_ip field in t_product to restrict API access by source IP. Combine this with HTTPS and rate limiting for enhanced protection.
Q: Can multiple apps share the same deposit address?
A: No. Each deposit address must be uniquely assigned to avoid fund attribution errors. Sharing addresses breaks accounting isolation.
Q: What happens if two requests arrive simultaneously?
A: Database transactions ensure serializable execution. Only one request will successfully claim an available address.
Q: How often should I rotate the app_sk (secret key)?
A: Rotate keys periodically (e.g., quarterly) or immediately if compromised. Ensure zero-downtime key rotation by supporting dual keys during transition.
Q: Is it safe to expose deposit addresses publicly?
A: Yes. Ethereum deposit addresses are designed to be public. However, never expose private keys or seed phrases.
Final Thoughts and Best Practices
Building a secure ETH exchange wallet backend requires more than just blockchain integration — it demands attention to authentication, data integrity, and operational reliability.
By implementing strong signature validation, maintaining a clean separation between available and assigned addresses, and leveraging database transactions, you create a foundation that scales securely.
As your platform grows, consider adding:
- Rate limiting per app
- Logging and audit trails
- Automated health checks
- Support for additional EVM-compatible chains
👉 Explore enterprise-grade tools for managing multi-chain deposit systems securely.
With these practices in place, your system will not only resist common attacks but also provide a reliable experience for developers and end users alike.
Core Keywords:
- Ethereum ETH wallet development
- Deposit address generation
- API signature verification
- Secure blockchain integration
- RESTful API for crypto
- Address allocation system
- Go Gin framework
- Cryptocurrency exchange backend