使用okex 的dex钱包功能去兑换代币golang实现

77 阅读4分钟

使用golang 使用okex 的dex钱包功能去兑换代币

如果你想接入okex,去okex的dex上交易代币,使用程序实现,参考如下,golang实现 首先安装依赖插件

go mod init test
#复制下面代码放入 test.go 然后执行:
go mod tidy

下面是一段golang代码展示调用okex去兑换代币交易

package main

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/yellomoon/web3tool"
	"github.com/yellomoon/web3tool/jsonrpc"
	"github.com/yellomoon/web3tool/wallet"
	"io/ioutil"
	"math"
	"math/big"
	"net/http"
	"net/url"
	"strconv"
	"time"
)

// Config 存储 API 配置
type Config struct {
	APIKey     string `json:"api_key"`
	Passphrase string `json:"passphrase"`
	Project    string `json:"project"`
	SecretKey  string `json:"secret_key"`
}

// PreHash 生成预签名字符串
func PreHash(timestamp, method, requestPath string, params map[string]string) string {
	queryString := ""
	if method == "GET" && len(params) > 0 {
		tempParms := make(map[string][]string)
		for k, v := range params {
			tempParms[k] = []string{v}
		}
		queryString = "?" + url.Values(tempParms).Encode()
	}
	if method == "POST" && len(params) > 0 {
		jsonData, _ := json.Marshal(params)
		queryString = string(jsonData)
	}
	return timestamp + method + requestPath + queryString
}

// Sign 使用 HMAC-SHA256 对消息进行签名
func Sign(message, secretKey string) string {
	key := []byte(secretKey)
	h := hmac.New(sha256.New, key)
	h.Write([]byte(message))
	return base64.StdEncoding.EncodeToString(h.Sum(nil))
}

// CreateSignature 生成签名和时间戳
func CreateSignature(method, requestPath string, params map[string]string, config Config) map[string]string {
	timestamp := time.Now().UTC().Format("2006-01-02T15:04:05Z")
	message := PreHash(timestamp, method, requestPath, params)
	signature := Sign(message, config.SecretKey)
	return map[string]string{
		"signature": signature,
		"timestamp": timestamp,
	}
}

// SendGetRequest 发送 GET 请求
func SendGetRequest(requestPath string, params map[string]string, config Config) (string, error) {
	// 生成签名
	signatureData := CreateSignature("GET", requestPath, params, config)

	// 构建请求 URL
	requestURL := fmt.Sprintf("https://www.okx.com%s", requestPath)
	tempParms := make(map[string][]string)
	for k, v := range params {
		tempParms[k] = []string{v}
	}
	if len(params) > 0 {
		requestURL += "?" + url.Values(tempParms).Encode()
	}
	proxyURL, _ := url.Parse("http://127.0.0.1:7890")
	// 创建 HTTP 客户端
	client := &http.Client{
		Transport: &http.Transport{
			Proxy: http.ProxyURL(proxyURL),
		},
	}

	// 创建请求
	req, err := http.NewRequest("GET", requestURL, nil)
	if err != nil {
		return "", fmt.Errorf("failed to create request: %v", err)
	}

	// 设置请求头
	req.Header.Set("OK-ACCESS-KEY", config.APIKey)
	req.Header.Set("OK-ACCESS-SIGN", signatureData["signature"])
	req.Header.Set("OK-ACCESS-TIMESTAMP", signatureData["timestamp"])
	req.Header.Set("OK-ACCESS-PASSPHRASE", config.Passphrase)
	req.Header.Set("OK-ACCESS-PROJECT", config.Project)

	// 发送请求
	resp, err := client.Do(req)
	if err != nil {
		return "", fmt.Errorf("failed to send request: %v", err)
	}
	defer resp.Body.Close()

	// 读取响应
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", fmt.Errorf("failed to read response body: %v", err)
	}

	return string(body), nil
}

func SendPostRequest(requestPath string, params map[string]string, config Config) (string, error) {
	// 生成签名
	signatureData := CreateSignature("POST", requestPath, params, config)

	// 构建请求 URL
	requestURL := fmt.Sprintf("https://www.okx.com%s", requestPath)

	// 将参数转换为 JSON
	jsonData, err := json.Marshal(params)
	if err != nil {
		return "", fmt.Errorf("failed to marshal params: %v", err)
	}

	// 创建 HTTP 客户端
	proxyURL, _ := url.Parse("http://127.0.0.1:7890")
	// 创建 HTTP 客户端
	client := &http.Client{
		Transport: &http.Transport{
			Proxy: http.ProxyURL(proxyURL),
		},
	}

	// 创建请求
	req, err := http.NewRequest("POST", requestURL, bytes.NewBuffer(jsonData))
	if err != nil {
		return "", fmt.Errorf("failed to create request: %v", err)
	}

	// 设置请求头
	req.Header.Set("OK-ACCESS-KEY", config.APIKey)
	req.Header.Set("OK-ACCESS-SIGN", signatureData["signature"])
	req.Header.Set("OK-ACCESS-TIMESTAMP", signatureData["timestamp"])
	req.Header.Set("OK-ACCESS-PASSPHRASE", config.Passphrase)
	req.Header.Set("OK-ACCESS-PROJECT", config.Project)
	req.Header.Set("Content-Type", "application/json")

	// 发送请求
	resp, err := client.Do(req)
	if err != nil {
		return "", fmt.Errorf("failed to send request: %v", err)
	}
	defer resp.Body.Close()

	// 读取响应
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", fmt.Errorf("failed to read response body: %v", err)
	}

	return string(body), nil
}

func get_nonce(address, chainIndex string, config Config) (error, string) {
	type Response struct {
		Code string `json:"code"`
		Msg  string `json:"msg"`
		Data []struct {
			Nonce        string `json:"nonce"`
			PendingNonce string `json:"pendingNonce"`
		} `json:"data"`
	}
	// 定义请求路径和参数
	requestPath := "/api/v5/wallet/pre-transaction/nonce"
	params := map[string]string{
		"chainIndex": chainIndex,
		"address":    address,
	}
	// 发送 GET 请求
	responseString, err := SendGetRequest(requestPath, params, config)
	if err != nil {
		fmt.Printf("Error: %v\n", err)
		return err, ""
	}
	var response Response
	err = json.Unmarshal([]byte(responseString), &response)
	if err != nil {
		fmt.Println("JSON 解析失败:", err)
		return err, response.Msg
	}
	for _, item := range response.Data {
		return nil, item.Nonce
	}
	return errors.New("其他错误"), ""
}

func post_transaction(input_data, chainIndex, myAddress string, config Config) (string, error) {
	requestPath := "/api/v5/wallet/pre-transaction/broadcast-transaction"
	params := map[string]string{
		"chainIndex": chainIndex,
		"signedTx":   "0x" + input_data,
		"address":    myAddress,
	}
	res, err := SendPostRequest(requestPath, params, config)
	return res, err
}


func main() {
	var rpcUrl = "https://polygon-mainnet.infura.io/v3/{XXX}" // RPC URL  如果地址不能使用了 请去 https://infura.io 注册账号获取免费的
	var privateKey = "ea9c312161c541758038e374a53147b933d39f504649b82f823285eb0b2ffd6e"
	var myAddress = "0xbf8B5bc7Ea580ca7cEDa5F79F6ef3362134fC695"
	var chainIndex = 56 //56  bsc 网络,137 polygon网络 , 1 eth 主网
	config := Config{
		APIKey:     "",
		Passphrase: "",
		Project:    "",
		SecretKey:  "",
	}
	USDT_DECIMAL := 18
	USDT_AMOUNT := 1
	USDT_ADDRESS := "0x55d398326f99059fF775485246999027B3197955"
	USDC_ADDRESS := "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d"

	var WalletAddress = web3tool.HexToAddress(myAddress).String()
	swap_api := "/api/v5/dex/aggregator/swap"
	var chainIndexStr = strconv.Itoa(chainIndex)
	WalletAddressObj := web3tool.HexToAddress(WalletAddress)
	params := map[string]string{
		"chainId":           chainIndexStr,
		"amount":            strconv.Itoa(USDT_AMOUNT * int(math.Pow10(USDT_DECIMAL))),
		"fromTokenAddress":  USDT_ADDRESS,
		"toTokenAddress":    USDC_ADDRESS,
		"slippage":          "0.005",
		"userWalletAddress": WalletAddress,
	}
	// 发送 GET 请求
	swap_response, err := SendGetRequest(swap_api, params, config)
	if err != nil {
		fmt.Printf("Error: %v\n", err)
		return
	}
	//// 配置 API 凭证
	time.Sleep(1 * time.Second)
	err, nonce := get_nonce(WalletAddress, chainIndexStr, config)
	if err != nil {
		fmt.Printf("Error: %v\n", err)
		return
	}
	fmt.Println("Nonce:", nonce)
	type SwapResponse struct {
		Code string `json:"code"`
		Msg  string `json:"msg"`
		Data []struct {
			RouterResult map[string]interface{} `json:"routerResult"`
			Tx           map[string]interface{} `json:"tx"`
		} `json:"data"`
	}
	var response SwapResponse
	err = json.Unmarshal([]byte(swap_response), &response)
	if err != nil {
		fmt.Println("JSON 解析失败:", err)
		return
	}
	for _, item := range response.Data {
		to, ok := item.Tx["to"].(string)
		if !ok {
			fmt.Println("error:", err)
			return
		}
		data, ok := item.Tx["data"].(string)
		if !ok {
			fmt.Println("error:", err)
			return
		}
		gasPrice, ok := item.Tx["gasPrice"].(string)
		if !ok {
			fmt.Println("error:", err)
			return
		}
		price, _ := strconv.Atoi(gasPrice)

		gastemp, ok := item.Tx["gas"].(string)
		if !ok {
			fmt.Println("error:", err)
			return
		}
		gas, _ := strconv.Atoi(gastemp)
		toAddress := web3tool.HexToAddress(to)
		hex_data, err := hex.DecodeString(data[2:])
		if err != nil {
			fmt.Println("error:", err)
			return
		}
		rnonce, _ := strconv.Atoi(nonce)
		txn := &web3tool.Transaction{
			To:       &toAddress,
			Value:    big.NewInt(0),
			GasPrice: uint64(price),
			Nonce:    uint64(rnonce),
			Input:    hex_data,
			Gas:      uint64(gas),
			ChainID:  big.NewInt(int64(chainIndex)),
			From:     WalletAddressObj,
		}
		msg := &web3tool.CallMsg{
			From:     WalletAddressObj,
			To:       &toAddress,
			Data:     hex_data,
			Value:    big.NewInt(0),
			GasPrice: uint64(price),
		}

		RpcClient, _ := jsonrpc.NewClient(rpcUrl)
		GasLimit, err := RpcClient.Eth().EstimateGas(msg)
		if err != nil {
			fmt.Println("post_transaction err:", err)
			return
		}
		txn.Gas = GasLimit
		privateByte, _ := hex.DecodeString(privateKey)
		key, _ := wallet.NewWalletFromPrivKey(privateByte)
		//signer := wallet.NewEIP155Signer(1) //主网 chainID是1
		signer := wallet.NewEIP155Signer(uint64(chainIndex))
		txn, _ = signer.SignTx(txn, key)
		senddata, _ := txn.MarshalRLPTo(nil)
		time.Sleep(1 * time.Second)
		res, err := post_transaction(hex.EncodeToString(senddata), chainIndexStr, WalletAddress, config)
		if err != nil {
			fmt.Println("post_transaction err:", err)
		}
		hash, _ := txn.GetHash()
		fmt.Printf("%v, hash : %s", res, hash.String())
		break
	}

}


每天学习一点点,遨游在区块链知识海洋里

本文由博客一文多发平台 OpenWrite 发布!