From ddfc1bb8aaa865b527a9eff454f406868801ff27 Mon Sep 17 00:00:00 2001 From: mmarcel Date: Sat, 20 Apr 2024 22:21:02 +0200 Subject: [PATCH] swap client support --- cfg/config.go | 48 +++++++++++++------- cfg/variables.go | 23 +++++----- clients/clients.go | 105 +++++++++++++++++++++++++++++++++++++++++++ clients/variables.go | 31 +++++++++++++ coin/btc.go | 13 ++++-- coin/functions.go | 14 +++--- coin/variables.go | 8 +++- dero/wallet.go | 27 ++++++++++- monero/wallet.go | 8 ++-- price.go | 3 ++ price_variables.go | 26 ++++++----- server.go | 103 +++++++++++++++++++++++++++++++++++++----- swap.go | 13 ++++-- swap_manager.go | 56 +++++++++++++++++++---- 14 files changed, 401 insertions(+), 77 deletions(-) create mode 100644 clients/clients.go create mode 100644 clients/variables.go diff --git a/cfg/config.go b/cfg/config.go index c70a413..0f045cc 100644 --- a/cfg/config.go +++ b/cfg/config.go @@ -4,6 +4,7 @@ import ( "dero-swap/coin" "dero-swap/dero" "dero-swap/monero" + "encoding/base64" "encoding/json" "log" "os" @@ -26,13 +27,24 @@ func LoadConfig() { return } - dero.Dero_Daemon = jsonrpc.NewClient("http://" + Settings.Dero_daemon + "/json_rpc") - dero.Dero_Wallet = jsonrpc.NewClient("http://" + Settings.Dero_wallet + "/json_rpc") - monero.Monero_Wallet = jsonrpc.NewClient("http://" + Settings.Monero_wallet + "/json_rpc") + dero.Dero_Daemon = jsonrpc.NewClient("http://" + Settings.Dero_Daemon + "/json_rpc") + if Settings.Dero_Login != "" { + dero.RPC_Login = base64.StdEncoding.EncodeToString([]byte(Settings.Dero_Login)) + dero.Dero_Wallet = jsonrpc.NewClientWithOpts("http://"+Settings.Dero_Wallet+"/json_rpc", &jsonrpc.RPCClientOpts{ + CustomHeaders: map[string]string{ + "Authorization": "Basic " + dero.RPC_Login, + }, + }) + } else { + dero.Dero_Wallet = jsonrpc.NewClient("http://" + Settings.Dero_Wallet + "/json_rpc") + log.Println("Dero Wallet: No RPC authorization specified") + } - coin.XTC_URL[coin.BTCDERO] = "http://" + Settings.BTC_daemon - coin.XTC_URL[coin.LTCDERO] = "http://" + Settings.LTC_daemon - coin.XTC_URL[coin.ARRRDERO] = "http://" + Settings.ARRR_daemon + monero.Monero_Wallet = jsonrpc.NewClient("http://" + Settings.Monero_Wallet + "/json_rpc") + + coin.XTC_URL[coin.BTCDERO] = "http://" + Settings.BTC_Daemon + coin.XTC_URL[coin.LTCDERO] = "http://" + Settings.LTC_Daemon + coin.XTC_URL[coin.ARRRDERO] = "http://" + Settings.ARRR_Daemon // check if pair is "supported" for _, p := range Settings.Pairs { @@ -75,7 +87,7 @@ func LoadFees() { // basic config check func CheckConfig() bool { - if Settings.Dero_daemon == "" || Settings.Dero_wallet == "" { + if Settings.Dero_Daemon == "" || Settings.Dero_Wallet == "" { log.Println("Dero Daemon or Dero Wallet is not set") return false } @@ -83,38 +95,44 @@ func CheckConfig() bool { for p := range coin.Pairs { switch p { case coin.BTCDERO, coin.DEROBTC: - if Settings.BTC_daemon == "" || Settings.BTC_dir == "" { + if Settings.BTC_Daemon == "" || Settings.BTC_Dir == "" { log.Printf("%s pair is set, but daemon or directory is not set\n", p) return false } else { - coin.BTC_dir = Settings.BTC_dir + coin.BTC_Dir = Settings.BTC_Dir } case coin.LTCDERO, coin.DEROLTC: - if Settings.LTC_daemon == "" || Settings.LTC_dir == "" { + if Settings.LTC_Daemon == "" || Settings.LTC_Dir == "" { log.Printf("%s pair is set, but daemon or directory is not set\n", p) return false } else { - coin.LTC_dir = Settings.LTC_dir + coin.LTC_Dir = Settings.LTC_Dir } case coin.ARRRDERO, coin.DEROARRR: - if Settings.ARRR_daemon == "" || Settings.ARRR_dir == "" { + if Settings.ARRR_Daemon == "" || Settings.ARRR_Dir == "" { log.Printf("%s pair is set, but daemon or directory is not set\n", p) return false } else { - coin.ARRR_dir = Settings.ARRR_dir + coin.ARRR_Dir = Settings.ARRR_Dir } case coin.XMRDERO, coin.DEROXMR: - if Settings.Monero_wallet == "" { + if Settings.Monero_Wallet == "" { log.Printf("%s pair is set, but wallet is not set\n", p) return false } } } - if dero.GetHeight() == 0 || dero.CheckBlockHeight() == 0 { + if dero.RPC_Login != "" { + log.Printf("%-14s: %s\n", "Dero Wallet", "Using RPC authorization") + } + dero_wallet := dero.GetAddress() + + if dero.GetHeight() == 0 || dero.CheckBlockHeight() == 0 || dero_wallet == "" { log.Println("Dero daemon or wallet is not available") return false } + log.Printf("%-14s: %s\n", "Dero Wallet", dero_wallet) return true } diff --git a/cfg/variables.go b/cfg/variables.go index f91cb46..6f9a7c0 100644 --- a/cfg/variables.go +++ b/cfg/variables.go @@ -2,16 +2,17 @@ package cfg type Config struct { ListenAddress string `json:"listen"` - BTC_daemon string `json:"btc_daemon"` - BTC_dir string `json:"btc_dir"` - LTC_daemon string `json:"ltc_daemon"` - LTC_dir string `json:"ltc_dir"` - ARRR_daemon string `json:"arrr_daemon"` - ARRR_dir string `json:"arrr_dir"` - Dero_daemon string `json:"dero_daemon"` - Dero_wallet string `json:"dero_wallet"` - Monero_daemon string `json:"monero_daemon"` - Monero_wallet string `json:"monero_wallet"` + BTC_Daemon string `json:"BTC_Daemon"` + BTC_Dir string `json:"BTC_Dir"` + LTC_Daemon string `json:"LTC_Daemon"` + LTC_Dir string `json:"LTC_Dir"` + ARRR_Daemon string `json:"ARRR_Daemon"` + ARRR_Dir string `json:"ARRR_Dir"` + Dero_Daemon string `json:"Dero_Daemon"` + Dero_Wallet string `json:"dero_wallet"` + Dero_Login string `json:"dero_login"` + Monero_Daemon string `json:"monero_daemon"` + Monero_Wallet string `json:"Monero_Wallet"` Pairs []string `json:"pairs"` //SwapFees float64 `json:"swap_fees"` } @@ -46,4 +47,4 @@ type ( ) var Settings Config -var SwapFees = Fees{Withdrawal: Withdrawal_Fees{DeroLTC: 0.0002, DeroBTC: 0.00004, DeroARRR: 0.001, DeroXMR: 0.00006}} +var SwapFees Fees diff --git a/clients/clients.go b/clients/clients.go new file mode 100644 index 0000000..7f8da4e --- /dev/null +++ b/clients/clients.go @@ -0,0 +1,105 @@ +package clients + +import ( + "dero-swap/coin" + "log" + + "github.com/lesismal/nbio/nbhttp/websocket" +) + +type Swap_External struct { + Nickname string `json:"nickname"` + Dero float64 `json:"dero"` + XMR float64 `json:"xmr,omitempty"` +} + +func IsExternalSwapAvailable(user string, pair string, amount float64) (ok bool, client *websocket.Conn) { + + Clients.Range(func(key any, value any) bool { + c := value.(ClientInfo) + for _, p := range c.PairInfo { + if p.Pair == pair && p.Balance >= amount && user == c.Nickname { + ok = true + client = key.(*websocket.Conn) + return false + } + } + return true + }) + return +} + +func PrepareExternalSwap(user string, pair string, amount float64) (bool, *websocket.Conn) { + + // only XMR swaps + if pair != coin.XMRDERO && pair != coin.DEROXMR { + log.Println("Only 3rd party XMR swaps") + return false, nil + } + + ok, conn := IsExternalSwapAvailable(user, pair, amount) + if !ok { + log.Println("No 3rd party swaps available") + return false, nil + } + + return true, conn +} + +func (c *SwapState) ChangeClientState(mode uint, conn *websocket.Conn) { + + c.Lock() + defer c.Unlock() + + if mode == LOCK { + c.Client[conn] = true + } else { + c.Client[conn] = false + } +} + +func (c *SwapState) CheckClientState(conn *websocket.Conn) bool { + + c.RLock() + defer c.RUnlock() + + return c.Client[conn] +} + +func (c *SwapState) AddOrigin(conn *websocket.Conn, target *websocket.Conn) { + + c.Lock() + defer c.Unlock() + + c.Result[conn] = target +} + +func (c *SwapState) GetOrigin(conn *websocket.Conn) *websocket.Conn { + + c.RLock() + defer c.RUnlock() + + return c.Result[conn] +} + +func GetExternalBalances() (list []Swap_External) { + + var entry Swap_External + + Clients.Range(func(key any, value any) bool { + c := value.(ClientInfo) + entry.Nickname = c.Nickname + for _, p := range c.PairInfo { + switch p.Pair { + case coin.DEROXMR: + entry.XMR = p.Balance + case coin.XMRDERO: + entry.Dero = p.Balance + } + } + list = append(list, entry) + return true + }) + + return +} diff --git a/clients/variables.go b/clients/variables.go new file mode 100644 index 0000000..de60550 --- /dev/null +++ b/clients/variables.go @@ -0,0 +1,31 @@ +package clients + +import ( + "sync" + + "github.com/lesismal/nbio/nbhttp/websocket" +) + +const ( + LOCK = iota + UNLOCK +) + +type ( + ClientInfo struct { + PairInfo []PairInfo `json:"pair_info"` + Nickname string `json:"nickname"` + } + PairInfo struct { + Pair string `json:"pair"` + Balance float64 `json:"balance"` + } +) +type SwapState struct { + Client map[*websocket.Conn]bool + Result map[*websocket.Conn]*websocket.Conn + sync.RWMutex +} + +var Clients sync.Map +var ActiveClients = SwapState{Client: make(map[*websocket.Conn]bool), Result: make(map[*websocket.Conn]*websocket.Conn)} diff --git a/coin/btc.go b/coin/btc.go index 559db58..7b829a5 100644 --- a/coin/btc.go +++ b/coin/btc.go @@ -8,6 +8,7 @@ import ( "io" "log" "os" + "strings" "net/http" ) @@ -19,17 +20,17 @@ func XTCGetCookie(pair string) bool { switch pair { case BTCDERO, DEROBTC: - if data, err = os.ReadFile(BTC_dir + "/.cookie"); err != nil { + if data, err = os.ReadFile(BTC_Dir + "/.cookie"); err != nil { log.Printf("Can't load BTC auth cookie: %v\n", err) return false } case LTCDERO, DEROLTC: - if data, err = os.ReadFile(LTC_dir + "/.cookie"); err != nil { + if data, err = os.ReadFile(LTC_Dir + "/.cookie"); err != nil { log.Printf("Can't load LTC auth cookie: %v\n", err) return false } case ARRRDERO, DEROARRR: - if data, err = os.ReadFile(ARRR_dir + "/.cookie"); err != nil { + if data, err = os.ReadFile(ARRR_Dir + "/.cookie"); err != nil { log.Printf("Can't load ARRR auth cookie: %v\n", err) return false } @@ -391,7 +392,11 @@ func XTCGetBalance(pair string) float64 { return 0 } - return RoundFloat(result.Result-Locked.GetLockedBalance(pair), 8) + if strings.HasPrefix(pair, "dero") { + result.Result -= Locked.GetLockedBalance(pair) + } + + return RoundFloat(result.Result, 8) } func XTCSend(pair string, wallet string, amount float64) (bool, string) { diff --git a/coin/functions.go b/coin/functions.go index 38be596..ea564fa 100644 --- a/coin/functions.go +++ b/coin/functions.go @@ -44,7 +44,7 @@ func (r *Swap) GetLockedBalance(coin string) float64 { defer r.RUnlock() switch coin { - case BTCDERO, LTCDERO, ARRRDERO: + case BTCDERO, LTCDERO, ARRRDERO, XMRDERO: return r.Dero_balance case DEROLTC: return r.LTC_balance @@ -52,6 +52,8 @@ func (r *Swap) GetLockedBalance(coin string) float64 { return r.BTC_balance case DEROARRR: return r.ARRR_balance + case DEROXMR: + return r.XMR_balance default: return 0 } @@ -62,7 +64,7 @@ func (r *Swap) AddLockedBalance(coin string, amount float64) { defer r.Unlock() switch coin { - case BTCDERO, LTCDERO, ARRRDERO: + case BTCDERO, LTCDERO, ARRRDERO, XMRDERO: r.Dero_balance += amount case DEROLTC: r.LTC_balance += amount @@ -70,6 +72,8 @@ func (r *Swap) AddLockedBalance(coin string, amount float64) { r.BTC_balance += amount case DEROARRR: r.ARRR_balance += amount + case DEROXMR: + r.XMR_balance += amount } } @@ -78,7 +82,7 @@ func (r *Swap) RemoveLockedBalance(coin string, amount float64) { defer r.Unlock() switch coin { - case BTCDERO, LTCDERO, ARRRDERO: + case BTCDERO, LTCDERO, ARRRDERO, XMRDERO: r.Dero_balance -= amount case DEROLTC: r.LTC_balance -= amount @@ -86,6 +90,8 @@ func (r *Swap) RemoveLockedBalance(coin string, amount float64) { r.BTC_balance -= amount case DEROARRR: r.ARRR_balance -= amount + case DEROXMR: + r.XMR_balance -= amount } } @@ -97,7 +103,6 @@ func (r *Swap) LoadLockedBalance() { } var swap_e Swap_Entry - var amount float64 for _, e := range dir_entries { file_data, err := os.ReadFile("swaps/active/" + e.Name()) @@ -110,7 +115,6 @@ func (r *Swap) LoadLockedBalance() { } switch swap_e.Coin { case LTCDERO, BTCDERO, ARRRDERO, XMRDERO: - amount += swap_e.Amount r.AddLockedBalance(swap_e.Coin, swap_e.Amount) default: r.AddLockedBalance(swap_e.Coin, swap_e.Price) diff --git a/coin/variables.go b/coin/variables.go index 3b7871c..fe94289 100644 --- a/coin/variables.go +++ b/coin/variables.go @@ -10,6 +10,7 @@ type ( Pair string `json:"pair"` Amount float64 `json:"amount"` DeroAddr string `json:"dero_address"` + Extern string `json:"extern,omitempty"` } Swap_Response struct { ID int64 `json:"id"` @@ -19,6 +20,10 @@ type ( Error string `json:"error,omitempty"` Request Swap_Request `json:"request"` } + Swap_Tracking struct { + ID int64 `json:"id"` + State uint64 `json:"state"` + } Swap_Entry struct { Coin string `json:"coin"` Wallet string `json:"wallet"` @@ -29,6 +34,7 @@ type ( Block uint64 `json:"block"` Balance float64 `json:"balance"` Status uint64 `json:"status"` + Txid string `json:"txid"` } Swap struct { Dero_balance float64 @@ -49,4 +55,4 @@ var XTC_Daemon = &http.Client{} var XTC_auth string var BTC_address, LTC_address, ARRR_address, XMR_address string -var BTC_dir, LTC_dir, ARRR_dir string +var BTC_Dir, LTC_Dir, ARRR_Dir string diff --git a/dero/wallet.go b/dero/wallet.go index 284b1a9..e44ed1b 100644 --- a/dero/wallet.go +++ b/dero/wallet.go @@ -15,6 +15,8 @@ import ( const atomicUnits float64 = 100000 const TxFee float64 = 0.0004 +var RPC_Login string + var Dero_Wallet jsonrpc.RPCClient func AddTX(wallet string, amount float64) rpc.Transfer { @@ -34,7 +36,7 @@ func GetHeight() uint64 { err = result.GetObject(&response) if err != nil { - log.Printf("Error getting DERO wallet height: %v\n", err) + log.Printf("Error checking DERO wallet height: %v\n", err) return 0 } @@ -55,7 +57,7 @@ func GetBalance() float64 { err = result.GetObject(&response) if err != nil { - log.Printf("Error getting DERO wallet balance: %v\n", err) + log.Printf("Error checking DERO wallet balance: %v\n", err) return 0 } @@ -65,6 +67,27 @@ func GetBalance() float64 { return coin.RoundFloat(balance_fl, 5) } +func GetAddress() string { + + ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) + result, err := Dero_Wallet.Call(ctx, "getaddress") + cancel() + + if err != nil { + return "" + } + + var response rpc.GetAddress_Result + + err = result.GetObject(&response) + if err != nil { + log.Printf("Error checking DERO wallet address: %v\n", err) + return "" + } + + return response.Address +} + func Payout(tx []rpc.Transfer) { var tries uint diff --git a/monero/wallet.go b/monero/wallet.go index bfff56f..dee7599 100644 --- a/monero/wallet.go +++ b/monero/wallet.go @@ -46,11 +46,11 @@ func XMRGetTX(payment string, block uint64) bool { err = result.GetObject(&response) if err != nil { - log.Printf("Error getting XMR incoming payments: %v\n", err) + log.Printf("Error checking XMR incoming payments: %v\n", err) return false } - // placeholder + // todo for _, p := range response.Payments { if p.UnlockTime > 0 { return false @@ -99,7 +99,7 @@ func GetBalance() float64 { err = result.GetObject(&response) if err != nil { - log.Printf("Error getting XMR wallet balance: %v\n", err) + log.Printf("Error checking XMR wallet balance: %v\n", err) return 0 } @@ -119,7 +119,7 @@ func GetAddress() string { err = result.GetObject(&response) if err != nil { - log.Printf("Error getting XMR wallet address: %v\n", err) + log.Printf("Error checking XMR wallet address: %v\n", err) return "" } diff --git a/price.go b/price.go index 3f74333..90ac878 100644 --- a/price.go +++ b/price.go @@ -3,6 +3,7 @@ package main import ( "bytes" "dero-swap/cfg" + "dero-swap/clients" "dero-swap/coin" "dero-swap/dero" "dero-swap/monero" @@ -299,5 +300,7 @@ func UpdatePool() Swap_Balance { } } + balance.External = clients.GetExternalBalances() + return balance } diff --git a/price_variables.go b/price_variables.go index 5e28f69..fa4cdfa 100644 --- a/price_variables.go +++ b/price_variables.go @@ -1,6 +1,9 @@ package main -import "sync" +import ( + "dero-swap/clients" + "sync" +) type ( Price_Provider struct { @@ -34,22 +37,23 @@ type ( DEROXMR float64 `json:"deroxmr,omitempty"` } Swap_Balance struct { - Dero float64 `json:"dero"` - LTC float64 `json:"ltc,omitempty"` - BTC float64 `json:"btc,omitempty"` - ARRR float64 `json:"arrr,omitempty"` - XMR float64 `json:"xmr,omitempty"` + Dero float64 `json:"dero"` + LTC float64 `json:"ltc,omitempty"` + BTC float64 `json:"btc,omitempty"` + ARRR float64 `json:"arrr,omitempty"` + XMR float64 `json:"xmr,omitempty"` + External []clients.Swap_External `json:"external,omitempty"` } ) const ( - ASK = iota - BID = iota - MEDIAN = iota + ASK = iota + BID + MEDIAN ) const ( - TO = iota - XEGGEX = iota + TO = iota + XEGGEX ) const SATOSHI float64 = 1e-08 diff --git a/server.go b/server.go index 416f3c0..37653a8 100644 --- a/server.go +++ b/server.go @@ -9,6 +9,7 @@ import ( "os" "strings" "sync" + "time" "github.com/lesismal/llib/std/crypto/tls" @@ -17,6 +18,7 @@ import ( "github.com/lesismal/nbio/nbhttp/websocket" "dero-swap/cfg" + "dero-swap/clients" "dero-swap/coin" "dero-swap/dero" ) @@ -122,6 +124,7 @@ func newUpgrader() *websocket.Upgrader { u.OnClose(func(c *websocket.Conn, err error) { WSConnections.Delete(c) + clients.Clients.Delete(c) }) u.OnMessage(func(c *websocket.Conn, messageType websocket.MessageType, data []byte) { @@ -148,10 +151,35 @@ func newUpgrader() *websocket.Upgrader { var response coin.Swap_Response p := in.Params.(map[string]any) + out.Method = "swap" - request.Pair = p["pair"].(string) - request.Amount = p["amount"].(float64) - request.DeroAddr = p["dero_address"].(string) + if d, ok := p["pair"]; ok { + request.Pair = d.(string) + } + if d, ok := p["amount"]; ok { + request.Amount = d.(float64) + } + if d, ok := p["dero_address"]; ok { + request.DeroAddr = d.(string) + } + + if q, ok := p["extern"]; ok && q.(string) != "" { + if ok, conn := clients.PrepareExternalSwap(q.(string), request.Pair, request.Amount); ok { + clients.ActiveClients.ChangeClientState(clients.LOCK, conn) + clients.ActiveClients.AddOrigin(conn, c) + out.Params = request + encoder.Encode(out) + SendWSData(conn, send.Bytes()) + } else { + response.Error = "External swap not possible" + } + + out.Result = response + encoder.Encode(out) + SendWSData(c, send.Bytes()) + + return + } switch request.Pair { case coin.BTCDERO, coin.LTCDERO, coin.ARRRDERO, coin.XMRDERO: @@ -161,11 +189,32 @@ func newUpgrader() *websocket.Upgrader { default: } - out.Method = "swap" out.Result = response encoder.Encode(out) SendWSData(c, send.Bytes()) + + var track coin.Swap_Tracking + + track.ID = response.ID + out.Method = "track" + go func() { + for { + time.Sleep(time.Second * 15) + track.State = SwapTracking(response.ID) + out.Result = track + send.Reset() + encoder.Encode(out) + if _, ok := WSConnections.Load(c); ok { + SendWSData(c, send.Bytes()) + } else { + break + } + if track.State == SWAP_DONE || track.State == SWAP_EXPIRED { + break + } + } + }() case "market": mk.RLock() @@ -194,6 +243,37 @@ func newUpgrader() *websocket.Upgrader { SendWSData(c, data.Bytes()) + case "client": + + var client clients.ClientInfo + + p := in.Params.(map[string]any) + client.Nickname = p["nickname"].(string) + + q := p["pair_info"].([]any) + for i := range q { + r := q[i].(map[string]any) + client.PairInfo = append(client.PairInfo, clients.PairInfo{Balance: r["balance"].(float64), Pair: r["pair"].(string)}) + } + if _, ok := clients.Clients.Load(c); !ok { + log.Printf("Client Hello from %s\n", client.Nickname) + } + clients.Clients.Store(c, client) + + case "client_ok": + + if clients.ActiveClients.CheckClientState(c) { + + clients.ActiveClients.ChangeClientState(clients.UNLOCK, c) + client := clients.ActiveClients.GetOrigin(c) + + out.Method = "swap" + out.Result = in.Result + encoder.Encode(out) + + SendWSData(client, send.Bytes()) + } + default: } @@ -247,28 +327,27 @@ func StartServer() { // certFile = fullchain.pem // keyFile = privkey.pem - // uncomment the following block to enable TLS; edit cert files first - /* + // comment the following block to disable TLS 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) } - */ mux := http.NewServeMux() mux.HandleFunc("/ws", webSocketHandler) + //mux.HandleFunc("/api", ) srv := nbhttp.NewServer(nbhttp.Config{ Network: "tcp", Handler: mux, - // 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}, + // comment the following 2 lines and uncomment "Addrs" to start server without TLS + AddrsTLS: []string{cfg.Settings.ListenAddress}, + TLSConfig: &tls.Config{Certificates: []tls.Certificate{cert}}, + //Addrs: []string{cfg.Settings.ListenAddress}, }) - err := srv.Start() + err = srv.Start() if err != nil { log.Println(err) os.Exit(2) diff --git a/swap.go b/swap.go index 6f1e750..958ae8d 100644 --- a/swap.go +++ b/swap.go @@ -84,10 +84,15 @@ func XTCSwap(pair string, dst_addr string, amount float64, resp *coin.Swap_Respo coin.Locked.AddLockedBalance(pair, amount) // create/get a deposit address - if pair != coin.XMRDERO { - resp.Wallet = coin.XTCGetAddress(pair) - } else { + switch pair { + case coin.BTCDERO: + resp.Wallet = coin.BTC_address + case coin.LTCDERO: + resp.Wallet = coin.LTC_address + case coin.XMRDERO: resp.Wallet = monero.MakeIntegratedAddress() + case coin.ARRRDERO: + resp.Wallet = coin.ARRR_address } if resp.Wallet == "" { return fmt.Errorf("no swap deposit address available") @@ -171,7 +176,7 @@ func DeroXTCSwap(pair string, dst_addr string, amount float64, resp *coin.Swap_R coin_value = mk.Pairs.DEROBTC fees = cfg.SwapFees.Withdrawal.DeroBTC case coin.DEROXMR: - coin_value = mk.Pairs.XMR + coin_value = mk.Pairs.DEROXMR fees = cfg.SwapFees.Withdrawal.DeroXMR } diff --git a/swap_manager.go b/swap_manager.go index 668058d..0b0a53a 100644 --- a/swap_manager.go +++ b/swap_manager.go @@ -14,6 +14,15 @@ import ( "github.com/deroproject/derohe/rpc" ) +const ( + SWAP_CREATED = iota + SWAP_CONFIRMED + SWAP_DONE + SWAP_EXPIRED + SWAP_TOO_OLD + SWAP_UNDEFINED +) + func Swap_Controller() { var file_data []byte @@ -30,6 +39,10 @@ func Swap_Controller() { time.Sleep(time.Minute) dir_entries, err = os.ReadDir("swaps/active") + if err != nil { + log.Println("Can't list swap entries") + continue + } expired = 0 fails = 0 @@ -57,7 +70,7 @@ func Swap_Controller() { creation_t := time.UnixMilli(swap_e.Created) // if there was no deposit, mark the request as expired - if swap_e.Status == 0 && time.Since(creation_t) > time.Hour { + if swap_e.Status == SWAP_CREATED && time.Since(creation_t) > time.Hour { os.WriteFile(fmt.Sprintf("swaps/expired/%d", swap_e.Created), file_data, 0644) os.Remove("swaps/active/" + e.Name()) switch swap_e.Coin { @@ -82,7 +95,7 @@ func Swap_Controller() { found_deposit = monero.XMRGetTX(payment_id, swap_e.Block) visible = found_deposit } else { - log.Println("Can't split intragrated XMR address") + log.Println("Can't split integrated XMR address") } default: found_deposit = dero.CheckIncomingTransfers(uint64(swap_e.Created), swap_e.Block) @@ -96,7 +109,7 @@ func Swap_Controller() { } // mark request as done - if swap_e.Status == 2 { + if swap_e.Status == SWAP_DONE { err = os.WriteFile(fmt.Sprintf("swaps/done/%d", swap_e.Created), file_data, 0644) if err != nil { log.Printf("Can't mark swap as done, swap %d, err %v\n", swap_e.Created, err) @@ -108,7 +121,8 @@ func Swap_Controller() { // start payout if there are at least 2 confirmations // requests won't be marked as expired, if there is already 1 confirmation if visible { - if found_deposit && swap_e.Status <= 1 { + log.Printf("Found TX for ID %d (%s) on chain\n", swap_e.Created, swap_e.Coin) + if found_deposit && swap_e.Status <= SWAP_CONFIRMED { // create transaction log.Printf("Found deposit for ID %d (%s): %.8f coins; adding to payout TX\n", swap_e.Created, swap_e.Coin, swap_e.Amount) @@ -116,7 +130,7 @@ func Swap_Controller() { case coin.DEROLTC, coin.DEROBTC: log.Println("Starting LTC/BTC payout") _, txid := coin.XTCSend(swap_e.Coin, swap_e.Destination, swap_e.Price) - log.Printf("LTC TXID: %s\n", txid) + log.Printf("LTC/BTC TXID: %s\n", txid) coin.Locked.RemoveLockedBalance(swap_e.Coin, swap_e.Price) case coin.DEROARRR: log.Println("Starting ARRR payout") @@ -129,18 +143,18 @@ func Swap_Controller() { txs = append(txs, dero.AddTX(swap_e.Destination, swap_e.Amount)) } - swap_e.Status = 2 + swap_e.Status = SWAP_DONE sent++ active-- } else { // transaction was confirmed - swap_e.Status = 1 + swap_e.Status = SWAP_CONFIRMED } json_data, _ := json.Marshal(&swap_e) os.WriteFile("swaps/active/"+e.Name(), json_data, 0644) - if swap_e.Status == 2 { + if swap_e.Status == SWAP_DONE { err = os.WriteFile(fmt.Sprintf("swaps/done/%d", swap_e.Created), file_data, 0644) if err != nil { log.Printf("Can't mark swap as done, swap %d, err %v\n", swap_e.Created, err) @@ -171,3 +185,29 @@ func Swap_Controller() { } } } + +func SwapTracking(session int64) uint64 { + + if time.Since(time.UnixMilli(int64(session))) > time.Hour*24*3 { + return SWAP_TOO_OLD + } + if _, err := os.ReadFile("swaps/expired/" + fmt.Sprintf("%d", session)); err == nil { + return SWAP_EXPIRED + } + if _, err := os.ReadFile("swaps/done/" + fmt.Sprintf("%d", session)); err == nil { + return SWAP_DONE + } + + var swap coin.Swap_Entry + if fd, err := os.ReadFile("swaps/active/" + fmt.Sprintf("%d", session)); err == nil { + if err = json.Unmarshal(fd, &swap); err == nil { + return swap.Status + } else { + log.Println(err) + } + } else { + log.Println(err) + } + + return SWAP_UNDEFINED +}