Skip to content

Commit

Permalink
xmrswap: Work on testnet.
Browse files Browse the repository at this point in the history
  • Loading branch information
JoeGruffins committed Sep 24, 2024
1 parent eeefd63 commit 6c5ff99
Show file tree
Hide file tree
Showing 3 changed files with 178 additions and 31 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,4 @@ server/cmd/dexadm/dexadm
server/cmd/geogame/geogame
internal/libsecp256k1/secp256k1
internal/cmd/xmrswap/xmrswap
internal/cmd/xmrswap/config.json
11 changes: 11 additions & 0 deletions internal/cmd/xmrswap/example-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"alice": {
"xmrhost": "http://127.0.0.1:28284/json_rpc",
"dcrconf": "/home/me/dextest/dcr/trading1/trading1.conf"
},
"bob": {
"xmrhost": "http://127.0.0.1:28184/json_rpc",
"dcrconf": "/home/me/dextest/dcr/trading2/trading2.conf"
},
"extraxmrhost": "http://127.0.0.1:28484/json_rpc"
}
197 changes: 166 additions & 31 deletions internal/cmd/xmrswap/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import (
"bytes"
"context"
"encoding/hex"
"encoding/json"
"errors"
"flag"
"fmt"
"math"
"math/big"
Expand Down Expand Up @@ -46,15 +48,31 @@ const (
dcrAmt = 7_000_000 // atoms
xmrAmt = 1_000 // 1e12 units
dumbFee = int64(6000)
configName = "config.json"
)

var (
homeDir = os.Getenv("HOME")
dextestDir = filepath.Join(homeDir, "dextest")
bobDir = filepath.Join(dextestDir, "xmr", "wallets", "bob")
curve = edwards.Edwards()

// These should be wallets with funds.
alicexmr = "http://127.0.0.1:28284/json_rpc"
bobxmr = "http://127.0.0.1:28184/json_rpc"
alicedcr = filepath.Join(dextestDir, "dcr", "trading1", "trading1.conf")
bobdcr = filepath.Join(dextestDir, "dcr", "trading2", "trading2.conf")

// This wallet does not need funds or to be loaded.
extraxmr = "http://127.0.0.1:28484/json_rpc"

testnet bool
)

func init() {
flag.BoolVar(&testnet, "testnet", false, "use testnet")
}

func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
Expand Down Expand Up @@ -147,19 +165,48 @@ func newRPCWallet(settings map[string]string, logger dex.Logger, net dex.Network
return newCombinedClient(nodeRPCClient, params), nil
}

func newClient(ctx context.Context, xmrAddr, dcrNode string) (*client, error) {
func newClient(ctx context.Context, xmrAddr, dcrConf string) (*client, error) {
xmr := rpc.New(rpc.Config{
Address: xmrAddr,
Client: &http.Client{},
})

settings, err := config.Parse(filepath.Join(dextestDir, "dcr", dcrNode, fmt.Sprintf("%s.conf", dcrNode)))
ticker := time.NewTicker(time.Second * 5)
defer ticker.Stop()
balReq := rpc.GetBalanceRequest{}
i := 0
out:
for {
select {
case <-ticker.C:
bal, err := xmr.GetBalance(ctx, &balReq)
if err != nil {
return nil, err
}
if bal.UnlockedBalance > xmrAmt*2 {
break out
}
if i%5 == 0 {
fmt.Println("xmr walet has no unlocked funds. Waiting...")
}
i++
case <-ctx.Done():
return nil, ctx.Err()
}

}

settings, err := config.Parse(dcrConf)
if err != nil {
return nil, err
}
settings["account"] = "default"

dcr, err := newRPCWallet(settings, dex.StdOutLogger(dcrNode, slog.LevelTrace), dex.Simnet)
net := dex.Simnet
if testnet {
net = dex.Testnet
}
dcr, err := newRPCWallet(settings, dex.StdOutLogger("client", slog.LevelTrace), net)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -265,7 +312,7 @@ func toAtoms(v float64) uint64 {
// and open it. Can only create one wallet at a time.
func createNewXMRWallet(ctx context.Context, genReq rpc.GenerateFromKeysRequest) (*rpc.Client, error) {
xmrChecker := rpc.New(rpc.Config{
Address: "http://127.0.0.1:28484/json_rpc",
Address: extraxmr,
Client: &http.Client{},
})

Expand Down Expand Up @@ -294,6 +341,10 @@ func (cl prettyLogger) Write(p []byte) (n int, err error) {
}

func run(ctx context.Context) error {
if err := parseConfig(); err != nil {
return err
}

pl := prettyLogger{c: color.New(color.FgGreen)}
log := dex.NewLogger("T", dex.LevelInfo, pl)

Expand Down Expand Up @@ -323,6 +374,51 @@ func run(ctx context.Context) error {
return nil
}

type clientJSON struct {
XMRHost string `json:"xmrhost"`
DCRConf string `json:"dcrconf"`
}

type configJSON struct {
Alice clientJSON `json:"alice"`
Bob clientJSON `json:"bob"`
ExtraXMRHost string `json:"extraxmrhost"`
}

func parseConfig() error {
flag.Parse()

if !testnet {
return nil
}

ex, err := os.Executable()
if err != nil {
return err
}

exPath := filepath.Dir(ex)
configPath := filepath.Join(exPath, configName)

b, err := os.ReadFile(configPath)
if err != nil {
return err
}

var cj configJSON
if err := json.Unmarshal(b, &cj); err != nil {
return err
}

alicexmr = cj.Alice.XMRHost
bobxmr = cj.Bob.XMRHost
alicedcr = cj.Alice.DCRConf
bobdcr = cj.Bob.DCRConf
extraxmr = cj.ExtraXMRHost

return nil
}

// generateDleag starts the trade by creating some keys.
func (c *partClient) generateDleag(ctx context.Context) (pubSpendKeyf *edwards.PublicKey, kbvf *edwards.PrivateKey,
pubPartSignKeyHalf *secp256k1.PublicKey, dleag []byte, err error) {
Expand Down Expand Up @@ -623,7 +719,11 @@ func (c *partClient) initXmr(ctx context.Context, viewKey *edwards.PrivateKey, p
fullPubKey = append(fullPubKey, c.pubSpendKey.SerializeCompressed()...)
fullPubKey = append(fullPubKey, c.viewKey.PubKey().SerializeCompressed()...)

sharedAddr := base58.EncodeAddr(18, fullPubKey)
tag := uint64(18)
if testnet {
tag = 53
}
sharedAddr := base58.EncodeAddr(tag, fullPubKey)

dest := rpc.Destination{
Amount: xmrAmt,
Expand Down Expand Up @@ -733,7 +833,11 @@ func (c *initClient) redeemXmr(ctx context.Context, initSignKeyHalfSig []byte) (
var fullPubKey []byte
fullPubKey = append(fullPubKey, vkbs.PubKey().Serialize()...)
fullPubKey = append(fullPubKey, c.viewKey.PubKey().Serialize()...)
walletAddr := base58.EncodeAddr(18, fullPubKey)
tag := uint64(18)
if testnet {
tag = 53
}
walletAddr := base58.EncodeAddr(tag, fullPubKey)
walletFileName := fmt.Sprintf("%s_spend", walletAddr)

var viewKeyBytes [32]byte
Expand Down Expand Up @@ -848,7 +952,11 @@ func (c *partClient) refundXmr(ctx context.Context, partSignKeyHalfSig []byte, e
var fullPubKey []byte
fullPubKey = append(fullPubKey, vkbs.PubKey().Serialize()...)
fullPubKey = append(fullPubKey, c.viewKey.PubKey().Serialize()...)
walletAddr := base58.EncodeAddr(18, fullPubKey)
tag := uint64(18)
if testnet {
tag = 53
}
walletAddr := base58.EncodeAddr(tag, fullPubKey)
walletFileName := fmt.Sprintf("%s_spend", walletAddr)

var viewKeyBytes [32]byte
Expand Down Expand Up @@ -912,14 +1020,12 @@ func (c *partClient) takeDcr(ctx context.Context, lockRefundTxScript []byte, spe

// success is a successful trade.
func success(ctx context.Context) error {
pc, err := newClient(ctx, "http://127.0.0.1:28284/json_rpc", "trading1")
pc, err := newClient(ctx, alicexmr, alicedcr)
if err != nil {
return err
}
alice := partClient{client: pc}
balReq := rpc.GetBalanceRequest{
AccountIndex: 0,
}
balReq := rpc.GetBalanceRequest{}
xmrBal, err := alice.xmr.GetBalance(ctx, &balReq)
if err != nil {
return err
Expand All @@ -933,7 +1039,7 @@ func success(ctx context.Context) error {
dcrBeforeBal := toAtoms(dcrBal.Balances[0].Total)
fmt.Printf("alice dcr balance %v\n", dcrBeforeBal)

ic, err := newClient(ctx, "http://127.0.0.1:28184/json_rpc", "trading2")
ic, err := newClient(ctx, bobxmr, bobdcr)
if err != nil {
return err
}
Expand Down Expand Up @@ -1001,14 +1107,28 @@ func success(ctx context.Context) error {
return err
}

// NOTE: This wallet must sync so may take a long time on mainnet.
// TODO: Wait for wallet sync rather than a dumb sleep.
time.Sleep(time.Second * 40)
ticker := time.NewTicker(time.Second * 5)
defer ticker.Stop()
timeout := time.After(time.Minute)
out:
for {
select {
case <-ticker.C:
xmrBal, err = xmrChecker.GetBalance(ctx, &balReq)
if err != nil {
return err
}
if xmrBal.Balance > 0 {
break out
}
case <-timeout:
return errors.New("xmr wallet not synced after one minute")
case <-ctx.Done():
return ctx.Err()
}

xmrBal, err = xmrChecker.GetBalance(ctx, &balReq)
if err != nil {
return err
}

if xmrBal.Balance != xmrAmt {
return fmt.Errorf("expected redeem xmr balance of %d but got %d", xmrAmt, xmrBal.Balance)
}
Expand All @@ -1029,13 +1149,13 @@ func success(ctx context.Context) error {
// aliceBailsBeforeXmrInit is a trade that fails because alice does nothing after
// Bob inits.
func aliceBailsBeforeXmrInit(ctx context.Context) error {
pc, err := newClient(ctx, "http://127.0.0.1:28284/json_rpc", "trading1")
pc, err := newClient(ctx, alicexmr, alicedcr)
if err != nil {
return err
}
alice := partClient{client: pc}

ic, err := newClient(ctx, "http://127.0.0.1:28184/json_rpc", "trading2")
ic, err := newClient(ctx, alicexmr, alicedcr)
if err != nil {
return err
}
Expand Down Expand Up @@ -1116,13 +1236,13 @@ func aliceBailsBeforeXmrInit(ctx context.Context) error {
// refund is a failed trade where both parties have sent their initial funds and
// both get them back minus fees.
func refund(ctx context.Context) error {
pc, err := newClient(ctx, "http://127.0.0.1:28284/json_rpc", "trading1")
pc, err := newClient(ctx, alicexmr, alicedcr)
if err != nil {
return err
}
alice := partClient{client: pc}

ic, err := newClient(ctx, "http://127.0.0.1:28184/json_rpc", "trading2")
ic, err := newClient(ctx, bobxmr, bobdcr)
if err != nil {
return err
}
Expand Down Expand Up @@ -1178,15 +1298,30 @@ func refund(ctx context.Context) error {
return err
}

// NOTE: This wallet must sync so may take a long time on mainnet.
// TODO: Wait for wallet sync rather than a dumb sleep.
time.Sleep(time.Second * 40)

var bal *rpc.GetBalanceResponse
balReq := rpc.GetBalanceRequest{}
bal, err := xmrChecker.GetBalance(ctx, &balReq)
if err != nil {
return err
ticker := time.NewTicker(time.Second * 5)
defer ticker.Stop()
timeout := time.After(time.Minute)
out:
for {
select {
case <-ticker.C:
bal, err = xmrChecker.GetBalance(ctx, &balReq)
if err != nil {
return err
}
if bal.Balance > 0 {
break out
}
case <-timeout:
return errors.New("xmr wallet not synced after one minute")
case <-ctx.Done():
return ctx.Err()
}

}

if bal.Balance != xmrAmt {
return fmt.Errorf("expected refund xmr balance of %d but got %d", xmrAmt, bal.Balance)
}
Expand All @@ -1199,13 +1334,13 @@ func refund(ctx context.Context) error {
// bobBailsAfterXmrInit is a failed trade where bob disappears after both parties
// init and alice takes all his dcr while losing her xmr. Bob gets nothing.
func bobBailsAfterXmrInit(ctx context.Context) error {
pc, err := newClient(ctx, "http://127.0.0.1:28284/json_rpc", "trading1")
pc, err := newClient(ctx, alicexmr, alicedcr)
if err != nil {
return err
}
alice := partClient{client: pc}

ic, err := newClient(ctx, "http://127.0.0.1:28184/json_rpc", "trading2")
ic, err := newClient(ctx, bobxmr, bobdcr)
if err != nil {
return err
}
Expand Down

0 comments on commit 6c5ff99

Please sign in to comment.