swap client support
This commit is contained in:
parent
cfa71f8203
commit
ddfc1bb8aa
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
105
clients/clients.go
Normal file
105
clients/clients.go
Normal file
@ -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
|
||||
}
|
31
clients/variables.go
Normal file
31
clients/variables.go
Normal file
@ -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)}
|
13
coin/btc.go
13
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) {
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 ""
|
||||
}
|
||||
|
||||
|
3
price.go
3
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
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
package main
|
||||
|
||||
import "sync"
|
||||
import (
|
||||
"dero-swap/clients"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type (
|
||||
Price_Provider struct {
|
||||
@ -39,17 +42,18 @@ type (
|
||||
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
|
||||
BID
|
||||
MEDIAN
|
||||
)
|
||||
const (
|
||||
TO = iota
|
||||
XEGGEX = iota
|
||||
XEGGEX
|
||||
)
|
||||
const SATOSHI float64 = 1e-08
|
||||
|
||||
|
103
server.go
103
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)
|
||||
|
13
swap.go
13
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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user