# Demo
# Go
package main
import (
"bytes"
"crypto/hmac"
"crypto/sha1"
"encoding/base64"
"encoding/json"
"fmt"
"io/ioutil"
"math/rand"
"net/http"
"reflect"
"sort"
"strconv"
"strings"
"time"
)
const (
AccessKey string = "RfV6BKQb"
SecretKey string = "b326231bf57bdcc4060d9bf05634b59535ad5d85"
BaseUrl string = "http://192.168.1.75:18713"
ApiPath string = "/api/v3/wallet/pay"
)
type CryptoPayment struct {
ExternalOrderId string `json:"externalOrderId,omitempty" binding:"required,max=64"`
CashierChainType string `json:"cashierChainType,omitempty" binding:"omitempty,oneof=ETH TRON BSC"`
CashierTokenType string `json:"cashierTokenType,omitempty" binding:"omitempty,oneof=USDT USDC TUSD BUSD"`
CashierCryptoAmount string `json:"cashierCryptoAmount,omitempty" binding:"omitempty,amountCrypto" err:"cant be more than 6 decimal"`
CashierCurrencyAmount string `json:"cashierCurrencyAmount,omitempty" binding:"omitempty,amountCurrency" err:"cant be more than 2 decimal"`
CashierCurrencyType string `json:"cashierCurrencyType,omitempty" binding:"omitempty,oneof=USD BRL"`
HiddenMerchantLogo *int64 `json:"hiddenMerchantLogo" binding:"omitempty,oneof=0 1"`
HiddenMerchantName *int64 `json:"hiddenMerchantName" binding:"omitempty,oneof=0 1"`
NotifyUrl string `json:"notifyUrl,omitempty" binding:"omitempty,url"`
Remark string `json:"remark,omitempty" binding:"omitempty,max=1024"`
}
func main() {
params := make(map[string]string)
// header params
params["access_key"] = AccessKey
params["timestamp"] = strconv.FormatInt(time.Now().UnixMilli(), 10)
params["nonce"] = randStr(36)
// Params body struct
var yes int64
yes = 1
payment := CryptoPayment{
ExternalOrderId: randStr(32),
CashierChainType: "TRON",
CashierTokenType: "USDT",
CashierCryptoAmount: "19.06",
HiddenMerchantLogo: &yes,
HiddenMerchantName: &yes,
NotifyUrl: "http://127.0.0.1/callback.go",
Remark: "测试生成",
}
// Params body json string
jsonStr, _ := json.Marshal(payment)
// trans json string to map
jsonMap := reflectJson2Map(string(jsonStr))
for key, value := range jsonMap {
params[key] = value
}
// sort params
var sortKeys []string
for k := range params {
if params[k] != "" {
sortKeys = append(sortKeys, k)
}
}
sort.Strings(sortKeys)
// combine params
var finalStrForSign string
for _, k := range sortKeys {
finalStrForSign = finalStrForSign + k + "=" + params[k] + "&"
}
// trim last &
finalStrForSign = strings.TrimRight(finalStrForSign, "&")
fmt.Printf("combine params: %s\n", finalStrForSign)
// Sign
key := []byte(SecretKey)
mac := hmac.New(sha1.New, key)
mac.Write([]byte(finalStrForSign))
// Base64
sign := base64.StdEncoding.EncodeToString(mac.Sum(nil))
fmt.Printf("sign result: %s\n", sign)
// create request use post method
request, _ := http.NewRequest("POST", BaseUrl+ApiPath, bytes.NewBuffer([]byte(jsonStr)))
request.Header.Set("Content-type", "application/json;charset=utf-8")
request.Header.Set("sign", sign)
request.Header.Set("access_key", params["access_key"])
request.Header.Set("timestamp", params["timestamp"])
request.Header.Set("nonce", params["nonce"])
// request
resp, _ := http.DefaultClient.Do(request)
defer resp.Body.Close()
bodyData, _ := ioutil.ReadAll(resp.Body)
fmt.Printf("response body: %s\n", string(bodyData))
}
// json trans to map
func reflectJson2Map(j string) map[string]string {
params := make(map[string]string)
var event map[string]interface{}
decoder := json.NewDecoder(bytes.NewBufferString(j))
decoder.UseNumber()
err := decoder.Decode(&event)
if err != nil {
return nil
}
for k, v := range event {
params[k] = fmt.Sprintf("%v", reflect.ValueOf(v))
}
return params
}
// struct trans to map
func reflectStruct2Map(s interface{}) map[string]string {
marshal, err := json.Marshal(s)
if err != nil {
return nil
}
params := reflectJson2Map(string(marshal))
return params
}
// gen random string
func randStr(length int) string {
var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
b := make([]rune, length)
for i := range b {
b[i] = letters[rand.Intn(len(letters))]
}
return string(b)
}
# Java
package io.hambit;
import com.alibaba.fastjson.JSON;
import sun.misc.BASE64Encoder;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
public class JavaHambitDemo {
final static String ACCESS_KEY = "RfV6BKQb";
final static String SECRET_KEY = "b326231bf57bdcc4060d9bf05634b59535ad5d85";
final static String BASE_URL = "http://192.168.1.75:18713";
final static String API_PATH = "/api/v3/wallet/pay";
public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException, IOException {
Map map = ParamsSortMap.getSortMap();
// Params header
map.put("access_key", ACCESS_KEY);
map.put("timestamp",String.valueOf(System.currentTimeMillis()));
map.put("nonce", UUID.randomUUID().toString().trim());
CryptoPayment cryptoPayment = new CryptoPayment();
cryptoPayment.setCashierChainType("ETH");
cryptoPayment.setCashierTokenType("USDT");
cryptoPayment.setCashierCryptoAmount("100.008");
cryptoPayment.setExternalOrderId(UUID.randomUUID().toString().trim().replace("-",""));
cryptoPayment.setNotifyUrl("http://192.168.1.75:18713/api/v3/wallet/pay/notify");
cryptoPayment.setRemark("remark");
cryptoPayment.setHiddenMerchantLogo(1);
cryptoPayment.setHiddenMerchantName(1);
// trans to json string use alibaba fastjson lib
String jsonString = JSON.toJSONString(cryptoPayment);
// trans to json map
Map _map = (Map) JSON.parse(jsonString);
for (Object key : _map.keySet()) {
map.put(key, _map.get(key));
}
// Combine
Set keySet = map.keySet();
String finalStrForSign = "";
for (Object next : keySet) {
finalStrForSign = finalStrForSign + next + "=" + map.get(next) + "&";
}
finalStrForSign = finalStrForSign.substring(0, finalStrForSign.length() - 1);
System.out.println("combine params: " + finalStrForSign);
// Sign
SecretKeySpec secretKeySpec = new SecretKeySpec(SECRET_KEY.getBytes(StandardCharsets.UTF_8), "HmacSHA1");
Mac hmac = Mac.getInstance("HmacSHA1");
hmac.init(secretKeySpec);
byte[] hash = hmac.doFinal(finalStrForSign.getBytes(StandardCharsets.UTF_8));
// Base64
String sign = new BASE64Encoder().encodeBuffer(hash);
System.out.println("sign result: " + sign);
// Http if you use other http client library, may be had some diff
String accessUrl = BASE_URL + API_PATH;
URL url = new URL(accessUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setUseCaches(false);
connection.setConnectTimeout(1000 * 5);
connection.setReadTimeout(1000 * 60);
connection.setInstanceFollowRedirects(true);
// Set header
connection.setRequestProperty("Content-type", "application/json;charset=utf-8");
connection.setRequestProperty("sign", sign.replaceAll("\n",""));
connection.setRequestProperty("access_key", ACCESS_KEY);
connection.setRequestProperty("timestamp", map.get("timestamp").toString());
connection.setRequestProperty("nonce", map.get("nonce").toString());
// connect
connection.connect();
// write json string
OutputStream out =connection.getOutputStream();
out.write(jsonString.getBytes());
out.flush();
InputStream in = connection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in));
StringBuilder response = new StringBuilder();
String tmp;
while ((tmp = bufferedReader.readLine()) != null) {
response.append(tmp);
}
in.close();
out.close();
bufferedReader.close();
connection.disconnect();
System.out.println("response body: " + response);
}
}
class CryptoPayment {
private String externalOrderId;
private String cashierChainType;
private String cashierTokenType;
private String cashierCryptoAmount;
private String cashierCurrencyAmount;
private String cashierCurrencyType;
private int hiddenMerchantLogo;
private int hiddenMerchantName;
private String notifyUrl;
private String remark;
public String getExternalOrderId() {
return externalOrderId;
}
public void setExternalOrderId(String externalOrderId) {
this.externalOrderId = externalOrderId;
}
public String getCashierChainType() {
return cashierChainType;
}
public void setCashierChainType(String cashierChainType) {
this.cashierChainType = cashierChainType;
}
public String getCashierTokenType() {
return cashierTokenType;
}
public void setCashierTokenType(String cashierTokenType) {
this.cashierTokenType = cashierTokenType;
}
public String getCashierCryptoAmount() {
return cashierCryptoAmount;
}
public void setCashierCryptoAmount(String cashierCryptoAmount) {
this.cashierCryptoAmount = cashierCryptoAmount;
}
public String getCashierCurrencyAmount() {
return cashierCurrencyAmount;
}
public void setCashierCurrencyAmount(String cashierCurrencyAmount) {
this.cashierCurrencyAmount = cashierCurrencyAmount;
}
public String getCashierCurrencyType() {
return cashierCurrencyType;
}
public void setCashierCurrencyType(String cashierCurrencyType) {
this.cashierCurrencyType = cashierCurrencyType;
}
public int getHiddenMerchantLogo() {
return hiddenMerchantLogo;
}
public void setHiddenMerchantLogo(int hiddenMerchantLogo) {
this.hiddenMerchantLogo = hiddenMerchantLogo;
}
public int getHiddenMerchantName() {
return hiddenMerchantName;
}
public void setHiddenMerchantName(int hiddenMerchantName) {
this.hiddenMerchantName = hiddenMerchantName;
}
public String getNotifyUrl() {
return notifyUrl;
}
public void setNotifyUrl(String notifyUrl) {
this.notifyUrl = notifyUrl;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
}
class ParamsSortMap {
public static Map getSortMap() {
return new TreeMap<>(new AccsiiAscComparator());
}
}
class AccsiiAscComparator implements Comparator {
@Override
public int compare(Object str1, Object str2) {
return str1.toString().compareTo(str2.toString());
}
}
# Python
import base64
import hmac
import json
import random
import time
from hashlib import sha1
from urllib import parse
import urllib.request
ACCESS_KEY = "RfV6BKQb"
SECRET_KEY = "b326231bf57bdcc4060d9bf05634b59535ad5d85"
BASE_URL = "http://192.168.1.75:18713"
API_PATH = "/api/v3/wallet/pay"
def hash_hmac(key, str, algorithm):
hmac_code = hmac.new(key.encode(), str.encode(), algorithm).digest()
return base64.b64encode(hmac_code).decode()
def generate_random_str(random_length=16):
random_str = ''
base_str = 'ABCDEFGHIGKLMNOPQRSTUVWXYZabcdefghigklmnopqrstuvwxyz0123456789'
length = len(base_str) - 1
for i in range(random_length):
random_str += base_str[random.randint(0, length)]
return random_str
if __name__ == '__main__':
body = dict()
params = dict()
# header
params["access_key"] = ACCESS_KEY
params["timestamp"] = str(round(time.time() * 1000))
params["nonce"] = generate_random_str(36)
# body
body["externalOrderId"] = generate_random_str(32)
body["cashierChainType"] = "BSC"
body["cashierTokenType"] = "USDC"
body["cashierCryptoAmount"] = "19.0087"
body["hiddenMerchantLogo"] = 1
body["notifyUrl"] = "https://payment.hambit.io/callback/do"
body["hiddenMerchantName"] = 1
body["remark"] = "测试代码"
# foreach key in body
for key in body:
params[key] = body[key]
# Sort and Combine
keys = sorted(params.keys())
qs0 = '&'.join(['%s=%s' % (key, params[key]) for key in keys])
# need replace Boolean because python boolean output True False
qs0 = qs0.replace("True", "true").replace("False", "false")
print("sign string: " + qs0)
# Sign
sign = hash_hmac(SECRET_KEY, qs0, sha1)
print("sign result: " + sign)
# request
header = {
'access_key': ACCESS_KEY,
'timestamp': params["timestamp"],
'nonce': params["nonce"],
'sign': sign,
'Content-Type': 'application/json;charset=utf-8',
}
URL = BASE_URL + API_PATH
request = urllib.request.Request(url=URL, headers=header)
file = urllib.request.urlopen(request, json.dumps(body).encode("utf-8", 'ignore'))
print("response body: " + file.read().decode("utf-8", 'ignore'))
# PHP
<?php
function get_rand_str($length): string
{
$str = 'ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghilkmnopqrstuvwxyz1234567890';
$randStr = str_shuffle($str);
$rand= substr($randStr,0,$length);
return $rand;
}
$AccessKey = "RfV6BKQb";
$SecretKey = "b326231bf57bdcc4060d9bf05634b59535ad5d85";
$BaseUrl = "http://192.168.1.75:18713";
$ApiPath = "/api/v3/wallet/pay";
$params = array(
'access_key' => $AccessKey,
'timestamp' => (int)(microtime(true)*1000),
'nonce' => get_rand_str(36),
'externalOrderId' => get_rand_str(32),
'cashierChainType' => 'ETH',
'cashierTokenType' => 'USDC',
'cashierCryptoAmount' => '19.987',
'hiddenMerchantLogo' => 1,
'hiddenMerchantName' => 1,
'notifyUrl' => 'https://www.example.com/notify',
'remark' => 'USER',
);
ksort($params);
// Encode and Combine
global $paramString;
foreach ($params as $key => $value) {
$paramString .= $key.'='. $value .'&';
}
$paramString = substr($paramString,0,-1);
$sign = base64_encode(hash_hmac("sha1", $paramString, $SecretKey, $raw_output=TRUE));
print "sign string: " .$paramString . "\n";
print "sign result: " .$sign. "\n";
// Http
$method ="POST";
$curl = curl_init($BaseUrl.$ApiPath);
// Header
$headers = [
'sign: '. $sign,
'access_key: ' .$AccessKey,
'timestamp: ' .$params['timestamp'],
'nonce: ' .$params['nonce'],
'Content-Type: application/json;charset=utf-8',
];
// remove header params
unset($params['access_key']);
unset($params['timestamp']);
unset($params['nonce']);
// post request
$payload = json_encode($params);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
curl_setopt($curl, CURLOPT_POSTFIELDS, $payload);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
$server_output = curl_exec ($curl);
curl_close ($curl);
# C#
using System;
using System.Runtime.InteropServices;
using System.Net.Http.Headers;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json.Nodes;
using Newtonsoft.Json;
String ACCESS_KEY = "RfV6BKQb";
String SECRET_KEY = "b326231bf57bdcc4060d9bf05634b59535ad5d85";
String BASE_URL = "http://192.168.1.75:18713";
String API_PATH = "/api/v3/wallet/pay";
// Params header
Dictionary<string, object> dic = new Dictionary<string, object>();
string chars = "ABCDEFGHIJKLMNOPQRSTUWVXYZ0123456789abcdefghijklmnopqrstuvwxyz";
Random random = new Random();
dic.Add("access_key", ACCESS_KEY);
dic.Add("timestamp", DateTimeOffset.Now.ToUnixTimeMilliseconds().ToString());
dic.Add("nonce", new string(Enumerable.Repeat(chars, 36).Select(s => s[random.Next(chars.Length)]).ToArray()));
// Body
dic.Add("externalOrderId", new string(Enumerable.Repeat(chars, 32).Select(s => s[random.Next(chars.Length)]).ToArray()));
dic.Add("cashierChainType", "BSC");
dic.Add("cashierTokenType", "BUSD");
dic.Add("cashierCryptoAmount", "99.998");
dic.Add("hiddenMerchantLogo", 1);
dic.Add("notifyUrl", "https://payment.hambit.io/callback/do");
dic.Add("hiddenMerchantName", 1);
dic.Add("remark", "测试代码");
// Sort and Combine
String finalStrForSign = "";
var sortDic = dic.OrderBy(x => x.Key, new OrdinalComparer()).ToDictionary(x => x.Key, y => y.Value);
foreach (KeyValuePair<string, Object> kvp in sortDic)
{
finalStrForSign += kvp.Key + "=" +kvp.Value + "&";
}
finalStrForSign = finalStrForSign.Substring(0, finalStrForSign.Length - 1);
Console.WriteLine("sign string: " + finalStrForSign);
// Sign
HMACSHA1 _hMacSha1 = new HMACSHA1(System.Text.Encoding.UTF8.GetBytes(SECRET_KEY));
byte[] inputBuffer = System.Text.Encoding.UTF8.GetBytes(finalStrForSign);
byte[] hashedBuffer = _hMacSha1.ComputeHash(inputBuffer);
String sign = Convert.ToBase64String(hashedBuffer);
Console.WriteLine("sign result: " + sign);
// Http if you use other http client library, may be had diff
HttpClient _httpClient = new HttpClient();
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
_httpClient.DefaultRequestHeaders.Add("sign", sign);
_httpClient.DefaultRequestHeaders.Add("access_key", ACCESS_KEY);
_httpClient.DefaultRequestHeaders.Add("timestamp", dic["timestamp"].ToString());
_httpClient.DefaultRequestHeaders.Add("nonce", dic["nonce"].ToString());
// remove header params
dic.Remove("access_key");
dic.Remove("timestamp");
dic.Remove("nonce");
var content = new StringContent(JsonConvert.SerializeObject(dic), Encoding.UTF8, "application/json");
// Http Request
var response = await _httpClient.PostAsync(BASE_URL + API_PATH, content);
Console.WriteLine(response.EnsureSuccessStatusCode());
Console.WriteLine(response.Content.ReadAsStringAsync().Result);
public class OrdinalComparer : System.Collections.Generic.IComparer<String>
{
public int Compare(String x, String y)
{
return string.CompareOrdinal(x, y);
}
}
# Node.js
import crypto from 'crypto';
import fetch from 'node-fetch';
function getRandStr(length) {
const str = 'ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghilkmnopqrstuvwxyz1234567890';
const randStr = str.split('').sort(() => 0.5 - Math.random()).join('');
return randStr.substr(0, length);
}
const AccessKey = "RfV6BKQb";
const SecretKey = "b326231bf57bdcc4060d9bf05634b59535ad5d85";
const BaseUrl = "http://192.168.1.75:18713";
const ApiPath = "/api/v3/wallet/pay";
const params = {
access_key: AccessKey,
timestamp: Math.floor(new Date().getTime()),
nonce: getRandStr(36),
externalOrderId: getRandStr(32),
cashierChainType: 'ETH',
cashierTokenType: 'USDC',
cashierCryptoAmount: '19.987',
hiddenMerchantLogo: 1,
hiddenMerchantName: 1,
notifyUrl: 'https://www.example.com/notify',
remark: 'USER'
};
const paramString = Object.keys(params)
.sort()
.map(key => `${key}=${params[key]}`)
.join('&');
const sign = crypto.createHmac('sha1', SecretKey)
.update(paramString)
.digest('base64');
console.log("sign string: " + paramString);
console.log("sign result: " + sign);
const method = "POST";
const headers = {
'sign': sign,
'access_key': AccessKey,
'timestamp': params.timestamp.toString(),
'nonce': params.nonce,
'Content-Type': 'application/json;charset=utf-8'
};
delete params.access_key;
delete params.timestamp;
delete params.nonce;
const payload = JSON.stringify(params);
fetch(BaseUrl + ApiPath, {
method: method,
headers: headers,
body: payload
})
.then(response => response.text())
.then(data => {
console.log(data);
})
.catch(error => {
console.error(error);
});