2024-04-11 13:35:17 +01:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
"net/http"
|
|
|
|
"os"
|
|
|
|
"strings"
|
|
|
|
"sync"
|
|
|
|
|
|
|
|
"github.com/lesismal/llib/std/crypto/tls"
|
|
|
|
|
|
|
|
"github.com/deroproject/derohe/globals"
|
|
|
|
"github.com/lesismal/nbio/nbhttp"
|
|
|
|
"github.com/lesismal/nbio/nbhttp/websocket"
|
|
|
|
|
|
|
|
"dero-swap/cfg"
|
|
|
|
"dero-swap/coin"
|
|
|
|
"dero-swap/dero"
|
|
|
|
)
|
|
|
|
|
|
|
|
type WS_Message struct {
|
|
|
|
ID uint64 `json:"id"`
|
|
|
|
Method string `json:"method"`
|
|
|
|
Params any `json:"params,omitempty"`
|
|
|
|
Result any `json:"result"`
|
|
|
|
}
|
|
|
|
|
|
|
|
var WSConnections sync.Map
|
|
|
|
|
|
|
|
// swap other coins to Dero
|
|
|
|
func Dero_Swap(request coin.Swap_Request) (response coin.Swap_Response) {
|
|
|
|
|
|
|
|
var err error
|
|
|
|
|
|
|
|
// check if destination wallet is valid. Registered usernames can also be used.
|
|
|
|
if strings.HasPrefix(request.DeroAddr, "dero1") || strings.HasPrefix(request.DeroAddr, "deroi") {
|
|
|
|
_, err = globals.ParseValidateAddress(request.DeroAddr)
|
|
|
|
} else {
|
|
|
|
if addr := dero.CheckAddress(request.DeroAddr); addr != "" {
|
|
|
|
request.DeroAddr = addr
|
|
|
|
} else {
|
|
|
|
err = fmt.Errorf("invalid address")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// basic checks
|
|
|
|
if request.Amount == 0 || err != nil {
|
|
|
|
response.Error = "invalid request"
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// prevent users from creating too many swap requests
|
|
|
|
if Delay.CheckUser(request.DeroAddr) {
|
|
|
|
response.Error = "2 minutes wait time triggered"
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// check if pair is enabled and available
|
|
|
|
pair := request.Pair
|
|
|
|
if !coin.IsPairEnabled(pair) || !IsPairAvailable[pair] {
|
|
|
|
response.Error = fmt.Sprintf("%s swap currently not possible", pair)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// create swap
|
|
|
|
err = XTCSwap(pair, request.DeroAddr, coin.RoundFloat(request.Amount, 5), &response)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
response.Error = err.Error()
|
|
|
|
log.Println(err)
|
|
|
|
} else {
|
|
|
|
Delay.AddUser(request.DeroAddr)
|
|
|
|
}
|
|
|
|
response.Request = request
|
|
|
|
|
|
|
|
return response
|
|
|
|
}
|
|
|
|
|
|
|
|
// swap Dero to other coins
|
|
|
|
func Reverse_Swap(request coin.Swap_Request) (response coin.Swap_Response) {
|
|
|
|
|
|
|
|
var err error
|
|
|
|
|
|
|
|
// prevent users from creating too many swap requests
|
|
|
|
if Delay.CheckUser(request.DeroAddr) {
|
|
|
|
response.Error = "2 minutes wait time triggered"
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// check if pair is enabled and available
|
|
|
|
pair := request.Pair
|
|
|
|
if !coin.IsPairEnabled(pair) || !IsPairAvailable[pair] {
|
|
|
|
response.Error = fmt.Sprintf("%s swap currently not possible", pair)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
response.Deposit = coin.RoundFloat(request.Amount, 5)
|
|
|
|
|
|
|
|
// create swap
|
|
|
|
err = DeroXTCSwap(pair, request.DeroAddr, response.Deposit, &response)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
response.Error = err.Error()
|
|
|
|
log.Println(err)
|
|
|
|
} else {
|
|
|
|
Delay.AddUser(request.DeroAddr)
|
|
|
|
}
|
|
|
|
response.Request = request
|
|
|
|
|
|
|
|
return response
|
|
|
|
}
|
|
|
|
|
|
|
|
func newUpgrader() *websocket.Upgrader {
|
|
|
|
u := websocket.NewUpgrader()
|
|
|
|
|
|
|
|
u.CheckOrigin = (func(r *http.Request) bool {
|
|
|
|
return true
|
|
|
|
})
|
|
|
|
|
|
|
|
u.OnClose(func(c *websocket.Conn, err error) {
|
|
|
|
WSConnections.Delete(c)
|
|
|
|
})
|
|
|
|
|
|
|
|
u.OnMessage(func(c *websocket.Conn, messageType websocket.MessageType, data []byte) {
|
|
|
|
|
|
|
|
var in, out WS_Message
|
|
|
|
var send bytes.Buffer
|
|
|
|
|
|
|
|
read := bytes.NewReader(data)
|
|
|
|
decoder := json.NewDecoder(read)
|
|
|
|
encoder := json.NewEncoder(&send)
|
|
|
|
|
|
|
|
err := decoder.Decode(&in)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
out.ID = in.ID
|
|
|
|
|
|
|
|
switch in.Method {
|
|
|
|
case "swap":
|
|
|
|
|
|
|
|
var request coin.Swap_Request
|
|
|
|
var response coin.Swap_Response
|
|
|
|
|
|
|
|
p := in.Params.(map[string]any)
|
|
|
|
|
|
|
|
request.Pair = p["pair"].(string)
|
|
|
|
request.Amount = p["amount"].(float64)
|
|
|
|
request.DeroAddr = p["dero_address"].(string)
|
|
|
|
|
|
|
|
switch request.Pair {
|
|
|
|
case coin.BTCDERO, coin.LTCDERO, coin.ARRRDERO, coin.XMRDERO:
|
|
|
|
response = Dero_Swap(request)
|
|
|
|
case coin.DEROBTC, coin.DEROLTC, coin.DEROARRR, coin.DEROXMR:
|
|
|
|
response = Reverse_Swap(request)
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
|
|
|
|
out.Method = "swap"
|
|
|
|
out.Result = response
|
|
|
|
encoder.Encode(out)
|
|
|
|
|
|
|
|
SendWSData(c, send.Bytes())
|
|
|
|
case "market":
|
|
|
|
|
|
|
|
mk.RLock()
|
|
|
|
defer mk.RUnlock()
|
|
|
|
|
|
|
|
var data bytes.Buffer
|
|
|
|
|
|
|
|
out.Method = "market"
|
|
|
|
inner := mk.Pairs
|
|
|
|
out.Result = inner
|
|
|
|
|
|
|
|
encoder := json.NewEncoder(&data)
|
|
|
|
encoder.Encode(out)
|
|
|
|
|
|
|
|
SendWSData(c, data.Bytes())
|
|
|
|
|
|
|
|
case "balance":
|
|
|
|
|
|
|
|
var data bytes.Buffer
|
|
|
|
|
|
|
|
out.Method = "balance"
|
|
|
|
out.Result = UpdatePool()
|
|
|
|
|
|
|
|
encoder := json.NewEncoder(&data)
|
|
|
|
encoder.Encode(out)
|
|
|
|
|
|
|
|
SendWSData(c, data.Bytes())
|
|
|
|
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
return u
|
|
|
|
}
|
|
|
|
|
|
|
|
func webSocketHandler(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
|
|
|
upgrader := newUpgrader()
|
|
|
|
conn, err := upgrader.Upgrade(w, r, nil)
|
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
WSConnections.Store(conn, true)
|
|
|
|
}
|
|
|
|
|
|
|
|
func SendWSData(c *websocket.Conn, data []byte) {
|
|
|
|
|
|
|
|
if len(data) == 0 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if c != nil {
|
|
|
|
err := c.WriteMessage(websocket.TextMessage, data)
|
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
WSConnections.Range(func(k any, v any) bool {
|
|
|
|
|
|
|
|
conn := k.(*websocket.Conn)
|
|
|
|
|
|
|
|
err := conn.WriteMessage(websocket.TextMessage, data)
|
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func StartServer() {
|
|
|
|
|
|
|
|
// cert files
|
|
|
|
// Let's Encrypt:
|
|
|
|
// certFile = fullchain.pem
|
|
|
|
// keyFile = privkey.pem
|
|
|
|
|
2024-04-11 20:36:07 +01:00
|
|
|
// uncomment the following block to enable TLS; edit cert files first
|
|
|
|
/*
|
2024-04-11 13:35:17 +01:00
|
|
|
cert, err := tls.LoadX509KeyPair("/etc/letsencrypt/live/mg25ot4aggt8dprv.myfritz.net/fullchain.pem", "/etc/letsencrypt/live/mg25ot4aggt8dprv.myfritz.net/privkey.pem")
|
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
os.Exit(2)
|
|
|
|
}
|
2024-04-11 20:36:07 +01:00
|
|
|
*/
|
2024-04-11 13:35:17 +01:00
|
|
|
|
|
|
|
mux := http.NewServeMux()
|
|
|
|
mux.HandleFunc("/ws", webSocketHandler)
|
|
|
|
|
|
|
|
srv := nbhttp.NewServer(nbhttp.Config{
|
|
|
|
Network: "tcp",
|
|
|
|
Handler: mux,
|
2024-04-11 20:36:07 +01:00
|
|
|
// uncomment the following 2 lines and comment "Addrs" to start server with TLS
|
|
|
|
//AddrsTLS: []string{cfg.Settings.ListenAddress},
|
|
|
|
//TLSConfig: &tls.Config{Certificates: []tls.Certificate{cert}},
|
|
|
|
Addrs: []string{cfg.Settings.ListenAddress},
|
2024-04-11 13:35:17 +01:00
|
|
|
})
|
|
|
|
|
2024-04-11 20:37:31 +01:00
|
|
|
err := srv.Start()
|
2024-04-11 13:35:17 +01:00
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
os.Exit(2)
|
|
|
|
}
|
|
|
|
srv.Wait()
|
|
|
|
}
|