In cryptocurrency exchange operations, efficient and secure asset management is critical. One essential component of this process is coin consolidation—the systematic transfer of fragmented user deposits from hot wallets to secure cold storage. This not only reduces exposure to potential hacks but also streamlines accounting and improves overall fund control.
This article dives into the technical workflow behind Ethereum (ETH) coin consolidation, covering transaction generation, broadcasting, and confirmation tracking. We'll explore how exchanges aggregate small incoming deposits, construct optimized transactions, and ensure reliable fund movement—all while minimizing gas costs and avoiding duplicate processing.
Whether you're building a wallet system or enhancing an existing exchange infrastructure, understanding this backend mechanism is crucial for scalability and security.
👉 Discover how professional platforms manage Ethereum transactions efficiently.
Understanding the Need for Coin Consolidation
When users deposit ETH into an exchange, funds typically arrive in small, frequent amounts across multiple addresses. Over time, this leads to fragmented balances spread across numerous hot wallet addresses. Leaving these funds unmanaged increases security risks and operational inefficiencies.
To mitigate this:
- Security: Moving funds to cold wallets limits exposure to online threats.
- Efficiency: Consolidating small balances reduces future transaction overhead.
- Cost Optimization: Batching transfers from the same source address lowers total gas consumption.
The goal of coin consolidation is to automatically collect scattered ETH from deposit addresses and send them to a centralized cold wallet—securely and cost-effectively.
Step 1: Generating Consolidation Transactions
Tracking Deposit Records
All incoming deposits are recorded in a database table called t_tx. Each entry includes:
- Transaction hash
- Deposit address
- Amount (in ETH and Wei)
- Consolidation status (0 = pending, 1 = processed)
Example data:
| id | tx_hash | deposit_addr | amount_eth | status |
|----|---------|--------------|------------|--------|
| 1 | 0x1 | 0xa | 0.11 | 0 |
| 2 | 0x2 | 0xb | 0.12 | 0 |
| 3 | 0x3 | 0xa | 0.08 | 0 |
| 4 | 0x4 | 0xc | 0.17 | 0 |Notice that address 0xa appears twice. Instead of sending two separate transactions, we combine both deposits into a single transfer—reducing gas fees and blockchain congestion.
Database Schema for Outbound Transactions
Once consolidation plans are generated, they are stored in the t_send table:
CREATE TABLE `t_send` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`related_type` tinyint(4) NOT NULL COMMENT '1: consolidation, 2: withdrawal',
`related_id` int(11) unsigned NOT NULL COMMENT 'Reference ID',
`tx_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Transaction hash',
`from_address` varchar(128) NOT NULL DEFAULT '' COMMENT 'Sender address',
`to_address` varchar(128) NOT NULL DEFAULT '' COMMENT 'Receiver (cold wallet)',
`balance` bigint(20) NOT NULL COMMENT 'Amount in Wei',
`balance_real` varchar(128) NOT NULL COMMENT 'Amount in Ether',
`gas` bigint(20) NOT NULL COMMENT 'Gas limit',
`gas_price` bigint(20) NOT NULL COMMENT 'Gas price in Wei',
`nonce` int(11) NOT NULL COMMENT 'Transaction nonce',
`hex` varchar(2048) NOT NULL COMMENT 'Signed raw transaction hex',
`create_time` bigint(20) NOT NULL COMMENT 'Creation timestamp',
`handle_status` tinyint(4) NOT NULL COMMENT 'Processing status',
`handle_msg` varchar(1024) NOT NULL DEFAULT '' COMMENT 'Error/log message',
`handle_time` bigint(20) NOT NULL COMMENT 'Last handled timestamp',
PRIMARY KEY (`id`),
UNIQUE KEY `related_id` (`related_id`,`related_type`) USING BTREE,
KEY `tx_id` (`tx_id`) USING BTREE,
KEY `t_send_from_address_idx` (`from_address`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;This schema ensures traceability, prevents duplication via unique constraints, and supports fast lookups during execution.
Core Processing Logic
Here’s how the system generates consolidation transactions:
- Fetch Pending Deposits: Query all records in
t_txwherestatus = 0. - Group by Address: Aggregate amounts by
deposit_addrusing a map:map[address]sum(amount). Process Each Group:
- Retrieve the private key for the deposit address (securely from a key management system).
- Ensure the total balance exceeds estimated gas costs.
Determine the correct nonce:
Use the maximum of:
- Last used nonce from the database (+1)
- Current nonce from Ethereum node via RPC (
eth_getTransactionCount)
- Construct and sign the transaction using Ethereum’s
types.NewTransactionandSignTx.
Key Code Snippet: Signing the Transaction
var data []byte
tx := types.NewTransaction(
uint64(nonce),
coldAddress,
big.NewInt(sendBalance),
uint64(gasLimit),
big.NewInt(gasPrice),
data,
)
chainID, err := ethclient.RpcNetworkID(context.Background())
if err != nil {
hcommon.Log.Warnf("RpcNetworkID err: [%T] %s", err, err.Error())
return
}
signedTx, err := types.SignTx(tx, types.NewEIP155Signer(big.NewInt(chainID)), privateKey)
if err != nil {
hcommon.Log.Warnf("Signing error: [%T] %s", err, err.Error())
return
}
rawTxBytes := new(types.Transactions).GetRlp(0)
rawTxHex := hex.EncodeToString(rawTxBytes)
txHash := strings.ToLower(signedTx.Hash().Hex())Store Signed Transaction:
- For the first record in a group: insert full transaction data into
t_send. - For others: link via
related_idwithout duplicating hex data.
- For the first record in a group: insert full transaction data into
- Update Status: Mark original deposits as “transaction generated” to prevent reprocessing.
👉 Learn how leading crypto platforms optimize transaction workflows.
Step 2: Broadcasting Transactions
After generating signed raw transactions, the next step is broadcasting them to the Ethereum network.
Deserializing Stored Transactions
Each pending transaction is retrieved from t_send, then decoded:
rawTxBytes, err := hex.DecodeString(sendRow.Hex)
if err != nil {
hcommon.Log.Errorf("Decode error: [%T] %s", err, err.Error())
return
}
tx := new(types.Transaction)
err = rlp.DecodeBytes(rawTxBytes, &tx)
if err != nil {
hcommon.Log.Errorf("RLP decode error: [%T] %s", err, err.Error())
return
}Sending via RPC
Using an Ethereum client (e.g., Geth or Infura), broadcast with eth_sendRawTransaction:
txHash := common.HexToHash(txHashStr)
tx, isPending, err := client.TransactionByHash(ctx, txHash)
if err != nil {
return nil, err
}
if isPending {
return nil, nil // Still in mempool
}Upon success:
- Update
t_send.handle_statusto “sent”. - Record timestamp in
handle_time.
Step 3: Monitoring Transaction Confirmations
Even after broadcast, a transaction isn’t final until it’s included in a block.
Confirmation Workflow
- Query all records in
t_sendwith status “sent” but not yet confirmed. Use
TransactionByHashto check inclusion:- If
isPending == falseandtx != nil, the transaction has been mined.
- If
- Update status to “confirmed”.
- Mark associated deposit records in
t_txas fully consolidated.
This loop runs periodically (e.g., every minute) to ensure timely reconciliation.
Core Keywords
- Ethereum wallet development
- ETH coin consolidation
- Exchange cold wallet management
- Raw transaction signing
- Gas optimization for ETH transfers
- Transaction nonce handling
- Blockchain fund aggregation
- Secure key management
Frequently Asked Questions (FAQ)
Q: Why is coin consolidation necessary for exchanges?
A: It enhances security by moving funds off hot wallets and reduces long-term gas costs by batching small deposits into fewer transactions.
Q: How does merging deposits from the same address save gas?
A: Instead of paying gas for multiple small transfers, one larger transfer incurs only a single base fee, improving cost efficiency.
Q: What happens if a consolidation transaction fails?
A: The system detects failure via RPC checks, logs the error, and retries with adjusted gas parameters or corrected nonce.
Q: Can this system handle high-volume deposit traffic?
A: Yes—by using indexed database queries, parallel processing, and rate-limited RPC calls, it scales well under load.
Q: Is there a risk of double-spending during consolidation?
A: No—each transaction uses a unique nonce derived from both local records and blockchain state, preventing collisions.
Q: How often should consolidation run?
A: Typically every few minutes to balance responsiveness with efficiency. Real-time triggers can be added for large deposits.
👉 Explore advanced tools for managing Ethereum transaction pipelines at scale.