Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add pairs #495

Merged
merged 13 commits into from
Aug 28, 2023
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
47 changes: 47 additions & 0 deletions cmd/swapcli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,20 @@ func cliApp() *cli.App {
swapdPortFlag,
},
},
{
Name: "pairs",
Aliases: []string{"p"},
Usage: "List active pairs",
Action: runPairs,
Flags: []cli.Flag{
swapdPortFlag,
&cli.Uint64Flag{
Name: flagSearchTime,
Usage: "Duration of time to search for, in seconds",
Value: defaultDiscoverSearchTimeSecs,
},
},
},
{
Name: "balances",
Aliases: []string{"b"},
Expand Down Expand Up @@ -536,6 +550,39 @@ func runPeers(ctx *cli.Context) error {
return nil
}

func runPairs(ctx *cli.Context) error {
searchTime := ctx.Uint64(flagSearchTime)

c := newClient(ctx)
resp, err := c.Pairs(searchTime)
if err != nil {
return err
}

for i, a := range resp.Pairs {
var verified string
if a.Verified {
verified = "Yes"
} else {
verified = "No"
}

fmt.Printf("Pair %d:\n", i+1)
fmt.Printf(" Name: %s\n", a.Token.Symbol)
fmt.Printf(" Token: %s\n", a.Token.Address)
fmt.Printf(" Verified: %s\n", verified)
fmt.Printf(" Offers: %d\n", a.Offers)
fmt.Printf(" Reported Liquidity XMR: %f\n", a.ReportedLiquidityXMR)
fmt.Println()
}

if len(resp.Pairs) == 0 {
fmt.Println("[none]")
}

return nil
}

func runBalances(ctx *cli.Context) error {
c := newClient(ctx)

Expand Down
8 changes: 8 additions & 0 deletions common/rpctypes/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,11 @@ type AddressesResponse struct {
type PeersResponse struct {
Addrs []string `json:"addresses" validate:"dive,required"`
}

// PairsRequest ...
type PairsRequest = DiscoverRequest
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since the Provides field of the request is always set to "", can you define this as a new type:

type PairsRequest struct {
    SearchTime uint64 `json:"searchTime"` // in seconds
}


// PairsResponse ...
type PairsResponse struct {
Pairs []*types.Pair
}
44 changes: 44 additions & 0 deletions common/types/pairs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright 2023 The AthanorLabs/atomic-swap Authors
// SPDX-License-Identifier: LGPL-3.0-only

package types

import (
"github.com/cockroachdb/apd/v3"

"github.com/athanorlabs/atomic-swap/coins"
)

// Pair represents a pair (Such as ETH / XMR)
type Pair struct {
ReportedLiquidityXMR *apd.Decimal `json:"reportedLiquidityXmr" validate:"required"`
EthAsset EthAsset `json:"ethAsset" validate:"required"`
Token coins.ERC20TokenInfo `json:"token" validate:"required"`
Offers uint64 `json:"offers" validate:"required"`
Verified bool `json:"verified" valdate:"required"`
}

// NewPair creates and returns a Pair
func NewPair(EthAsset EthAsset) *Pair {
pair := &Pair{
ReportedLiquidityXMR: apd.New(0, 0),
EthAsset: EthAsset,

// Always set to false for now until the verified-list
// is implemented
Verified: false,
}
return pair
}

// AddOffer adds an offer to a pair
func (pair *Pair) AddOffer(o *Offer) error {
_, err := coins.DecimalCtx().Add(pair.ReportedLiquidityXMR, pair.ReportedLiquidityXMR, o.MaxAmount)
if err != nil {
return err
}

pair.Offers++

return nil
}
82 changes: 81 additions & 1 deletion rpc/net.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package rpc

import (
"context"
"fmt"
"net/http"
"time"
Expand All @@ -18,6 +19,8 @@ import (
"github.com/athanorlabs/atomic-swap/common/types"
"github.com/athanorlabs/atomic-swap/net/message"
"github.com/athanorlabs/atomic-swap/protocol/swap"

ethcommon "github.com/ethereum/go-ethereum/common"
)

const defaultSearchTime = time.Second * 12
Expand All @@ -35,19 +38,31 @@ type Net interface {

// NetService is the RPC service prefixed by net_.
type NetService struct {
ctx context.Context
net Net
xmrtaker XMRTaker
xmrmaker XMRMaker
pb ProtocolBackend
sm swap.Manager
isBootnode bool
}

// NewNetService ...
func NewNetService(net Net, xmrtaker XMRTaker, xmrmaker XMRMaker, sm swap.Manager, isBootnode bool) *NetService {
func NewNetService(
ctx context.Context,
net Net,
xmrtaker XMRTaker,
xmrmaker XMRMaker,
pb ProtocolBackend,
sm swap.Manager,
isBootnode bool,
) *NetService {
return &NetService{
ctx: ctx,
net: net,
xmrtaker: xmrtaker,
xmrmaker: xmrmaker,
pb: pb,
sm: sm,
isBootnode: isBootnode,
}
Expand All @@ -73,6 +88,71 @@ func (s *NetService) Peers(_ *http.Request, _ *interface{}, resp *rpctypes.Peers
return nil
}

// Pairs returns all currently available pairs from offers of all peers
func (s *NetService) Pairs(_ *http.Request, req *rpctypes.PairsRequest, resp *rpctypes.PairsResponse) error {
if s.isBootnode {
return errUnsupportedForBootnode
}

peerIDs, err := s.discover(req)
if err != nil {
return err
}

addrs := make(map[ethcommon.Address]int)
pairs := make([]*types.Pair, 0, 100)

addrs[ethcommon.Address{}] = 0 // ETH/XMR pair is always first
pairs = append(pairs, types.NewPair(types.EthAsset{}))
pairs[0].Verified = true
pairs[0].Token = coins.ERC20TokenInfo{
NumDecimals: 18,
Name: "Ether",
Symbol: "ETH",
}

for _, p := range peerIDs {
msg, err := s.net.Query(p)
if err != nil {
log.Debugf("Failed to query peer ID %s", p)
continue
}
if len(msg.Offers) > 0 {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit for readability, but can you change this to:

if len(msg.Offers) == 0 {
    continue
}

// the code that's currently in this block here

for _, o := range msg.Offers {
address := o.EthAsset.Address()
index, exists := addrs[address]
pair := types.NewPair(o.EthAsset)
if !exists {
addrs[address] = index
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the value does not exist in the map, isn't index always 0? this seems off, can you simplify this logic to just have one map pairs := make(map[ethcommon.Address]*types.Pair) where the key is the ETH-asset?

if pair.EthAsset.IsToken() {
tokenInfo, tokenInfoErr := s.pb.ETHClient().ERC20Info(s.ctx, address)
if tokenInfoErr != nil {
log.Debugf("Error while reading token info: %s", tokenInfoErr)
continue
}
pair.Token = *tokenInfo
}
pairs = append(pairs, pair)
} else {
pair = pairs[index]
}
err = pair.AddOffer(o)
if err != nil {
return err
}
}
}
}

// Remove ETH/XMR pair if there is no offer
if pairs[0].Offers <= 0 {
pairs = pairs[1:]
}

resp.Pairs = pairs
return nil
}

// QueryAll discovers peers who provide a certain coin and queries all of them for their current offers.
func (s *NetService) QueryAll(_ *http.Request, req *rpctypes.QueryAllRequest, resp *rpctypes.QueryAllResponse) error {
if s.isBootnode {
Expand Down
10 changes: 9 additions & 1 deletion rpc/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,15 @@ func NewServer(cfg *Config) (*Server, error) {
case DatabaseNamespace:
err = rpcServer.RegisterService(NewDatabaseService(cfg.RecoveryDB), DatabaseNamespace)
case NetNamespace:
netService = NewNetService(cfg.Net, cfg.XMRTaker, cfg.XMRMaker, swapManager, isBootnode)
netService = NewNetService(
serverCtx,
cfg.Net,
cfg.XMRTaker,
cfg.XMRMaker,
cfg.ProtocolBackend,
swapManager,
isBootnode,
)
err = rpcServer.RegisterService(netService, NetNamespace)
case PersonalName:
err = rpcServer.RegisterService(NewPersonalService(serverCtx, cfg.XMRMaker, cfg.ProtocolBackend), PersonalName)
Expand Down
22 changes: 19 additions & 3 deletions rpcclient/net_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package rpcclient

import (
"context"
"testing"

"github.com/cockroachdb/apd/v3"
Expand All @@ -15,7 +16,12 @@ import (
)

func TestNet_Discover(t *testing.T) {
ns := rpc.NewNetService(new(mockNet), new(mockXMRTaker), nil, mockSwapManager(t), false)
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(func() {
cancel()
})

ns := rpc.NewNetService(ctx, new(mockNet), new(mockXMRTaker), nil, new(mockProtocolBackend), mockSwapManager(t), false)

req := &rpctypes.DiscoverRequest{
Provides: "",
Expand All @@ -29,7 +35,12 @@ func TestNet_Discover(t *testing.T) {
}

func TestNet_Query(t *testing.T) {
ns := rpc.NewNetService(new(mockNet), new(mockXMRTaker), nil, mockSwapManager(t), false)
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(func() {
cancel()
})

ns := rpc.NewNetService(ctx, new(mockNet), new(mockXMRTaker), nil, new(mockProtocolBackend), mockSwapManager(t), false)

req := &rpctypes.QueryPeerRequest{
PeerID: "12D3KooWDqCzbjexHEa8Rut7bzxHFpRMZyDRW1L6TGkL1KY24JH5",
Expand All @@ -43,7 +54,12 @@ func TestNet_Query(t *testing.T) {
}

func TestNet_TakeOffer(t *testing.T) {
ns := rpc.NewNetService(new(mockNet), new(mockXMRTaker), nil, mockSwapManager(t), false)
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(func() {
cancel()
})

ns := rpc.NewNetService(ctx, new(mockNet), new(mockXMRTaker), nil, new(mockProtocolBackend), mockSwapManager(t), false)

req := &rpctypes.TakeOfferRequest{
PeerID: "12D3KooWDqCzbjexHEa8Rut7bzxHFpRMZyDRW1L6TGkL1KY24JH5",
Expand Down
28 changes: 28 additions & 0 deletions rpcclient/pairs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright 2023 The AthanorLabs/atomic-swap Authors
// SPDX-License-Identifier: LGPL-3.0-only

package rpcclient

import (
"github.com/athanorlabs/atomic-swap/common/rpctypes"
)

// Pairs calls net_pairs to get pairs from all offers.
func (c *Client) Pairs(searchTime uint64) (*rpctypes.PairsResponse, error) {
const (
method = "net_pairs"
)

req := &rpctypes.PairsRequest{
Provides: "",
SearchTime: searchTime,
}

res := &rpctypes.PairsResponse{}

if err := c.post(method, req, res); err != nil {
return nil, err
}

return res, nil
}
9 changes: 9 additions & 0 deletions ui/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,12 @@ dist-ssr
*.njsproj
*.sln
*.sw?

/build
/.svelte-kit
/package
.env
.env.*
!.env.example
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
13 changes: 13 additions & 0 deletions ui/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example

# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json
yarn.lock
9 changes: 9 additions & 0 deletions ui/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"useTabs": true,
"singleQuote": true,
"trailingComma": "none",
"printWidth": 100,
"plugins": ["prettier-plugin-svelte"],
"pluginSearchDirs": ["."],
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
}
Loading