Skip to content

Commit

Permalink
premium: enable flexible settings with bbolt db
Browse files Browse the repository at this point in the history
Remove policy.conf management and switch to bbolt db for managing
premium settings. Provide APIs for cln and lnd to interact with
premium.

- Implement Observer for premium updates
- Poller detects updates and performs polling
  • Loading branch information
YusukeShimizu committed Jan 6, 2025
1 parent ff38dc8 commit 17b0abc
Show file tree
Hide file tree
Showing 41 changed files with 3,786 additions and 2,578 deletions.
10 changes: 9 additions & 1 deletion clightning/clightning.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"time"

"github.com/elementsproject/peerswap/log"
"github.com/elementsproject/peerswap/premium"

"github.com/btcsuite/btcd/chaincfg"
"github.com/elementsproject/glightning/gbitcoin"
Expand Down Expand Up @@ -46,6 +47,10 @@ var methods = []peerswaprpcMethod{
&ReloadPolicyFile{},
&GetRequestedSwaps{},
&ListConfig{},
&GetPremiumRate{},
&SetPremiumRate{},
&GetDefaultPremiumRate{},
&SetDefaultPremiumRate{},
}

var devmethods = []peerswaprpcMethod{}
Expand All @@ -70,6 +75,7 @@ type ClightningClient struct {
requestedSwaps *swap.RequestedSwapsPrinter
policy PolicyReloader
pollService *poll.Service
ps *premium.Setting

gbitcoin *gbitcoin.Bitcoin
bitcoinChain *onchain.BitcoinOnChain
Expand Down Expand Up @@ -326,14 +332,16 @@ func (cl *ClightningClient) GetPreimage() (lightning.Preimage, error) {
func (cl *ClightningClient) SetupClients(liquidWallet wallet.Wallet,
swaps *swap.SwapService,
policy PolicyReloader, requestedSwaps *swap.RequestedSwapsPrinter,
bitcoin *gbitcoin.Bitcoin, bitcoinChain *onchain.BitcoinOnChain, pollService *poll.Service) {
bitcoin *gbitcoin.Bitcoin, bitcoinChain *onchain.BitcoinOnChain, pollService *poll.Service,
ps *premium.Setting) {
cl.liquidWallet = liquidWallet
cl.requestedSwaps = requestedSwaps
cl.swaps = swaps
cl.policy = policy
cl.gbitcoin = bitcoin
cl.pollService = pollService
cl.bitcoinChain = bitcoinChain
cl.ps = ps
if cl.bitcoinChain != nil {
cl.bitcoinNetwork = bitcoinChain.GetChain()
}
Expand Down
241 changes: 225 additions & 16 deletions clightning/clightning_commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (

"github.com/elementsproject/peerswap/log"
"github.com/elementsproject/peerswap/peerswaprpc"
"github.com/elementsproject/peerswap/premium"

"github.com/elementsproject/glightning/glightning"
"github.com/elementsproject/glightning/jrpc2"
Expand Down Expand Up @@ -628,11 +629,13 @@ func (l *ListPeers) Call() (jrpc2.Result, error) {
SatsOut: ReceiverSatsOut,
SatsIn: ReceiverSatsIn,
},
PaidFee: paidFees,
BTCSwapInPremiumRatePPM: p.BTCSwapInPremiumRatePPM,
BTCSwapOutPremiumRatePPM: p.BTCSwapOutPremiumRatePPM,
LBTCSwapInPremiumRatePPM: p.LBTCSwapInPremiumRatePPM,
LBTCSwapOutPremiumRatePPM: p.LBTCSwapOutPremiumRatePPM,
PaidFee: paidFees,
PeerPremium: &Premium{
BTCSwapInPremiumRatePPM: p.BTCSwapInPremiumRatePPM,
BTCSwapOutPremiumRatePPM: p.BTCSwapOutPremiumRatePPM,
LBTCSwapInPremiumRatePPM: p.LBTCSwapInPremiumRatePPM,
LBTCSwapOutPremiumRatePPM: p.LBTCSwapOutPremiumRatePPM,
},
}
channels, err := l.cl.glightning.ListChannelsBySource(peer.Id)
if err != nil {
Expand Down Expand Up @@ -1102,6 +1105,208 @@ func (c ListConfig) LongDescription() string {
return c.Description()
}

func toPremiumAssetType(asset string) premium.AssetType {
switch strings.ToUpper(asset) {
case "BTC":
return premium.BTC
case "LBTC":
return premium.LBTC
default:
return premium.AsserUnspecified
}
}

func toPremiumOperationType(operation string) premium.OperationType {
switch strings.ToUpper(operation) {
case "SWAP_IN":
return premium.SwapIn
case "SWAP_OUT":
return premium.SwapOut
default:
return premium.OperationUnspecified
}
}

type GetPremiumRate struct {
PeerID string `json:"peer_id"`
Asset string `json:"asset"`
Operation string `json:"operation"`
cl *ClightningClient `json:"-"`
}

func (c *GetPremiumRate) Name() string {
return "peerswap-getpremiumrate"
}

func (c *GetPremiumRate) New() interface{} {
return &GetPremiumRate{
cl: c.cl,
}
}

func (c *GetPremiumRate) Call() (jrpc2.Result, error) {
if !c.cl.isReady {
return nil, ErrWaitingForReady
}
e, err := c.cl.ps.GetRate(c.PeerID, toPremiumAssetType(c.Asset),
toPremiumOperationType(c.Operation))
if err != nil {
return nil, fmt.Errorf("error getting premium rate: %v", err)
}
return e.PremiumRatePPM().Value(), nil
}

func (c *GetPremiumRate) Get(client *ClightningClient) jrpc2.ServerMethod {
return &GetPremiumRate{
cl: client,
}
}

func (c GetPremiumRate) Description() string {
return "Get the premium rate for a peer"
}

func (c GetPremiumRate) LongDescription() string {
return c.Description()
}

type SetPremiumRate struct {
PeerID string `json:"peer_id"`
Asset string `json:"asset"`
Operation string `json:"operation"`
PremiumRatePPM int64 `json:"premium_rate_ppm"`
cl *ClightningClient `json:"-"`
}

func (c *SetPremiumRate) Name() string {
return "peerswap-setpremiumrate"
}

func (c *SetPremiumRate) New() interface{} {
return &SetPremiumRate{
cl: c.cl,
}
}

func (c *SetPremiumRate) Call() (jrpc2.Result, error) {
if !c.cl.isReady {
return nil, ErrWaitingForReady
}
rate, err := premium.NewPremiumRate(toPremiumAssetType(c.Asset),
toPremiumOperationType(c.Operation), premium.NewPPM(c.PremiumRatePPM))
if err != nil {
return nil, fmt.Errorf("error creating premium rate: %v", err)
}
err = c.cl.ps.SetRate(c.PeerID, rate)
if err != nil {
return nil, fmt.Errorf("error setting premium rate: %v", err)
}
return rate, nil
}

func (c *SetPremiumRate) Get(client *ClightningClient) jrpc2.ServerMethod {
return &SetPremiumRate{
cl: client,
}
}

func (c SetPremiumRate) Description() string {
return "Set the premium rate for a peer"
}

func (c SetPremiumRate) LongDescription() string {
return c.Description()
}

type SetDefaultPremiumRate struct {
Asset string `json:"asset"`
Operation string `json:"operation"`
PremiumRatePPM int64 `json:"premium_rate_ppm"`
cl *ClightningClient `json:"-"`
}

func (c *SetDefaultPremiumRate) Name() string {
return "peerswap-setdefaultpremiumrate"
}

func (c *SetDefaultPremiumRate) New() interface{} {
return &SetDefaultPremiumRate{
cl: c.cl,
}
}

func (c *SetDefaultPremiumRate) Call() (jrpc2.Result, error) {
if !c.cl.isReady {
return nil, ErrWaitingForReady
}
rate, err := premium.NewPremiumRate(toPremiumAssetType(c.Asset),
toPremiumOperationType(c.Operation), premium.NewPPM(c.PremiumRatePPM))
if err != nil {
return nil, fmt.Errorf("error creating premium rate: %v", err)
}
err = c.cl.ps.SetDefaultRate(rate)
if err != nil {
return nil, fmt.Errorf("error setting default premium rate: %v", err)
}
return rate, nil
}

func (c *SetDefaultPremiumRate) Get(client *ClightningClient) jrpc2.ServerMethod {
return &SetDefaultPremiumRate{
cl: client,
}
}

func (c SetDefaultPremiumRate) Description() string {
return "Set the default premium rate"
}

func (c SetDefaultPremiumRate) LongDescription() string {
return c.Description()
}

type GetDefaultPremiumRate struct {
Asset string `json:"asset"`
Operation string `json:"operation"`
cl *ClightningClient `json:"-"`
}

func (c *GetDefaultPremiumRate) Name() string {
return "peerswap-getdefaultpremiumrate"
}

func (c *GetDefaultPremiumRate) New() interface{} {
return &GetDefaultPremiumRate{
cl: c.cl,
}
}

func (c *GetDefaultPremiumRate) Call() (jrpc2.Result, error) {
if !c.cl.isReady {
return nil, ErrWaitingForReady
}
rate, err := c.cl.ps.GetDefaultRate(toPremiumAssetType(c.Asset),
toPremiumOperationType(c.Operation))
if err != nil {
return nil, fmt.Errorf("error getting default premium rate: %v", err)
}
return rate.PremiumRatePPM().Value(), nil
}

func (c *GetDefaultPremiumRate) Get(client *ClightningClient) jrpc2.ServerMethod {
return &GetDefaultPremiumRate{
cl: client,
}
}

func (c GetDefaultPremiumRate) Description() string {
return "Get the default premium rate"
}

func (c GetDefaultPremiumRate) LongDescription() string {
return c.Description()
}

type PeerSwapPeerChannel struct {
ChannelId string `json:"short_channel_id"`
LocalBalance uint64 `json:"local_balance"`
Expand All @@ -1116,18 +1321,22 @@ type SwapStats struct {
SatsIn uint64 `json:"total_sats_swapped_in"`
}

type Premium struct {
BTCSwapInPremiumRatePPM int64 `json:"btc_swap_in_premium_rate_ppm"`
BTCSwapOutPremiumRatePPM int64 `json:"btc_swap_out_premium_rate_ppm"`
LBTCSwapInPremiumRatePPM int64 `json:"lbtc_swap_in_premium_rate_ppm"`
LBTCSwapOutPremiumRatePPM int64 `json:"lbtc_swap_out_premium_rate_ppm"`
}

type PeerSwapPeer struct {
NodeId string `json:"nodeid"`
SwapsAllowed bool `json:"swaps_allowed"`
SupportedAssets []string `json:"supported_assets"`
Channels []*PeerSwapPeerChannel `json:"channels"`
AsSender *SwapStats `json:"sent,omitempty"`
AsReceiver *SwapStats `json:"received,omitempty"`
PaidFee uint64 `json:"total_fee_paid,omitempty"`
BTCSwapInPremiumRatePPM int64 `json:"btc_swap_in_premium_rate_ppm"`
BTCSwapOutPremiumRatePPM int64 `json:"btc_swap_out_premium_rate_ppm"`
LBTCSwapInPremiumRatePPM int64 `json:"lbtc_swap_in_premium_rate_ppm"`
LBTCSwapOutPremiumRatePPM int64 `json:"lbtc_swap_out_premium_rate_ppm"`
NodeId string `json:"nodeid"`
SwapsAllowed bool `json:"swaps_allowed"`
SupportedAssets []string `json:"supported_assets"`
Channels []*PeerSwapPeerChannel `json:"channels"`
AsSender *SwapStats `json:"sent,omitempty"`
AsReceiver *SwapStats `json:"received,omitempty"`
PaidFee uint64 `json:"total_fee_paid,omitempty"`
PeerPremium *Premium `json:"premium,omitempty"`
}

// checkFeatures checks if a node runs the peerswap Plugin
Expand Down
10 changes: 8 additions & 2 deletions cmd/peerswap-plugin/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/elementsproject/peerswap/onchain"
"github.com/elementsproject/peerswap/policy"
"github.com/elementsproject/peerswap/poll"
"github.com/elementsproject/peerswap/premium"
"github.com/elementsproject/peerswap/swap"
"github.com/elementsproject/peerswap/txwatcher"
"github.com/elementsproject/peerswap/wallet"
Expand Down Expand Up @@ -327,6 +328,10 @@ func run(ctx context.Context, lightningPlugin *clightning.ClightningClient) erro

// Manager for send message retry.
mesmgr := messages.NewManager()
ps, err := premium.NewSetting(swapDb)
if err != nil {
return err
}

swapServices := swap.NewSwapServices(swapStore,
requestedSwapStore,
Expand All @@ -342,6 +347,7 @@ func run(ctx context.Context, lightningPlugin *clightning.ClightningClient) erro
liquidOnChainService,
liquidOnChainService,
liquidTxWatcher,
ps,
)
swapService := swap.NewSwapService(swapServices)

Expand Down Expand Up @@ -370,12 +376,12 @@ func run(ctx context.Context, lightningPlugin *clightning.ClightningClient) erro
if err != nil {
return err
}
pollService := poll.NewService(1*time.Hour, 2*time.Hour, pollStore, lightningPlugin, pol, lightningPlugin, supportedAssets)
pollService := poll.NewService(1*time.Hour, 2*time.Hour, pollStore, lightningPlugin, pol, lightningPlugin, supportedAssets, ps)
pollService.Start()
defer pollService.Stop()

sp := swap.NewRequestedSwapsPrinter(requestedSwapStore)
lightningPlugin.SetupClients(liquidRpcWallet, swapService, pol, sp, bitcoinCli, bitcoinOnChainService, pollService)
lightningPlugin.SetupClients(liquidRpcWallet, swapService, pol, sp, bitcoinCli, bitcoinOnChainService, pollService, ps)

// We are ready to accept and handle requests.
// FIXME: Once we reworked the recovery service (non-blocking) we want to
Expand Down
Loading

0 comments on commit 17b0abc

Please sign in to comment.