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

feat: use discountCT #318

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/grpc.md
Original file line number Diff line number Diff line change
Expand Up @@ -548,7 +548,7 @@ Channel creations are an optional extension to a submarine swap in the data type
| `to_wallet_id` | [`uint64`](#uint64) | optional | Wallet where the the funds will go if the swap succeeds. |
| `accept_zero_conf` | [`bool`](#bool) | optional | Whether the daemon should broadcast the claim transaction immediately after the lockup transaction is in the mempool. Should only be used for smaller amounts as it involves trust in Boltz. |
| `external_pay` | [`bool`](#bool) | optional | If set, the daemon will not pay the swap from an internal wallet. |
| `lockup_zero_conf` | [`bool`](#bool) | optional | Boltz does not accept 0-conf for Liquid transactions with a fee of 0.01 sat/vByte; when `lockup_zero_conf` is enabled, a fee of 0.1 sat/vByte will be used for Liquid lockup transactions |
| `lockup_zero_conf` | [`bool`](#bool) | optional | **Deprecated.** |
| `sat_per_vbyte` | [`double`](#double) | optional | Fee rate to use when sending from internal wallet |
| `accepted_pair` | [`PairInfo`](#pairinfo) | optional | Rates to accept for the swap. Queries latest from boltz otherwise The recommended way to use this is to pass a user approved value from a previous `GetPairInfo` call |

Expand Down Expand Up @@ -625,7 +625,7 @@ Channel creations are an optional extension to a submarine swap in the data type
| `refund_address` | [`string`](#string) | optional | address where the coins should go if the swap fails. Refunds will go to any of the daemons wallets otherwise. |
| `wallet_id` | [`uint64`](#uint64) | optional | wallet to pay swap from. only used if `send_from_internal` is set to true |
| `invoice` | [`string`](#string) | optional | bolt11 invoice, lnurl, or lnaddress to use for the swap. required in standalone mode. when connected to a lightning node, a new invoice for `amount` sats will be fetched the `amount` field has to be populated in case of a lnurl and lnaddress |
| `zero_conf` | [`bool`](#bool) | optional | Boltz does not accept 0-conf for Liquid transactions with a fee of 0.01 sat/vByte; when `zero_conf` is enabled, a fee of 0.1 sat/vByte will be used for Liquid lockup transactions |
| `zero_conf` | [`bool`](#bool) | optional | **Deprecated.** |
| `sat_per_vbyte` | [`double`](#double) | optional | Fee rate to use when sending from internal wallet |
| `accepted_pair` | [`PairInfo`](#pairinfo) | optional | Rates to accept for the swap. Queries latest from boltz otherwise The recommended way to use this is to pass a user approved value from a previous `GetPairInfo` call |

Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ require (
github.com/stretchr/testify v1.9.0
github.com/urfave/cli/v2 v2.25.7
github.com/vektra/mockery v1.1.2
github.com/vulpemventures/go-elements v0.5.3
github.com/vulpemventures/go-elements v0.5.5
golang.org/x/crypto v0.31.0
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8
golang.org/x/sync v0.10.0
Expand All @@ -60,7 +60,7 @@ require (
github.com/aokoli/goutils v1.0.1 // indirect
github.com/benbjohnson/clock v1.3.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/btcsuite/btcd/btcutil/psbt v1.1.8 // indirect
github.com/btcsuite/btcd/btcutil/psbt v1.1.9 // indirect
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f // indirect
github.com/btcsuite/btcwallet v0.16.10-0.20240404104514-b2f31f9045fb // indirect
github.com/btcsuite/btcwallet/wallet/txauthor v1.3.4 // indirect
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -438,8 +438,8 @@ github.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9Ur
github.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE=
github.com/btcsuite/btcd/btcutil v1.1.5 h1:+wER79R5670vs/ZusMTF1yTcRYE5GUsFbdjdisflzM8=
github.com/btcsuite/btcd/btcutil v1.1.5/go.mod h1:PSZZ4UitpLBWzxGd5VGOrLnmOjtPP/a6HaFo12zMs00=
github.com/btcsuite/btcd/btcutil/psbt v1.1.8 h1:4voqtT8UppT7nmKQkXV+T9K8UyQjKOn2z/ycpmJK8wg=
github.com/btcsuite/btcd/btcutil/psbt v1.1.8/go.mod h1:kA6FLH/JfUx++j9pYU0pyu+Z8XGBQuuTmuKYUf6q7/U=
github.com/btcsuite/btcd/btcutil/psbt v1.1.9 h1:UmfOIiWMZcVMOLaN+lxbbLSuoINGS1WmK1TZNI0b4yk=
github.com/btcsuite/btcd/btcutil/psbt v1.1.9/go.mod h1:ehBEvU91lxSlXtA+zZz3iFYx7Yq9eqnKx4/kSrnsvMY=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 h1:59Kx4K6lzOW5w6nFlA0v5+lk/6sjybR934QNHSJZPTQ=
Expand Down Expand Up @@ -1029,8 +1029,8 @@ github.com/vektra/mockery v1.1.2 h1:uc0Yn67rJpjt8U/mAZimdCKn9AeA97BOkjpmtBSlfP4=
github.com/vektra/mockery v1.1.2/go.mod h1:VcfZjKaFOPO+MpN4ZvwPjs4c48lkq1o3Ym8yHZJu0jU=
github.com/vulpemventures/fastsha256 v0.0.0-20160815193821-637e65642941 h1:CTcw80hz/Sw8hqlKX5ZYvBUF5gAHSHwdjXxRf/cjDcI=
github.com/vulpemventures/fastsha256 v0.0.0-20160815193821-637e65642941/go.mod h1:GXBJykxW2kUcktGdsgyay7uwwWvkljASfljNcT0mbh8=
github.com/vulpemventures/go-elements v0.5.3 h1:zaC/ynHFwCAzFSOMfzb6BcbD6FXASppSiGMycc95WVA=
github.com/vulpemventures/go-elements v0.5.3/go.mod h1:aBGuWXHaiAIUIcwqCdtEh2iQ3kJjKwHU9ywvhlcRSeU=
github.com/vulpemventures/go-elements v0.5.5 h1:oN76qcussRvVn8jkwaCI9+thmP9UeXwrzghAoWFzLAg=
github.com/vulpemventures/go-elements v0.5.5/go.mod h1:Tvhb+rZWv3lxoI5CdK03J3V+e2QVr/7UAnCYILxFSq4=
github.com/vulpemventures/go-secp256k1-zkp v1.1.6 h1:BmsrmXRLUibwa75Qkk8yELjpzCzlAjYFGLiLiOdq7Xo=
github.com/vulpemventures/go-secp256k1-zkp v1.1.6/go.mod h1:zo7CpgkuPgoe7fAV+inyxsI9IhGmcoFgyD8nqZaPSOM=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
Expand Down
6 changes: 2 additions & 4 deletions internal/lightning/lib/bolt12/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,8 @@ pub unsafe extern "C" fn decode_invoice(invoice: *const c_char) -> CResult<Invoi
Invoice {
amount_sat: convert_msats_to_sats(invoice.amount_msats()),
payment_hash: invoice.payment_hash().0,
expiry_date: invoice
.absolute_expiry()
.and_then(|d| Some(d.as_secs()))
.unwrap_or(0),
expiry_date: (invoice.created_at()
+ invoice.relative_expiry()).as_secs(),
}
}))
}
Expand Down
37 changes: 4 additions & 33 deletions internal/nursery/nursery.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@ import (

"github.com/BoltzExchange/boltz-client/v2/internal/onchain/wallet"

"github.com/BoltzExchange/boltz-client/v2/pkg/boltzrpc"
"github.com/btcsuite/btcd/chaincfg/chainhash"

"github.com/BoltzExchange/boltz-client/v2/internal/utils"
"github.com/BoltzExchange/boltz-client/v2/pkg/boltzrpc"

"github.com/BoltzExchange/boltz-client/v2/internal/lightning"
"github.com/BoltzExchange/boltz-client/v2/internal/onchain"
Expand Down Expand Up @@ -173,15 +171,9 @@ func (nursery *Nursery) recoverSwaps() error {
return err
}

var lockupTxs []string
var spentTxs []string

var swapIds []string
for _, swap := range swaps {
swapIds = append(swapIds, swap.Id)
if swap.Pair.From == boltz.CurrencyLiquid {
lockupTxs = append(lockupTxs, swap.LockupTransactionId)
}
}
for _, reverseSwap := range reverseSwaps {
if err := nursery.payReverseSwap(reverseSwap); err != nil {
Expand All @@ -192,27 +184,6 @@ func (nursery *Nursery) recoverSwaps() error {
}
for _, chainSwap := range chainSwaps {
swapIds = append(swapIds, chainSwap.Id)
if chainSwap.Pair.From == boltz.CurrencyLiquid {
lockupTxs = append(lockupTxs, chainSwap.FromData.LockupTransactionId)
}
}

for _, lockupTx := range lockupTxs {
if lockupTx != "" {
tx, err := nursery.onchain.GetTransaction(boltz.CurrencyLiquid, lockupTx, nil)
if err != nil {
return fmt.Errorf("could not get lockup transaction: %w", err)
}
for _, input := range tx.(*boltz.LiquidTransaction).Inputs {
spentTxs = append(spentTxs, chainhash.Hash(input.Hash).String())
}
}
}

for _, anyWallet := range nursery.onchain.Wallets {
if ownWallet, ok := anyWallet.(*wallet.Wallet); ok {
ownWallet.SetSpentOutputs(spentTxs)
}
}

return nursery.registerSwaps(swapIds)
Expand Down Expand Up @@ -292,7 +263,7 @@ func (nursery *Nursery) createTransaction(currency boltz.Currency, outputs []*Ou
return id, err
}

feeSatPerVbyte, err := nursery.onchain.EstimateFee(currency, true)
feeSatPerVbyte, err := nursery.onchain.EstimateFee(currency)
if err != nil {
return handleErr(fmt.Errorf("could not get fee estimation: %w", err))
}
Expand Down Expand Up @@ -372,11 +343,11 @@ func (nursery *Nursery) populateOutputs(outputs []*Output) (valid []*Output, det

func (nursery *Nursery) CheckAmounts(swapType boltz.SwapType, pair boltz.Pair, sendAmount uint64, receiveAmount uint64, serviceFee boltz.Percentage) (err error) {
fees := make(boltz.FeeEstimations)
fees[boltz.CurrencyLiquid], err = nursery.onchain.EstimateFee(boltz.CurrencyLiquid, true)
fees[boltz.CurrencyLiquid], err = nursery.onchain.EstimateFee(boltz.CurrencyLiquid)
if err != nil {
return err
}
fees[boltz.CurrencyBtc], err = nursery.onchain.EstimateFee(boltz.CurrencyBtc, true)
fees[boltz.CurrencyBtc], err = nursery.onchain.EstimateFee(boltz.CurrencyBtc)
if err != nil {
return err
}
Expand Down
7 changes: 1 addition & 6 deletions internal/onchain/onchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,12 +195,7 @@ func (onchain *Onchain) GetWallets(checker WalletChecker) []Wallet {
return wallets
}

func (onchain *Onchain) EstimateFee(currency boltz.Currency, allowLowball bool) (float64, error) {
if currency == boltz.CurrencyLiquid && onchain.Network == boltz.MainNet && allowLowball {
if boltzProvider, ok := onchain.Liquid.Tx.(*BoltzTxProvider); ok {
return boltzProvider.GetFeeEstimation(boltz.CurrencyLiquid)
}
}
func (onchain *Onchain) EstimateFee(currency boltz.Currency) (float64, error) {
chain, err := onchain.GetCurrency(currency)
if err != nil {
return 0, err
Expand Down
33 changes: 0 additions & 33 deletions internal/onchain/onchain_test.go

This file was deleted.

100 changes: 19 additions & 81 deletions internal/onchain/wallet/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import (
"github.com/BoltzExchange/boltz-client/v2/pkg/boltz"
)

const MinFeeRate = 0.01
const MaxInputs = uint64(255) // TODO: change back to 256 when gdk is fixed
const DefaultAutoConsolidateThreshold = uint64(200)
const GapLimit = 100
Expand Down Expand Up @@ -112,14 +111,11 @@ type Subaccount struct {

type Wallet struct {
onchain.WalletInfo
subaccount *uint64
session Session
connected bool
syncedAccounts []uint64
txProvider onchain.TxProvider
spentOutputs map[string]bool
spentOutputsLock sync.RWMutex
txNotifier <-chan TransactionNotification
subaccount *uint64
session Session
connected bool
syncedAccounts []uint64
txNotifier <-chan TransactionNotification
}

type Config struct {
Expand Down Expand Up @@ -342,9 +338,7 @@ func (wallet *Wallet) Connect() error {
}

params := map[string]any{
// gdk uses sat/kVB
"min_fee_rate": MinFeeRate * 1000,
"gap_limit": GapLimit,
"gap_limit": GapLimit,
}
var electrum onchain.ElectrumOptions
if wallet.Currency == boltz.CurrencyBtc {
Expand Down Expand Up @@ -494,7 +488,7 @@ func Login(credentials *Credentials) (*Wallet, error) {
if credentials.Encrypted() {
return nil, errors.New("credentials are encrypted")
}
wallet := &Wallet{WalletInfo: credentials.WalletInfo, spentOutputs: make(map[string]bool)}
wallet := &Wallet{WalletInfo: credentials.WalletInfo}
login := make(map[string]any)

if credentials.Mnemonic != "" {
Expand Down Expand Up @@ -568,10 +562,6 @@ func GenerateMnemonic() (string, error) {
return C.GoString(mnemonic), nil
}

func (wallet *Wallet) SetTxProvider(txProvider onchain.TxProvider) {
wallet.txProvider = txProvider
}

func (wallet *Wallet) Disconnect() error {
if !wallet.connected {
return nil
Expand Down Expand Up @@ -684,25 +674,6 @@ func (wallet *Wallet) getUnspentOutputs(subaccount uint64, includeUnconfirmed bo
if err := withAuthHandler(C.GA_get_unspent_outputs(wallet.session, params, handler), handler, result); err != nil {
return nil, err
}
wallet.spentOutputsLock.Lock()
defer wallet.spentOutputsLock.Unlock()
for spent := range wallet.spentOutputs {
found := false
for key, outputs := range result.Unspent {
for i, output := range outputs {
if output["txhash"] == spent {
logger.Debugf("Ignoring output for tx %s since it is marked as spent", spent)
result.Unspent[key] = append(outputs[:i], outputs[i+1:]...)
found = true
break
}
}
}
if !found {
delete(wallet.spentOutputs, spent)
}
}

return result, nil
}

Expand Down Expand Up @@ -793,8 +764,6 @@ func (wallet *Wallet) SendToAddress(address string, amount uint64, satPerVbyte f
return "", err
}

wallet.spentOutputsLock.Lock()
defer wallet.spentOutputsLock.Unlock()
handler := new(AuthHandler)
params, free := toJson(result)
if err := withAuthHandler(C.GA_blind_transaction(wallet.session, params, handler), handler, &result); err != nil {
Expand All @@ -808,56 +777,25 @@ func (wallet *Wallet) SendToAddress(address string, amount uint64, satPerVbyte f
}
free()

var signedTx struct {
Transaction string `mapstructure:"transaction"`
Error string `mapstructure:"error"`
TransactionInputs []struct {
TxId string `mapstructure:"txhash"`
} `mapstructure:"transaction_inputs"`
}
if err := mapstructure.Decode(result, &signedTx); err != nil {
return "", err
}
if signedTx.Error != "" {
return "", fmt.Errorf("could not sign: %s", signedTx.Error)
if errMsg, ok := result["error"].(string); ok && errMsg != "" {
return "", fmt.Errorf("could not sign: %s", errMsg)
}

if wallet.txProvider != nil {
tx, err = wallet.txProvider.BroadcastTransaction(signedTx.Transaction)
} else {
params, free = toJson(result)
var sendTx struct {
TxHash string `json:"txhash"`
Error string `json:"error"`
}
if err := withAuthHandler(C.GA_send_transaction(wallet.session, params, handler), handler, &sendTx); err != nil {
return "", err
}
free()

if sendTx.Error != "" {
err = errors.New(sendTx.Error)
}
tx = sendTx.TxHash
params, free = toJson(result)
var sendTx struct {
TxHash string `json:"txhash"`
Error string `json:"error"`
}
if err != nil {
return "", fmt.Errorf("failed to broadcast: %w", err)
if err := withAuthHandler(C.GA_send_transaction(wallet.session, params, handler), handler, &sendTx); err != nil {
return "", err
}
free()

for _, input := range signedTx.TransactionInputs {
wallet.spentOutputs[input.TxId] = true
if sendTx.Error != "" {
return "", fmt.Errorf("failed to broadcast: %s", sendTx.Error)
}

return tx, nil
}

func (wallet *Wallet) SetSpentOutputs(outputs []string) {
wallet.spentOutputsLock.Lock()
defer wallet.spentOutputsLock.Unlock()
wallet.spentOutputs = make(map[string]bool)
for _, output := range outputs {
wallet.spentOutputs[output] = true
}
return sendTx.TxHash, nil
}

func (wallet *Wallet) GetTransactions(limit, offset uint64) ([]*onchain.WalletTransaction, error) {
Expand Down
Loading
Loading