feat: implement net_pairs (#495)
@@ -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"},
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -147,3 +147,13 @@ type AddressesResponse struct {
|
||||
type PeersResponse struct {
|
||||
Addrs []string `json:"addresses" validate:"dive,required"`
|
||||
}
|
||||
|
||||
// PairsRequest ...
|
||||
type PairsRequest struct {
|
||||
SearchTime uint64 `json:"searchTime"` // in seconds
|
||||
}
|
||||
|
||||
// PairsResponse ...
|
||||
type PairsResponse struct {
|
||||
Pairs []*types.Pair
|
||||
}
|
||||
|
||||
44
common/types/pairs.go
Normal file
@@ -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
|
||||
}
|
||||
86
rpc/net.go
@@ -4,6 +4,7 @@
|
||||
package rpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
@@ -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
|
||||
@@ -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,
|
||||
}
|
||||
@@ -73,6 +88,75 @@ 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(&rpctypes.DiscoverRequest{
|
||||
Provides: "",
|
||||
SearchTime: req.SearchTime,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pairs := make(map[ethcommon.Address]*types.Pair)
|
||||
|
||||
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 {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, o := range msg.Offers {
|
||||
address := o.EthAsset.Address()
|
||||
pair, exists := pairs[address]
|
||||
|
||||
if !exists {
|
||||
pair = types.NewPair(o.EthAsset)
|
||||
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
|
||||
} else {
|
||||
pair.Token.Name = "Ether"
|
||||
pair.Token.Symbol = "ETH"
|
||||
pair.Token.NumDecimals = 18
|
||||
pair.Verified = true
|
||||
}
|
||||
pairs[address] = pair
|
||||
}
|
||||
|
||||
err = pair.AddOffer(o)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pairsArray := make([]*types.Pair, 0, len(pairs))
|
||||
for _, pair := range pairs {
|
||||
if pair.EthAsset.IsETH() {
|
||||
pairsArray = append([]*types.Pair{pair}, pairsArray...)
|
||||
} else {
|
||||
pairsArray = append(pairsArray, pair)
|
||||
}
|
||||
}
|
||||
|
||||
resp.Pairs = pairsArray
|
||||
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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
package rpcclient
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/cockroachdb/apd/v3"
|
||||
@@ -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: "",
|
||||
@@ -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",
|
||||
@@ -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",
|
||||
|
||||
27
rpcclient/pairs.go
Normal file
@@ -0,0 +1,27 @@
|
||||
// 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{
|
||||
SearchTime: searchTime,
|
||||
}
|
||||
|
||||
res := &rpctypes.PairsResponse{}
|
||||
|
||||
if err := c.post(method, req, res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
@@ -129,6 +129,54 @@ func (s *IntegrationTestSuite) TestXMRMaker_Discover() {
|
||||
require.Equal(s.T(), 0, len(peerIDs))
|
||||
}
|
||||
|
||||
func (s *IntegrationTestSuite) TestXMRMaker_Pairs() {
|
||||
ctx := context.Background()
|
||||
bc := rpcclient.NewClient(ctx, defaultXMRMakerSwapdPort)
|
||||
|
||||
_, err := bc.MakeOffer(
|
||||
coins.StrToDecimal("1"),
|
||||
coins.StrToDecimal("2"),
|
||||
coins.StrToExchangeRate("200"),
|
||||
s.testToken,
|
||||
false)
|
||||
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
_, err = bc.MakeOffer(
|
||||
coins.StrToDecimal("1"),
|
||||
coins.StrToDecimal("2"),
|
||||
coins.StrToExchangeRate("200"),
|
||||
types.EthAssetETH,
|
||||
false)
|
||||
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
_, err = bc.MakeOffer(
|
||||
coins.StrToDecimal("1"),
|
||||
coins.StrToDecimal("2"),
|
||||
coins.StrToExchangeRate("200"),
|
||||
types.EthAssetETH,
|
||||
false)
|
||||
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
// Give offer advertisement time to propagate
|
||||
require.NoError(s.T(), common.SleepWithContext(ctx, time.Second))
|
||||
|
||||
ac := rpcclient.NewClient(ctx, defaultXMRTakerSwapdPort)
|
||||
pairs, err := ac.Pairs(3)
|
||||
|
||||
require.Equal(s.T(), len(pairs.Pairs), 2)
|
||||
|
||||
p1 := pairs.Pairs[0]
|
||||
p2 := pairs.Pairs[1]
|
||||
|
||||
require.Equal(s.T(), p1.Offers, uint64(2))
|
||||
require.Equal(s.T(), p2.Offers, uint64(1))
|
||||
|
||||
require.NoError(s.T(), err)
|
||||
}
|
||||
|
||||
func (s *IntegrationTestSuite) TestXMRTaker_Query() {
|
||||
s.testXMRTakerQuery(types.EthAssetETH)
|
||||
}
|
||||
|
||||
9
ui/.gitignore
vendored
@@ -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
ui/.prettierignore
Normal file
@@ -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
ui/.prettierrc
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"useTabs": true,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none",
|
||||
"printWidth": 100,
|
||||
"plugins": ["prettier-plugin-svelte"],
|
||||
"pluginSearchDirs": ["."],
|
||||
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
|
||||
}
|
||||
221
ui/.svelte-kit/ambient.d.ts
vendored
Normal file
@@ -0,0 +1,221 @@
|
||||
|
||||
// this file is generated — do not edit it
|
||||
|
||||
|
||||
/// <reference types="@sveltejs/kit" />
|
||||
|
||||
/**
|
||||
* Environment variables [loaded by Vite](https://vitejs.dev/guide/env-and-mode.html#env-files) from `.env` files and `process.env`. Like [`$env/dynamic/private`](https://kit.svelte.dev/docs/modules#$env-dynamic-private), this module cannot be imported into client-side code. This module only includes variables that _do not_ begin with [`config.kit.env.publicPrefix`](https://kit.svelte.dev/docs/configuration#env) _and do_ start with [`config.kit.env.privatePrefix`](https://kit.svelte.dev/docs/configuration#env) (if configured).
|
||||
*
|
||||
* _Unlike_ [`$env/dynamic/private`](https://kit.svelte.dev/docs/modules#$env-dynamic-private), the values exported from this module are statically injected into your bundle at build time, enabling optimisations like dead code elimination.
|
||||
*
|
||||
* ```ts
|
||||
* import { API_KEY } from '$env/static/private';
|
||||
* ```
|
||||
*
|
||||
* Note that all environment variables referenced in your code should be declared (for example in an `.env` file), even if they don't have a value until the app is deployed:
|
||||
*
|
||||
* ```
|
||||
* MY_FEATURE_FLAG=""
|
||||
* ```
|
||||
*
|
||||
* You can override `.env` values from the command line like so:
|
||||
*
|
||||
* ```bash
|
||||
* MY_FEATURE_FLAG="enabled" npm run dev
|
||||
* ```
|
||||
*/
|
||||
declare module '$env/static/private' {
|
||||
export const SHELL: string;
|
||||
export const npm_command: string;
|
||||
export const LSCOLORS: string;
|
||||
export const WINDOWID: string;
|
||||
export const npm_config_userconfig: string;
|
||||
export const COLORTERM: string;
|
||||
export const npm_config_cache: string;
|
||||
export const LESS: string;
|
||||
export const NVM_INC: string;
|
||||
export const CONDA_EXE: string;
|
||||
export const _CE_M: string;
|
||||
export const I3SOCK: string;
|
||||
export const NODE: string;
|
||||
export const COLOR: string;
|
||||
export const npm_config_local_prefix: string;
|
||||
export const KITTY_PID: string;
|
||||
export const npm_config_globalconfig: string;
|
||||
export const EDITOR: string;
|
||||
export const GTK_MODULES: string;
|
||||
export const XDG_SEAT: string;
|
||||
export const PWD: string;
|
||||
export const LOGNAME: string;
|
||||
export const XDG_SESSION_TYPE: string;
|
||||
export const npm_config_init_module: string;
|
||||
export const _: string;
|
||||
export const XAUTHORITY: string;
|
||||
export const DESKTOP_STARTUP_ID: string;
|
||||
export const KITTY_PUBLIC_KEY: string;
|
||||
export const MOTD_SHOWN: string;
|
||||
export const HOME: string;
|
||||
export const LANG: string;
|
||||
export const LS_COLORS: string;
|
||||
export const npm_package_version: string;
|
||||
export const KITTY_WINDOW_ID: string;
|
||||
export const INIT_CWD: string;
|
||||
export const npm_lifecycle_script: string;
|
||||
export const NVM_DIR: string;
|
||||
export const XDG_SESSION_CLASS: string;
|
||||
export const TERMINFO: string;
|
||||
export const TERM: string;
|
||||
export const npm_package_name: string;
|
||||
export const ZSH: string;
|
||||
export const _CE_CONDA: string;
|
||||
export const npm_config_prefix: string;
|
||||
export const USER: string;
|
||||
export const CONDA_SHLVL: string;
|
||||
export const DISPLAY: string;
|
||||
export const npm_lifecycle_event: string;
|
||||
export const SHLVL: string;
|
||||
export const NVM_CD_FLAGS: string;
|
||||
export const PAGER: string;
|
||||
export const XDG_VTNR: string;
|
||||
export const XDG_SESSION_ID: string;
|
||||
export const npm_config_user_agent: string;
|
||||
export const npm_execpath: string;
|
||||
export const CONDA_PYTHON_EXE: string;
|
||||
export const XDG_RUNTIME_DIR: string;
|
||||
export const DEBUGINFOD_URLS: string;
|
||||
export const npm_package_json: string;
|
||||
export const npm_config_noproxy: string;
|
||||
export const PATH: string;
|
||||
export const npm_config_metrics_registry: string;
|
||||
export const npm_config_node_gyp: string;
|
||||
export const DBUS_SESSION_BUS_ADDRESS: string;
|
||||
export const npm_config_global_prefix: string;
|
||||
export const NVM_BIN: string;
|
||||
export const MAIL: string;
|
||||
export const npm_config_scripts_prepend_node_path: string;
|
||||
export const KITTY_INSTALLATION_DIR: string;
|
||||
export const npm_node_execpath: string;
|
||||
export const OLDPWD: string;
|
||||
export const NODE_ENV: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to [`$env/static/private`](https://kit.svelte.dev/docs/modules#$env-static-private), except that it only includes environment variables that begin with [`config.kit.env.publicPrefix`](https://kit.svelte.dev/docs/configuration#env) (which defaults to `PUBLIC_`), and can therefore safely be exposed to client-side code.
|
||||
*
|
||||
* Values are replaced statically at build time.
|
||||
*
|
||||
* ```ts
|
||||
* import { PUBLIC_BASE_URL } from '$env/static/public';
|
||||
* ```
|
||||
*/
|
||||
declare module '$env/static/public' {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This module provides access to runtime environment variables, as defined by the platform you're running on. For example if you're using [`adapter-node`](https://github.com/sveltejs/kit/tree/master/packages/adapter-node) (or running [`vite preview`](https://kit.svelte.dev/docs/cli)), this is equivalent to `process.env`. This module only includes variables that _do not_ begin with [`config.kit.env.publicPrefix`](https://kit.svelte.dev/docs/configuration#env) _and do_ start with [`config.kit.env.privatePrefix`](https://kit.svelte.dev/docs/configuration#env) (if configured).
|
||||
*
|
||||
* This module cannot be imported into client-side code.
|
||||
*
|
||||
* ```ts
|
||||
* import { env } from '$env/dynamic/private';
|
||||
* console.log(env.DEPLOYMENT_SPECIFIC_VARIABLE);
|
||||
* ```
|
||||
*
|
||||
* > In `dev`, `$env/dynamic` always includes environment variables from `.env`. In `prod`, this behavior will depend on your adapter.
|
||||
*/
|
||||
declare module '$env/dynamic/private' {
|
||||
export const env: {
|
||||
SHELL: string;
|
||||
npm_command: string;
|
||||
LSCOLORS: string;
|
||||
WINDOWID: string;
|
||||
npm_config_userconfig: string;
|
||||
COLORTERM: string;
|
||||
npm_config_cache: string;
|
||||
LESS: string;
|
||||
NVM_INC: string;
|
||||
CONDA_EXE: string;
|
||||
_CE_M: string;
|
||||
I3SOCK: string;
|
||||
NODE: string;
|
||||
COLOR: string;
|
||||
npm_config_local_prefix: string;
|
||||
KITTY_PID: string;
|
||||
npm_config_globalconfig: string;
|
||||
EDITOR: string;
|
||||
GTK_MODULES: string;
|
||||
XDG_SEAT: string;
|
||||
PWD: string;
|
||||
LOGNAME: string;
|
||||
XDG_SESSION_TYPE: string;
|
||||
npm_config_init_module: string;
|
||||
_: string;
|
||||
XAUTHORITY: string;
|
||||
DESKTOP_STARTUP_ID: string;
|
||||
KITTY_PUBLIC_KEY: string;
|
||||
MOTD_SHOWN: string;
|
||||
HOME: string;
|
||||
LANG: string;
|
||||
LS_COLORS: string;
|
||||
npm_package_version: string;
|
||||
KITTY_WINDOW_ID: string;
|
||||
INIT_CWD: string;
|
||||
npm_lifecycle_script: string;
|
||||
NVM_DIR: string;
|
||||
XDG_SESSION_CLASS: string;
|
||||
TERMINFO: string;
|
||||
TERM: string;
|
||||
npm_package_name: string;
|
||||
ZSH: string;
|
||||
_CE_CONDA: string;
|
||||
npm_config_prefix: string;
|
||||
USER: string;
|
||||
CONDA_SHLVL: string;
|
||||
DISPLAY: string;
|
||||
npm_lifecycle_event: string;
|
||||
SHLVL: string;
|
||||
NVM_CD_FLAGS: string;
|
||||
PAGER: string;
|
||||
XDG_VTNR: string;
|
||||
XDG_SESSION_ID: string;
|
||||
npm_config_user_agent: string;
|
||||
npm_execpath: string;
|
||||
CONDA_PYTHON_EXE: string;
|
||||
XDG_RUNTIME_DIR: string;
|
||||
DEBUGINFOD_URLS: string;
|
||||
npm_package_json: string;
|
||||
npm_config_noproxy: string;
|
||||
PATH: string;
|
||||
npm_config_metrics_registry: string;
|
||||
npm_config_node_gyp: string;
|
||||
DBUS_SESSION_BUS_ADDRESS: string;
|
||||
npm_config_global_prefix: string;
|
||||
NVM_BIN: string;
|
||||
MAIL: string;
|
||||
npm_config_scripts_prepend_node_path: string;
|
||||
KITTY_INSTALLATION_DIR: string;
|
||||
npm_node_execpath: string;
|
||||
OLDPWD: string;
|
||||
NODE_ENV: string;
|
||||
[key: `PUBLIC_${string}`]: undefined;
|
||||
[key: `${string}`]: string | undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to [`$env/dynamic/private`](https://kit.svelte.dev/docs/modules#$env-dynamic-private), but only includes variables that begin with [`config.kit.env.publicPrefix`](https://kit.svelte.dev/docs/configuration#env) (which defaults to `PUBLIC_`), and can therefore safely be exposed to client-side code.
|
||||
*
|
||||
* Note that public dynamic environment variables must all be sent from the server to the client, causing larger network requests — when possible, use `$env/static/public` instead.
|
||||
*
|
||||
* ```ts
|
||||
* import { env } from '$env/dynamic/public';
|
||||
* console.log(env.PUBLIC_DEPLOYMENT_SPECIFIC_VARIABLE);
|
||||
* ```
|
||||
*/
|
||||
declare module '$env/dynamic/public' {
|
||||
export const env: {
|
||||
[key: `PUBLIC_${string}`]: string | undefined;
|
||||
}
|
||||
}
|
||||
21
ui/.svelte-kit/generated/client/app.js
Normal file
@@ -0,0 +1,21 @@
|
||||
export { matchers } from './matchers.js';
|
||||
|
||||
export const nodes = [
|
||||
() => import('./nodes/0'),
|
||||
() => import('./nodes/1'),
|
||||
() => import('./nodes/2'),
|
||||
() => import('./nodes/3')
|
||||
];
|
||||
|
||||
export const server_loads = [];
|
||||
|
||||
export const dictionary = {
|
||||
"/": [2],
|
||||
"/offers/[token]": [3]
|
||||
};
|
||||
|
||||
export const hooks = {
|
||||
handleError: (({ error }) => { console.error(error) }),
|
||||
};
|
||||
|
||||
export { default as root } from '../root.svelte';
|
||||
1
ui/.svelte-kit/generated/client/matchers.js
Normal file
@@ -0,0 +1 @@
|
||||
export const matchers = {};
|
||||
1
ui/.svelte-kit/generated/client/nodes/0.js
Normal file
@@ -0,0 +1 @@
|
||||
export { default as component } from "../../../../src/routes/+layout.svelte";
|
||||
1
ui/.svelte-kit/generated/client/nodes/1.js
Normal file
@@ -0,0 +1 @@
|
||||
export { default as component } from "../../../../node_modules/@sveltejs/kit/src/runtime/components/error.svelte";
|
||||
1
ui/.svelte-kit/generated/client/nodes/2.js
Normal file
@@ -0,0 +1 @@
|
||||
export { default as component } from "../../../../src/routes/+page.svelte";
|
||||
3
ui/.svelte-kit/generated/client/nodes/3.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import * as universal from "../../../../src/routes/offers/[token]/+page.ts";
|
||||
export { universal };
|
||||
export { default as component } from "../../../../src/routes/offers/[token]/+page.svelte";
|
||||
1
ui/.svelte-kit/generated/client/nodes/4.js
Normal file
@@ -0,0 +1 @@
|
||||
export { default as component } from "../../../../src/routes/pairs/+page.svelte";
|
||||
54
ui/.svelte-kit/generated/root.svelte
Normal file
@@ -0,0 +1,54 @@
|
||||
<!-- This file is generated by @sveltejs/kit — do not edit it! -->
|
||||
<script>
|
||||
import { setContext, afterUpdate, onMount } from 'svelte';
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
// stores
|
||||
export let stores;
|
||||
export let page;
|
||||
|
||||
export let constructors;
|
||||
export let components = [];
|
||||
export let form;
|
||||
export let data_0 = null;
|
||||
export let data_1 = null;
|
||||
|
||||
if (!browser) {
|
||||
setContext('__svelte__', stores);
|
||||
}
|
||||
|
||||
$: stores.page.set(page);
|
||||
afterUpdate(stores.page.notify);
|
||||
|
||||
let mounted = false;
|
||||
let navigated = false;
|
||||
let title = null;
|
||||
|
||||
onMount(() => {
|
||||
const unsubscribe = stores.page.subscribe(() => {
|
||||
if (mounted) {
|
||||
navigated = true;
|
||||
title = document.title || 'untitled page';
|
||||
}
|
||||
});
|
||||
|
||||
mounted = true;
|
||||
return unsubscribe;
|
||||
});
|
||||
</script>
|
||||
|
||||
{#if constructors[1]}
|
||||
<svelte:component this={constructors[0]} bind:this={components[0]} data={data_0}>
|
||||
<svelte:component this={constructors[1]} bind:this={components[1]} data={data_1} {form} />
|
||||
</svelte:component>
|
||||
{:else}
|
||||
<svelte:component this={constructors[0]} bind:this={components[0]} data={data_0} {form} />
|
||||
{/if}
|
||||
|
||||
{#if mounted}
|
||||
<div id="svelte-announcer" aria-live="assertive" aria-atomic="true" style="position: absolute; left: 0; top: 0; clip: rect(0 0 0 0); clip-path: inset(50%); overflow: hidden; white-space: nowrap; width: 1px; height: 1px">
|
||||
{#if navigated}
|
||||
{title}
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
30
ui/.svelte-kit/generated/server/internal.js
Normal file
@@ -0,0 +1,30 @@
|
||||
|
||||
import root from '../root.svelte';
|
||||
import { set_building } from '__sveltekit/environment';
|
||||
import { set_assets } from '__sveltekit/paths';
|
||||
import { set_private_env, set_public_env } from '../../../node_modules/@sveltejs/kit/src/runtime/shared-server.js';
|
||||
|
||||
export const options = {
|
||||
app_template_contains_nonce: false,
|
||||
csp: {"mode":"auto","directives":{"upgrade-insecure-requests":false,"block-all-mixed-content":false},"reportOnly":{"upgrade-insecure-requests":false,"block-all-mixed-content":false}},
|
||||
csrf_check_origin: true,
|
||||
track_server_fetches: false,
|
||||
embedded: false,
|
||||
env_public_prefix: 'PUBLIC_',
|
||||
env_private_prefix: '',
|
||||
hooks: null, // added lazily, via `get_hooks`
|
||||
preload_strategy: "modulepreload",
|
||||
root,
|
||||
service_worker: false,
|
||||
templates: {
|
||||
app: ({ head, body, assets, nonce, env }) => "<!DOCTYPE html>\n<html lang=\"en\">\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<!--\n\t\t<link rel=\"icon\" href=\"" + assets + "/favicon.png\" />\n\t\t-->\n\t\t<meta name=\"viewport\" content=\"width=device-width\" />\n\t\t" + head + "\n\t</head>\n\t<body data-sveltekit-preload-data=\"hover\">\n\t\t<div style=\"display: contents\">" + body + "</div>\n\t</body>\n</html>\n",
|
||||
error: ({ status, message }) => "<!DOCTYPE html>\n<html lang=\"en\">\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>" + message + "</title>\n\n\t\t<style>\n\t\t\tbody {\n\t\t\t\t--bg: white;\n\t\t\t\t--fg: #222;\n\t\t\t\t--divider: #ccc;\n\t\t\t\tbackground: var(--bg);\n\t\t\t\tcolor: var(--fg);\n\t\t\t\tfont-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,\n\t\t\t\t\tUbuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: center;\n\t\t\t\tjustify-content: center;\n\t\t\t\theight: 100vh;\n\t\t\t\tmargin: 0;\n\t\t\t}\n\n\t\t\t.error {\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: center;\n\t\t\t\tmax-width: 32rem;\n\t\t\t\tmargin: 0 1rem;\n\t\t\t}\n\n\t\t\t.status {\n\t\t\t\tfont-weight: 200;\n\t\t\t\tfont-size: 3rem;\n\t\t\t\tline-height: 1;\n\t\t\t\tposition: relative;\n\t\t\t\ttop: -0.05rem;\n\t\t\t}\n\n\t\t\t.message {\n\t\t\t\tborder-left: 1px solid var(--divider);\n\t\t\t\tpadding: 0 0 0 1rem;\n\t\t\t\tmargin: 0 0 0 1rem;\n\t\t\t\tmin-height: 2.5rem;\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: center;\n\t\t\t}\n\n\t\t\t.message h1 {\n\t\t\t\tfont-weight: 400;\n\t\t\t\tfont-size: 1em;\n\t\t\t\tmargin: 0;\n\t\t\t}\n\n\t\t\t@media (prefers-color-scheme: dark) {\n\t\t\t\tbody {\n\t\t\t\t\t--bg: #222;\n\t\t\t\t\t--fg: #ddd;\n\t\t\t\t\t--divider: #666;\n\t\t\t\t}\n\t\t\t}\n\t\t</style>\n\t</head>\n\t<body>\n\t\t<div class=\"error\">\n\t\t\t<span class=\"status\">" + status + "</span>\n\t\t\t<div class=\"message\">\n\t\t\t\t<h1>" + message + "</h1>\n\t\t\t</div>\n\t\t</div>\n\t</body>\n</html>\n"
|
||||
},
|
||||
version_hash: "cgqvn8"
|
||||
};
|
||||
|
||||
export function get_hooks() {
|
||||
return {};
|
||||
}
|
||||
|
||||
export { set_assets, set_building, set_private_env, set_public_env };
|
||||
46
ui/.svelte-kit/tsconfig.json
Normal file
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"$lib": [
|
||||
"../src/lib"
|
||||
],
|
||||
"$lib/*": [
|
||||
"../src/lib/*"
|
||||
]
|
||||
},
|
||||
"rootDirs": [
|
||||
"..",
|
||||
"./types"
|
||||
],
|
||||
"importsNotUsedAsValues": "error",
|
||||
"isolatedModules": true,
|
||||
"preserveValueImports": true,
|
||||
"lib": [
|
||||
"esnext",
|
||||
"DOM",
|
||||
"DOM.Iterable"
|
||||
],
|
||||
"moduleResolution": "node",
|
||||
"module": "esnext",
|
||||
"target": "esnext",
|
||||
"ignoreDeprecations": "5.0"
|
||||
},
|
||||
"include": [
|
||||
"ambient.d.ts",
|
||||
"./types/**/$types.d.ts",
|
||||
"../vite.config.ts",
|
||||
"../src/**/*.js",
|
||||
"../src/**/*.ts",
|
||||
"../src/**/*.svelte",
|
||||
"../tests/**/*.js",
|
||||
"../tests/**/*.ts",
|
||||
"../tests/**/*.svelte"
|
||||
],
|
||||
"exclude": [
|
||||
"../node_modules/**",
|
||||
"./[!ambient.d.ts]**",
|
||||
"../src/service-worker.js",
|
||||
"../src/service-worker.ts",
|
||||
"../src/service-worker.d.ts"
|
||||
]
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"moduleResolution": "bundler",
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
/**
|
||||
* svelte-preprocess cannot figure out whether you have
|
||||
* a value or a type, so tell TypeScript to enforce using
|
||||
* `import type` instead of `import` for Types.
|
||||
*/
|
||||
"verbatimModuleSyntax": true,
|
||||
"isolatedModules": true,
|
||||
"resolveJsonModule": true,
|
||||
/**
|
||||
* To have warnings / errors of the Svelte compiler at the
|
||||
* correct position, enable source maps by default.
|
||||
*/
|
||||
"sourceMap": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
/**
|
||||
* Typecheck JS in `.svelte` and `.js` files by default.
|
||||
* Disable this if you'd like to use dynamic types.
|
||||
*/
|
||||
"checkJs": true
|
||||
},
|
||||
/**
|
||||
* Use global.d.ts instead of compilerOptions.types
|
||||
* to avoid limiting type declarations.
|
||||
*/
|
||||
"include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.svelte"]
|
||||
}
|
||||
@@ -4,20 +4,36 @@
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"dev": "vite dev",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
"preview": "vite preview",
|
||||
"test": "npm run test:integration && npm run test:unit",
|
||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
||||
"test:integration": "playwright test",
|
||||
"test:unit": "vitest",
|
||||
"lint": "prettier --plugin-search-dir . --check .",
|
||||
"format": "prettier --plugin-search-dir . --write ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.28.1",
|
||||
"@sveltejs/adapter-auto": "^2.1.0",
|
||||
"@sveltejs/kit": "^1.20.4",
|
||||
"@sveltejs/vite-plugin-svelte": "^2.0.3",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"postcss": "^8.4.23",
|
||||
"postcss": "^8.4.24",
|
||||
"postcss-load-config": "^4.0.1",
|
||||
"svelte": "^3.57.0",
|
||||
"prettier": "^2.8.0",
|
||||
"prettier-plugin-svelte": "^2.10.1",
|
||||
"svelte": "^4.0.0",
|
||||
"svelte-check": "^3.4.3",
|
||||
"svelte-heros-v2": "^0.4.2",
|
||||
"svelte-preprocess": "^5.0.3",
|
||||
"tailwindcss": "^3.3.1",
|
||||
"vite": "^4.3.5"
|
||||
"tslib": "^2.4.1",
|
||||
"typescript": "^5.0.0",
|
||||
"vite": "^4.3.6",
|
||||
"vitest": "^0.32.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@popperjs/core": "^2.11.7",
|
||||
|
||||
12
ui/playwright.config.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import type { PlaywrightTestConfig } from '@playwright/test';
|
||||
|
||||
const config: PlaywrightTestConfig = {
|
||||
webServer: {
|
||||
command: 'npm run build && npm run preview',
|
||||
port: 4173
|
||||
},
|
||||
testDir: 'tests',
|
||||
testMatch: /(.+\.)?(test|spec)\.[jt]s/
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -4,8 +4,8 @@ const autoprefixer = require("autoprefixer");
|
||||
const config = {
|
||||
plugins: [
|
||||
//Some plugins, like tailwindcss/nesting, need to run before Tailwind,
|
||||
tailwindcss(),
|
||||
//But others, like autoprefixer, need to run after,
|
||||
tailwindcss(), //But others, like autoprefixer, need to run after,
|
||||
autoprefixer,
|
||||
autoprefixer,
|
||||
],
|
||||
};
|
||||
|
||||
@@ -2,14 +2,11 @@
|
||||
import svelteLogo from './assets/svelte.svg'
|
||||
import viteLogo from '/vite.svg'
|
||||
import Navbar from './lib/Navbar.svelte'
|
||||
import OffersTable from './lib/OffersTable.svelte'
|
||||
import TakeDealDialog from './lib/TakeDealDialog.svelte'
|
||||
import Offers from './lib/Offers.svelte'
|
||||
</script>
|
||||
|
||||
<main>
|
||||
<Navbar />
|
||||
<OffersTable />
|
||||
<TakeDealDialog />
|
||||
</main>
|
||||
|
||||
<style>
|
||||
|
||||
12
ui/src/app.d.ts
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
// See https://kit.svelte.dev/docs/types#app
|
||||
// for information about these interfaces
|
||||
declare global {
|
||||
namespace App {
|
||||
// interface Error {}
|
||||
// interface Locals {}
|
||||
// interface PageData {}
|
||||
// interface Platform {}
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
||||
14
ui/src/app.html
Normal file
@@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<!--
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
-->
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,18 +1,20 @@
|
||||
/* Write your global styles here, in PostCSS syntax */
|
||||
|
||||
/* Write your global styles here, in PostCSS syntax */
|
||||
|
||||
@tailwind base;
|
||||
|
||||
@font-face {
|
||||
font-family: 'Iosevka';
|
||||
font-display: swap;
|
||||
font-weight: 400;
|
||||
font-stretch: normal;
|
||||
font-style: normal;
|
||||
src: url('assets/iosevka-regular.ttf') format('truetype');
|
||||
font-family: "Iosevka";
|
||||
font-display: swap;
|
||||
font-weight: 400;
|
||||
font-stretch: normal;
|
||||
font-style: normal;
|
||||
src: url("assets/iosevka-regular.ttf") format("truetype");
|
||||
}
|
||||
|
||||
:root {
|
||||
font-family: 'Iosevka', Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||
font-family: "Iosevka", Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||
line-height: 1.5;
|
||||
font-weight: 400;
|
||||
|
||||
@@ -80,4 +82,3 @@ button:focus-visible {
|
||||
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
|
||||
BIN
ui/src/assets/coins/1inch@2x.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
ui/src/assets/coins/aave@2x.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
ui/src/assets/coins/ada@2x.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
ui/src/assets/coins/algo@2x.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
ui/src/assets/coins/amp@2x.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
ui/src/assets/coins/ampl@2x.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
ui/src/assets/coins/ankr@2x.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
ui/src/assets/coins/ant@2x.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
ui/src/assets/coins/ape@2x.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
ui/src/assets/coins/atom@2x.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
ui/src/assets/coins/avax@2x.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
ui/src/assets/coins/bat@2x.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
ui/src/assets/coins/bch@2x.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
ui/src/assets/coins/bnb@2x.png
Normal file
|
After Width: | Height: | Size: 721 B |
BIN
ui/src/assets/coins/bsv@2x.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
ui/src/assets/coins/btc@2x.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
ui/src/assets/coins/btg@2x.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
ui/src/assets/coins/btt@2x.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
ui/src/assets/coins/chz@2x.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
ui/src/assets/coins/comp@2x.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
ui/src/assets/coins/crv@2x.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
ui/src/assets/coins/dai@2x.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
ui/src/assets/coins/dash@2x.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
ui/src/assets/coins/dcr@2x.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
ui/src/assets/coins/dgb@2x.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
ui/src/assets/coins/doge@2x.png
Normal file
|
After Width: | Height: | Size: 811 B |
BIN
ui/src/assets/coins/dot@2x.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
ui/src/assets/coins/enj@2x.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
ui/src/assets/coins/eos@2x.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
ui/src/assets/coins/etc@2x.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
ui/src/assets/coins/eth@2x.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
ui/src/assets/coins/eur@2x.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
ui/src/assets/coins/fil@2x.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
ui/src/assets/coins/flux@2x.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
ui/src/assets/coins/gold@2x.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
ui/src/assets/coins/grt@2x.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
ui/src/assets/coins/mkr@2x.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
ui/src/assets/coins/neo@2x.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
ui/src/assets/coins/nexo@2x.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
ui/src/assets/coins/ont@2x.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
ui/src/assets/coins/ox@2x.png
Normal file
|
After Width: | Height: | Size: 962 B |
BIN
ui/src/assets/coins/pax@2x.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
ui/src/assets/coins/paxg@2x.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
ui/src/assets/coins/qnt@2x.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
ui/src/assets/coins/qtum@2x.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
ui/src/assets/coins/rvn@2x.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
ui/src/assets/coins/sand@2x.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
ui/src/assets/coins/sc@2x.png
Normal file
|
After Width: | Height: | Size: 929 B |
BIN
ui/src/assets/coins/snt@2x.png
Normal file
|
After Width: | Height: | Size: 956 B |
BIN
ui/src/assets/coins/snx@2x.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
ui/src/assets/coins/sol@2x.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
ui/src/assets/coins/steem@2x.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
ui/src/assets/coins/storj@2x.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
ui/src/assets/coins/stx@2x.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
ui/src/assets/coins/sushi@2x.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
ui/src/assets/coins/theta@2x.png
Normal file
|
After Width: | Height: | Size: 661 B |
BIN
ui/src/assets/coins/tomo@2x.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
ui/src/assets/coins/trx@2x.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
ui/src/assets/coins/tusd@2x.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
ui/src/assets/coins/uni@2x.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
61
ui/src/assets/coins/unknown.svg
Normal file
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="48.501175mm"
|
||||
height="48.501175mm"
|
||||
viewBox="0 0 48.501175 48.501175"
|
||||
version="1.1"
|
||||
id="svg5"
|
||||
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
|
||||
sodipodi:docname="unknown.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview7"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="mm"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.5459244"
|
||||
inkscape:cx="58.541027"
|
||||
inkscape:cy="75.682875"
|
||||
inkscape:window-width="1596"
|
||||
inkscape:window-height="861"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1" />
|
||||
<defs
|
||||
id="defs2" />
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-92.8564,-66.860764)">
|
||||
<circle
|
||||
style="fill:#e4e4e4;fill-opacity:1;stroke:none;stroke-width:0.499999;stroke-linecap:round;stroke-linejoin:round"
|
||||
id="path236"
|
||||
cx="117.10699"
|
||||
cy="91.111351"
|
||||
r="24.000587" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:30.088px;line-height:1.25;font-family:'Font Awesome 6 Free';-inkscape-font-specification:'Font Awesome 6 Free';fill:#a0a0a0;fill-opacity:1;stroke:none;stroke-width:0.752202"
|
||||
x="107.70449"
|
||||
y="102.39435"
|
||||
id="text1576"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan1574"
|
||||
style="font-style:normal;font-variant:normal;font-weight:900;font-stretch:normal;font-family:'Font Awesome 6 Free';-inkscape-font-specification:'Font Awesome 6 Free Heavy';fill:#a0a0a0;fill-opacity:1;stroke-width:0.752202"
|
||||
x="107.70449"
|
||||
y="102.39435">?</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
BIN
ui/src/assets/coins/usd@2x.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
ui/src/assets/coins/usdc@2x.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
ui/src/assets/coins/usdt@2x.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
ui/src/assets/coins/vet@2x.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
ui/src/assets/coins/waves@2x.png
Normal file
|
After Width: | Height: | Size: 536 B |
BIN
ui/src/assets/coins/wax@2x.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
ui/src/assets/coins/wbtc@2x.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
ui/src/assets/coins/xem@2x.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
ui/src/assets/coins/xlm@2x.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |