Skip to content

Commit adfd6c8

Browse files
committed
cmd: add asset cmd
1 parent 2c7a9f8 commit adfd6c8

File tree

2 files changed

+244
-1
lines changed

2 files changed

+244
-1
lines changed

cmd/loop/assets.go

Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
package main
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"encoding/hex"
7+
"errors"
8+
"fmt"
9+
10+
"github.com/btcsuite/btcd/btcutil"
11+
"github.com/lightninglabs/loop/looprpc"
12+
"github.com/urfave/cli"
13+
)
14+
15+
var assetsCommands = cli.Command{
16+
17+
Name: "assets",
18+
ShortName: "a",
19+
Usage: "manage asset swaps",
20+
Description: `
21+
`,
22+
Subcommands: []cli.Command{
23+
assetsOutCommand,
24+
listOutCommand,
25+
listAvailableAssetsComand,
26+
},
27+
}
28+
var (
29+
assetsOutCommand = cli.Command{
30+
Name: "out",
31+
ShortName: "o",
32+
Usage: "swap asset out",
33+
ArgsUsage: "",
34+
Description: `
35+
List all reservations.
36+
`,
37+
Flags: []cli.Flag{
38+
cli.Uint64Flag{
39+
Name: "amt",
40+
Usage: "the amount in satoshis to loop out.",
41+
},
42+
cli.StringFlag{
43+
Name: "asset_id",
44+
Usage: "asset_id",
45+
},
46+
},
47+
Action: assetSwapOut,
48+
}
49+
listAvailableAssetsComand = cli.Command{
50+
Name: "available",
51+
ShortName: "a",
52+
Usage: "list available assets",
53+
ArgsUsage: "",
54+
Description: `
55+
List available assets from the loop server
56+
`,
57+
58+
Action: listAvailable,
59+
}
60+
listOutCommand = cli.Command{
61+
Name: "list",
62+
ShortName: "l",
63+
Usage: "list asset swaps",
64+
ArgsUsage: "",
65+
Description: `
66+
List all reservations.
67+
`,
68+
Action: listOut,
69+
}
70+
)
71+
72+
func assetSwapOut(ctx *cli.Context) error {
73+
// First set up the swap client itself.
74+
client, cleanup, err := getAssetsClient(ctx)
75+
if err != nil {
76+
return err
77+
}
78+
defer cleanup()
79+
80+
args := ctx.Args()
81+
82+
var amtStr string
83+
switch {
84+
case ctx.IsSet("amt"):
85+
amtStr = ctx.String("amt")
86+
case ctx.NArg() > 0:
87+
amtStr = args[0]
88+
args = args.Tail() //nolint: wastedassign
89+
default:
90+
// Show command help if no arguments and flags were provided.
91+
return cli.ShowCommandHelp(ctx, "out")
92+
}
93+
94+
amt, err := parseAmt(amtStr)
95+
if err != nil {
96+
return err
97+
}
98+
if amt <= 0 {
99+
return fmt.Errorf("amount must be greater than zero")
100+
}
101+
102+
assetId, err := hex.DecodeString(ctx.String("asset_id"))
103+
if err != nil {
104+
return err
105+
}
106+
107+
if len(assetId) != 32 {
108+
return fmt.Errorf("invalid asset id")
109+
}
110+
111+
// First we'll list the available assets.
112+
assets, err := client.ClientListAvailableAssets(
113+
context.Background(),
114+
&looprpc.ClientListAvailableAssetsRequest{},
115+
)
116+
if err != nil {
117+
return err
118+
}
119+
120+
// We now extract the asset name from the list of available assets.
121+
var assetName string
122+
for _, asset := range assets.AvailableAssets {
123+
if bytes.Equal(asset.AssetId, assetId) {
124+
assetName = asset.Name
125+
break
126+
}
127+
}
128+
if assetName == "" {
129+
return fmt.Errorf("asset not found")
130+
}
131+
132+
// First we'll quote the swap out to get the current fee and rate.
133+
quote, err := client.ClientGetAssetSwapOutQuote(
134+
context.Background(),
135+
&looprpc.ClientGetAssetSwapOutQuoteRequest{
136+
Amt: uint64(amt),
137+
Asset: assetId,
138+
},
139+
)
140+
if err != nil {
141+
return err
142+
}
143+
144+
totalSats := (amt * btcutil.Amount(quote.SatsPerUnit)).MulF64(float64(1) + quote.SwapFee)
145+
146+
fmt.Printf(satAmtFmt, "Fixed prepay cost:", quote.PrepayAmt)
147+
fmt.Printf(bpsFmt, "Swap fee:", int64(quote.SwapFee*10000))
148+
fmt.Printf(satAmtFmt, "Sats per unit:", quote.SatsPerUnit)
149+
fmt.Printf(satAmtFmt, "Swap Offchain payment:", totalSats)
150+
fmt.Printf(satAmtFmt, "Total Send off-chain:", totalSats+btcutil.Amount(quote.PrepayAmt))
151+
fmt.Printf(assetFmt, "Receive assets on-chain:", int64(amt), assetName)
152+
153+
fmt.Println("CONTINUE SWAP? (y/n): ")
154+
155+
var answer string
156+
fmt.Scanln(&answer)
157+
if answer != "y" {
158+
return errors.New("swap canceled")
159+
}
160+
161+
res, err := client.SwapOut(
162+
context.Background(),
163+
&looprpc.SwapOutRequest{
164+
Amt: uint64(amt),
165+
Asset: assetId,
166+
},
167+
)
168+
if err != nil {
169+
return err
170+
}
171+
172+
printRespJSON(res)
173+
return nil
174+
}
175+
176+
func listAvailable(ctx *cli.Context) error {
177+
// First set up the swap client itself.
178+
client, cleanup, err := getAssetsClient(ctx)
179+
if err != nil {
180+
return err
181+
}
182+
defer cleanup()
183+
184+
res, err := client.ClientListAvailableAssets(
185+
context.Background(),
186+
&looprpc.ClientListAvailableAssetsRequest{},
187+
)
188+
if err != nil {
189+
return err
190+
}
191+
192+
printRespJSON(res)
193+
return nil
194+
}
195+
func listOut(ctx *cli.Context) error {
196+
// First set up the swap client itself.
197+
client, cleanup, err := getAssetsClient(ctx)
198+
if err != nil {
199+
return err
200+
}
201+
defer cleanup()
202+
203+
res, err := client.ListAssetSwaps(
204+
context.Background(),
205+
&looprpc.ListAssetSwapsRequest{},
206+
)
207+
if err != nil {
208+
return err
209+
}
210+
211+
printRespJSON(res)
212+
return nil
213+
}
214+
215+
func getAssetsClient(ctx *cli.Context) (looprpc.AssetsClientClient, func(), error) {
216+
rpcServer := ctx.GlobalString("rpcserver")
217+
tlsCertPath, macaroonPath, err := extractPathArgs(ctx)
218+
if err != nil {
219+
return nil, nil, err
220+
}
221+
conn, err := getClientConn(rpcServer, tlsCertPath, macaroonPath)
222+
if err != nil {
223+
return nil, nil, err
224+
}
225+
cleanup := func() { conn.Close() }
226+
227+
loopClient := looprpc.NewAssetsClientClient(conn)
228+
return loopClient, cleanup, nil
229+
}

cmd/loop/main.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ var (
8383
listSwapsCommand, swapInfoCommand, getLiquidityParamsCommand,
8484
setLiquidityRuleCommand, suggestSwapCommand, setParamsCommand,
8585
getInfoCommand, abandonSwapCommand, reservationsCommands,
86-
instantOutCommand, listInstantOutsCommand,
86+
instantOutCommand, listInstantOutsCommand, assetsCommands,
8787
}
8888
)
8989

@@ -110,6 +110,20 @@ const (
110110
// Exchange rate: 0.0002 USD/SAT
111111
rateFmt = "%-36s %12.4f %s/SAT\n"
112112

113+
// bpsFmt formats a basis point value into a one line string, intended to
114+
// prettify the terminal output. For Instance,
115+
// fmt.Printf(f, "Service fee:", fee)
116+
// prints out as,
117+
// Service fee: 20 bps
118+
bpsFmt = "%-36s %12d bps\n"
119+
120+
// assetFmt formats an asset into a one line string, intended to
121+
// prettify the terminal output. For Instance,
122+
// fmt.Printf(f, "Receive asset onchain:", assetName, assetAmt)
123+
// prints out as,
124+
// Receive asset onchain: 0.0001 USD
125+
assetFmt = "%-36s %12d %s\n"
126+
113127
// blkFmt formats the number of blocks into a one line string, intended
114128
// to prettify the terminal output. For Instance,
115129
// fmt.Printf(f, "Conf target", target)

0 commit comments

Comments
 (0)