USDT Recharge via BTC Network (Non-Node Wallet Address) Implementation Guide

ยท

Integrating USDT (Tether) deposits over the Bitcoin blockchain using the Omni Layer protocol is a common requirement for platforms offering cryptocurrency deposit functionality. This guide walks you through a secure, scalable approach to implementing USDT recharge via the BTC network, focusing on backend logic, transaction verification, database design, and automated confirmation using scheduled tasks.

Whether you're building a digital asset platform, exchange, or wallet service, understanding how to verify USDT transactions accurately is essential for ensuring fund integrity and user trust.


How USDT Recharge on BTC Network Works

USDT issued on the Bitcoin blockchain operates via the Omni Layer protocol, a decentralized platform built on top of Bitcoin. Unlike ERC-20 USDT (on Ethereum), Omni-based USDT transactions occur within Bitcoin blocks, making them slower but widely supported across exchanges.

When a user wants to deposit USDT into your system:

  1. They initiate a transfer from an external wallet or exchange.
  2. The transaction is broadcasted to the Bitcoin network.
  3. Your system listens for this transaction using the Omni protocol.
  4. Once confirmed, your backend validates sender, recipient, amount, and timestamp before crediting the user.
โš ๏ธ Important: Only accept deposits from pre-registered addresses. Allowing arbitrary addresses increases risk of fraud or mistaken deposits.

๐Ÿ‘‰ Discover how leading platforms manage cross-chain deposits securely.


Core Database Design for Recharge Tracking

To track incoming USDT deposits reliably, use a structured database schema that captures all relevant transaction metadata.

CREATE TABLE `yy_recharge` (
 `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
 `user_id` int(11) DEFAULT NULL COMMENT 'User ID',
 `order_num` varchar(255) DEFAULT NULL COMMENT 'Recharge order number',
 `usdt_order_num` varchar(255) DEFAULT NULL COMMENT 'USDT transaction hash (txid)',
 `money` decimal(18,8) NOT NULL DEFAULT '0.00000000' COMMENT 'Deposit amount',
 `sender` varchar(255) DEFAULT NULL COMMENT 'Sender wallet address',
 `recipient` varchar(255) DEFAULT NULL COMMENT 'Recipient wallet address',
 `status` tinyint(4) DEFAULT '1' COMMENT 'Status: 1=pending, 2=confirmed, 3=failed',
 `create_time` datetime DEFAULT NULL COMMENT 'Order creation time',
 `qr_time` datetime DEFAULT NULL COMMENT 'Confirmation time',
 `block_time` datetime DEFAULT NULL COMMENT 'Blockchain transaction time',
 `block_t_time` varchar(255) DEFAULT '' COMMENT 'Blockchain timestamp',
 `remarks` varchar(255) DEFAULT NULL COMMENT 'Failure reason or notes',
 PRIMARY KEY (`id`),
 UNIQUE KEY `ordernum` (`order_num`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Key Fields Explained:


Verifying Transactions with omni_gettransaction

The omni_gettransaction RPC method retrieves full details of a specific USDT transfer on the Bitcoin network.

Example Response:

[
 "txid" => "c41525d0de0b5d5668f44995570184e6a4c52931a0ebb7e10205676f6bb9a40f",
 "fee" => "0.00015975",
 "sendingaddress" => "3KeC2JqGHqW6kuUBJKjAHmmfUThj2RiR1F",
 "referenceaddress" => "18An5WWLHR59NpHdKzPoDjKLKULsMpP1ci",
 "ismine" => true,
 "type" => "Simple Send",
 "amount" => "0.10000000",
 "valid" => true,
 "blocktime" => 1560766900,
 "confirmations" => 36
]

Critical Validation Checks:

Ensure all of the following conditions pass before marking a deposit as successful:


Automating Deposit Confirmation with Scheduled Tasks

Manually checking transactions isn't scalable. Use a scheduled task (cron job or Swoole timer) to periodically scan pending deposits and verify their status.

PHP + Swoole Example: Auto-Recharge Task

protected function execute(Input $input, Output $output)
{
    $id = \swoole_timer_tick(5000, function () {
        try {
            $pendingDeposits = Db::name('recharge')
                ->where(['status' => 1, 'usdt_order_num' => ['<>', '']])
                ->select();

            foreach ($pendingDeposits as $deposit) {
                $usdtClient = (new Coins())->getCoins();
                $txData = $usdtClient->omni_gettransaction($deposit['usdt_order_num']);

                if (!is_array($txData)) {
                    Db::name('recharge')->where(['id' => $deposit['id']])->update(['status' => 3, 'remarks' => 'Invalid transaction hash']);
                    continue;
                }

                // Validate amount
                if ($txData['amount'] != $deposit['money']) {
                    updateAsFailed($deposit['id'], 'Amount mismatch');
                    continue;
                }

                // Ensure transaction occurred after order creation
                $createTime = strtotime($deposit['create_time']);
                if ($txData['blocktime'] < $createTime) {
                    updateAsFailed($deposit['id'], 'Suspicious early transfer');
                    continue;
                }

                // Confirm recipient address
                if ($txData['referenceaddress'] != $deposit['recipient']) {
                    updateAsFailed($deposit['id'], 'Wrong recipient address');
                    continue;
                }

                // Final validation
                if ($txData['valid']) {
                    // Mark as confirmed
                    Db::name('recharge')->where(['id' => $deposit['id']])->update([
                        'status' => 2,
                        'qr_time' => date('YmdHis'),
                        'block_t_time' => $txData['blocktime'],
                        'block_time' => date('Y-m-d H:i:s', $txData['blocktime'])
                    ]);

                    // Credit user balance
                    Db::name('users_asset')->where(['user_id' => $deposit['user_id']])->setInc('usdt', $deposit['money']);

                    // Log transaction
                    $log = [
                        'user_id' => $deposit['user_id'],
                        'money' => $deposit['money'],
                        'type' => 1,
                        'message' => 'Deposit confirmed',
                        'status' => 2,
                        'class' => 2,
                        'create_time' => date('YmdHis')
                    ];
                    Db::name('users_account_log')->insert($log);
                } else {
                    updateAsFailed($deposit['id'], 'Blockchain validation failed');
                }
            }
        } catch (Exception $e) {
            file_put_contents('recharge.log', date('Y-m-d H:i:s') . $e->getMessage() . PHP_EOL, FILE_APPEND);
        }
    });
}

This script runs every 5 seconds, checks all pending deposits, and updates their status based on blockchain data.

๐Ÿ‘‰ Explore real-time blockchain monitoring tools used by top-tier platforms.


Frequently Asked Questions (FAQ)

Q1: Can I accept USDT deposits from any wallet?

No. Only allow deposits from pre-approved addresses linked to the user account. Accepting random addresses opens your platform to scams or accidental transfers you canโ€™t reconcile.

Q2: Why use Omni USDT instead of ERC-20 or TRC-20?

Omni USDT runs on Bitcoinโ€™s secure network and is supported by many legacy exchanges. However, it has higher fees and slower confirmations than TRC-20 or ERC-20 variants. Choose based on your target user base and infrastructure.

Q3: What does โ€œconfirmationsโ€ mean in Omni transactions?

Each confirmation represents a new Bitcoin block added after the transaction block. Most systems require at least 2โ€“6 confirmations before considering a deposit final.

Q4: How do I handle partial or incorrect deposits?

If the amount doesn't match exactly, flag the transaction as failed with a note like "Incorrect amount sent." You can optionally notify support for manual review โ€” but never auto-credit mismatched amounts.

Q5: Is there a risk in using Swoole timers?

Swoole offers high performance but requires proper error handling and logging. Always wrap logic in try-catch blocks and monitor logs regularly to detect failures early.

Q6: How often should I run the verification task?

Running every 5โ€“10 seconds strikes a balance between responsiveness and server load. Adjust based on traffic volume and system resources.


Best Practices for Secure USDT Integration


Final Thoughts

Implementing a robust USDT recharge system over the BTC network requires careful planning around security, automation, and validation. By leveraging omni_gettransaction, designing a clear database model, and automating checks via scheduled tasks, you can build a reliable deposit pipeline that scales with your platform.

As digital assets evolve, maintaining accurate, secure deposit processing remains critical to user satisfaction and operational integrity.

๐Ÿ‘‰ Learn how modern platforms streamline multi-chain deposit workflows today.