記錄一個使用第三方USDT支付通道的PHP專案的開發過程及解決方案

dikena發表於2024-09-29
  1. 專案的需求背景
    接到一個專案,需要收付USDT,顧客要求用幣安鏈的,即BSC鏈,需要實現:

充值監控:當使用者透過區塊鏈錢包將 USDT 轉賬到指定地址時,系統能夠監控並確認充值到賬。
提現功能:當使用者發起提現請求時,系統能夠根據使用者指定的地址,自動完成 USDT 的轉賬操作。
交易安全性:確保每筆交易都具有合法性,防止雙花攻擊或偽造交易。

要是都自己做,費錢費力還容易出問題,還是用第三方USDT支付通道吧。想起以前同事用過UBAO.IO,用起來還不錯,還是使用UBAO吧。註冊地址:https://m.ubao.io/#/login?c=8YmVrlk 。註冊後儲存商戶號和API_SECRET備用。

  1. 開發過程
    程式碼,用PHP。商業邏輯,倒也沒什麼說的。主要記錄一下支付這一塊。
    想法是,生成一批錢包地址,儲存在本地資料庫中,供會員輪流使用,時限24小時。比如,甲會員需要付款,那就呼叫一個地址A,標記呼叫時間,24小時內,只要地址A進來的USDT,都認為是甲會員所付(這個時間已經很寬鬆了,大多數人付款,時間也就幾分鐘,不會超過半小時)。如果再來乙會員,那就呼叫地址B,依次類推。24小時後,這些地址釋放,供會員輪流呼叫,這樣比較節約地址。畢竟付款的動作,不是每個會員每天都做。

生成地址的程式碼:

//呼叫API生成一個錢包地址 
$url = "https://api.ubao.id/mch/address/create";

$merchantId = "12345"; //商戶號 
$api_key = "123456789"; //商戶金鑰 

$timestamp = time();
//結果:1725607713
$nonce = rand(100000,999999);
//結果:212343

$body_data = array('chainType'=>170,'type'=>0,'callUrl'=>'http://www.xxx.com/callback.html'); 
//把body陣列轉為JSON字串 
$str = json_encode($body_data);
//結果:{"chainType":170,"type":0,"callUrl":"http:\/\/www.xxx.com\/callback.html"}

//再用base64編碼,得到最終的body字串 
$body = base64_encode($str);
//結果:eyJjaGFpblR5cGUiOjE2MCwidHlwZSI6MCwiY2FsbFVybCI6Imh0dHA6XC9cL3d3dy54eHguY29tXC94eHguaHRtbCJ9

//簽名 
$sign = md5($body . $api_key . $nonce . $timestamp);
//結果:5eab870f6a4fea6caabc6e0be4308bf0

//提交給閘道器的資料  
$data = array('merchantId'=>$merchantId,'timestamp'=>$timestamp,'nonce'=>$nonce,'sign'=>$sign,'body'=>$body);

//用POST方式提交給閘道器 
$res = curlPost($url,$data);
//結果:{"code":200,"message":"SUCCESS","address":"0xD3b0d838cCCEAe7ebF1781D11D1bB741DB7Fe1A8","chainType":170}
//這個address ,就是錢包地址,儲存到本地資料庫。如果需要更多地址,再呼叫就是。
//......



function curlPost($url, $post_data = array(),$timeout = 5, $header = array("content-type: application/x-www-form-urlencoded"), $data_type = "") {
	$header = empty($header) ? '' : $header;
	if($data_type == 'json'){
		$post_string = json_encode($post_data);
	}elseif($data_type == 'array') {
		$post_string = $post_data;
	}elseif(is_array($post_data)){
		$post_string = http_build_query($post_data, '', '&');
	}
	
	$ch = curl_init();
	curl_setopt($ch, CURLOPT_URL, $url);
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
	curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
	curl_setopt($ch, CURLOPT_POST, true);
	curl_setopt($ch, CURLOPT_POSTFIELDS, $post_string);     
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 
	curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
	$result = curl_exec($ch);
	curl_close($ch);
	
	return $result;
}

3.如果有會員付款,UBAO會通知上面留下的回撥地址 http://www.xxx.com/callback.html 。然後在這個程式裡處理一下。

$api_key = "123456789"; //商戶金鑰 

$body = $_POST['body'];
$sign = $_POST['sign'];
$nonce = $_POST['nonce'];
$timestamp = $_POST['timestamp'];

$msg = "";

try {
	$sign2 = md5($body . $api_key . $nonce . $timestamp);
	
	if($sign2 != $sign){
		$msg = "sign error";
		throw new Exception();
	}
	
	$json = json_decode(base64_decode($body),true);
	
	$decimals = $json['decimals'];
	$amount = number_format($json['amount']/pow(10,$decimals),3,'.','') + 0;
	
	if($json['callbackType'] == 'recharge'){
	    //充幣的業務邏輯處理 
                                if($json['chainType'] == 170 && $json['coinID'] == 1002){ //幣安鏈的USDT
                                    $address = $json['address'];//收款的地址
                                    //找到本地資料庫記錄的鎖定此地址的會員,將他的付款狀態改為付款成功。
                                    。。。。
                                }
	}
	
	if($json['callbackType'] == 'transfer'){
	    //提幣或轉賬的業務邏輯處理 
		if($json['result'] == 1){
			//轉賬成功 
		}
		else{
			//轉賬失敗 
			$msg = $json['message'];
		}
	}
	
	if($json['callbackType'] == 'balance'){
	    //得到地址餘額的業務邏輯處理 
	}
	
	$msg = "SUCCESS";
	
}
catch (Exception $e) {
	//
}

echo $msg;
  1. 測試與後記
    測試起來,挺順利。顧客也挺滿意。收尾款,收工。至於說以後可用地址不足,讓他花錢升級就是了。也不麻煩。

相關文章