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: initial chainswaps #133

Merged
merged 25 commits into from
Apr 27, 2024
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
f41c3f9
feat: initial chainswaps
jackstar12 Apr 4, 2024
0af9edf
chore: cleanup
jackstar12 Apr 4, 2024
f29a1c1
refactor: unify fee and transaction logic
jackstar12 Apr 9, 2024
afc22af
refactor: use IN when querying refundable swaps
jackstar12 Apr 9, 2024
10c2a3b
refactor: use getters and setters for refund and claim pubkey in swap…
jackstar12 Apr 9, 2024
47e1349
chore: api naming
jackstar12 Apr 9, 2024
955544c
chore: cleanup
jackstar12 Apr 9, 2024
e006772
feat: improve wallet logic when creating chain swap
jackstar12 Apr 11, 2024
ef8e981
feat: manual chain swap refunds
jackstar12 Apr 11, 2024
5db0ba8
feat: include chainswaps in `ListSwaps` rpc
jackstar12 Apr 11, 2024
735525b
chore: consistent naming
jackstar12 Apr 15, 2024
f45bb00
Update nursery/refund.go
jackstar12 Apr 15, 2024
3810f12
chore: improve proto definitions
jackstar12 Apr 15, 2024
09eadee
refactor: dont set externalPay implicitly
jackstar12 Apr 15, 2024
3b42e23
chore: cleanup
jackstar12 Apr 15, 2024
940ad74
refactor: use wallet ids in create request
jackstar12 Apr 16, 2024
e89f816
feat: only query coop refundable swaps in specific states
jackstar12 Apr 16, 2024
0bb5565
fix: check if swap already has been paid in nursery
jackstar12 Apr 16, 2024
cb272cc
chore: improve error messages
jackstar12 Apr 26, 2024
eaa78bc
feat: chain swaps cli (#136)
jackstar12 Apr 26, 2024
156be3b
docs: improve grpc comments
jackstar12 Apr 26, 2024
d9ea9be
fix: transaction reconstruction logic
jackstar12 Apr 26, 2024
8dd8c00
ci: temporarily use chainswaps branch of regtest
jackstar12 Apr 26, 2024
1428396
text: wait with mining blocks
jackstar12 Apr 27, 2024
6af1356
test: remove flaky batch test for now
jackstar12 Apr 27, 2024
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
176 changes: 165 additions & 11 deletions boltz/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@ type SwapType string
const (
NormalSwap SwapType = "submarine"
ReverseSwap SwapType = "reverse"
ChainSwap SwapType = "chain"
)

var ErrPartialSignaturesDisabled = errors.New("partial signatures are disabled")

func ParseSwapType(swapType string) (SwapType, error) {
switch strings.ToLower(swapType) {
case string(NormalSwap), "normal":
Expand Down Expand Up @@ -91,6 +94,28 @@ type ReversePair struct {

type ReversePairs map[Currency]map[Currency]ReversePair

type ChainPair struct {
Hash string `json:"hash"`
Rate float64 `json:"rate"`
Limits struct {
Minimal uint64 `json:"minimal"`
Maximal uint64 `json:"maximal"`
MaximalZeroConfAmount uint64 `json:"maximalZeroConfAmount"`
} `json:"limits"`
Fees struct {
Percentage float64 `json:"percentage"`
MinerFees struct {
Server uint64 `json:"server"`
User struct {
Claim uint64 `json:"claim"`
Lockup uint64 `json:"lockup"`
} `json:"user"`
} `json:"minerFees"`
} `json:"fees"`
}

type ChainPairs map[Currency]map[Currency]ChainPair

type symbolMinerFees struct {
Normal uint64 `json:"normal"`
Reverse struct {
Expand Down Expand Up @@ -147,6 +172,20 @@ type GetSwapTransactionResponse struct {
Error string `json:"error"`
}

type ChainSwapTransaction struct {
Transaction struct {
Id string `json:"id"`
Hex string `json:"hex"`
} `json:"transaction"`
}

type GetChainSwapTransactionsResponse struct {
UserLock *ChainSwapTransaction `json:"userLock"`
ServerLock *ChainSwapTransaction `json:"serverLock"`

Error string `json:"error"`
}

type GetTransactionRequest struct {
Currency string `json:"currency"`
TransactionId string `json:"transactionId"`
Expand Down Expand Up @@ -197,8 +236,7 @@ type CreateSwapResponse struct {
Error string `json:"error"`
}

type RefundSwapRequest struct {
Id string `json:"id"`
type RefundRequest struct {
PubNonce HexString `json:"pubNonce"`
Transaction string `json:"transaction"`
Index int `json:"index"`
Expand All @@ -213,6 +251,22 @@ type SwapClaimDetails struct {
Error string `json:"error"`
}

type ChainSwapSigningDetails struct {
PubNonce HexString `json:"pubNonce"`
TransactionHash HexString `json:"transactionHash"`
PublicKey HexString `json:"publicKey"`

Error string `json:"error"`
}

type ChainSwapSigningRequest struct {
Preimage HexString `json:"preimage"`
Signature *PartialSignature `json:"signature"`
ToSign *ClaimRequest `json:"toSign"`

Error string `json:"error"`
}

type GetInvoiceAmountResponse struct {
InvoiceAmount uint64 `json:"invoiceAmount"`
Error string `json:"error"`
Expand Down Expand Up @@ -251,14 +305,43 @@ type CreateReverseSwapResponse struct {

Error string `json:"error"`
}
type ClaimReverseSwapRequest struct {
Id string `json:"id"`
type ClaimRequest struct {
Preimage HexString `json:"preimage"`
PubNonce HexString `json:"pubNonce"`
Transaction string `json:"transaction"`
Index int `json:"index"`
}

type ChainRequest struct {
From Currency `json:"from"`
To Currency `json:"to"`
PreimageHash HexString `json:"preimageHash"`
ClaimPublicKey HexString `json:"claimPublicKey,omitempty"`
RefundPublicKey HexString `json:"refundPublicKey,omitempty"`
UserLockAmount uint64 `json:"userLockAmount,omitempty"`
ServerLockAmount uint64 `json:"serverLockAmount,omitempty"`
PairHash string `json:"pairHash,omitempty"`
ReferralId string `json:"referralId,omitempty"`
}

type ChainResponse struct {
Id string `json:"id"`
ClaimDetails *ChainSwapData `json:"claimDetails,omitempty"`
LockupDetails *ChainSwapData `json:"lockupDetails,omitempty"`

Error string `json:"error"`
}

type ChainSwapData struct {
SwapTree *SerializedTree `json:"swapTree,omitempty"`
LockupAddress string `json:"lockupAddress"`
ServerPublicKey HexString `json:"serverPublicKey,omitempty"`
TimeoutBlockHeight uint32 `json:"timeoutBlockHeight"`
Amount uint64 `json:"amount"`
BlindingKey HexString `json:"blindingKey,omitempty"`
Bip21 string `json:"bip21,omitempty"`
}

type PartialSignature struct {
PubNonce HexString `json:"pubNonce"`
PartialSignature HexString `json:"partialSignature"`
Expand Down Expand Up @@ -303,6 +386,12 @@ func (boltz *Boltz) GetReversePairs() (response ReversePairs, err error) {
return response, err
}

func (boltz *Boltz) GetChainPairs() (response ChainPairs, err error) {
err = boltz.sendGetRequest("/v2/swap/chain", &response)

return response, err
}

func (boltz *Boltz) GetNodes() (Nodes, error) {
var response Nodes
err := boltz.sendGetRequest("/v2/nodes", &response)
Expand Down Expand Up @@ -334,6 +423,18 @@ func (boltz *Boltz) GetSwapTransaction(id string) (*GetSwapTransactionResponse,
return &response, err
}

func (boltz *Boltz) GetChainSwapTransactions(id string) (*GetChainSwapTransactionsResponse, error) {
var response GetChainSwapTransactionsResponse
path := fmt.Sprintf("/v2/swap/chain/%s/transactions", id)
err := boltz.sendGetRequest(path, &response)

if response.Error != "" {
return nil, Error(errors.New(response.Error))
}

return &response, err
}

func (boltz *Boltz) GetTransaction(transactionId string, currency Currency) (string, error) {
var response GetTransactionResponse
path := fmt.Sprintf("/v2/chain/%s/transaction/%s", currency, transactionId)
Expand Down Expand Up @@ -379,12 +480,12 @@ func (boltz *Boltz) CreateSwap(request CreateSwapRequest) (*CreateSwapResponse,
return &response, err
}

func (boltz *Boltz) RefundSwap(request RefundSwapRequest) (*PartialSignature, error) {
func (boltz *Boltz) RefundSwap(swapId string, request *RefundRequest) (*PartialSignature, error) {
if boltz.DisablePartialSignatures {
return nil, errors.New("partial signatures are disabled")
return nil, ErrPartialSignaturesDisabled
}
var response PartialSignature
err := boltz.sendPostRequest("/v2/swap/submarine/refund", request, &response)
err := boltz.sendPostRequest(fmt.Sprintf("/v2/swap/submarine/%s/refund", swapId), request, &response)

if response.Error != "" {
return nil, Error(errors.New(response.Error))
Expand All @@ -406,7 +507,7 @@ func (boltz *Boltz) GetInvoiceAmount(swapId string) (*GetInvoiceAmountResponse,

func (boltz *Boltz) GetSwapClaimDetails(swapId string) (*SwapClaimDetails, error) {
if boltz.DisablePartialSignatures {
return nil, errors.New("partial signatures are disabled")
return nil, ErrPartialSignaturesDisabled
}
var response SwapClaimDetails
err := boltz.sendGetRequest(fmt.Sprintf("/v2/swap/submarine/%s/claim", swapId), &response)
Expand Down Expand Up @@ -451,12 +552,65 @@ func (boltz *Boltz) CreateReverseSwap(request CreateReverseSwapRequest) (*Create
return &response, err
}

func (boltz *Boltz) ClaimReverseSwap(request ClaimReverseSwapRequest) (*PartialSignature, error) {
func (boltz *Boltz) ClaimReverseSwap(swapId string, request *ClaimRequest) (*PartialSignature, error) {
if boltz.DisablePartialSignatures {
return nil, ErrPartialSignaturesDisabled
}
var response PartialSignature
err := boltz.sendPostRequest(fmt.Sprintf("/v2/swap/reverse/%s/claim", swapId), request, &response)

if response.Error != "" {
return nil, Error(errors.New(response.Error))
}

return &response, err
}

func (boltz *Boltz) CreateChainSwap(request ChainRequest) (*ChainResponse, error) {
var response ChainResponse
err := boltz.sendPostRequest("/v2/swap/chain", request, &response)

if response.Error != "" {
return nil, Error(errors.New(response.Error))
}

return &response, err
}

func (boltz *Boltz) GetChainSwapClaimDetails(swapId string) (*ChainSwapSigningDetails, error) {
if boltz.DisablePartialSignatures {
return nil, ErrPartialSignaturesDisabled
}
var response ChainSwapSigningDetails
err := boltz.sendGetRequest(fmt.Sprintf("/v2/swap/chain/%s/claim", swapId), &response)

if response.Error != "" {
return nil, Error(errors.New(response.Error))
}

return &response, err
}

func (boltz *Boltz) ExchangeChainSwapClaimSignature(swapId string, request *ChainSwapSigningRequest) (*PartialSignature, error) {
if boltz.DisablePartialSignatures {
return nil, ErrPartialSignaturesDisabled
}
var response PartialSignature
err := boltz.sendPostRequest(fmt.Sprintf("/v2/swap/chain/%s/claim", swapId), request, &response)

if response.Error != "" {
return nil, Error(errors.New(response.Error))
}

return &response, err
}

func (boltz *Boltz) RefundChainSwap(swapId string, request *RefundRequest) (*PartialSignature, error) {
if boltz.DisablePartialSignatures {
return nil, errors.New("partial signatures are disabled")
return nil, ErrPartialSignaturesDisabled
}
var response PartialSignature
err := boltz.sendPostRequest("/v2/swap/reverse/claim", request, &response)
err := boltz.sendPostRequest(fmt.Sprintf("/v2/swap/chain/%s/refund", swapId), request, &response)

if response.Error != "" {
return nil, Error(errors.New(response.Error))
Expand Down
13 changes: 3 additions & 10 deletions boltz/btc.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ func btcTaprootHash(transaction Transaction, outputs []OutputDetails, index int)
)
}

func constructBtcTransaction(network *Network, outputs []OutputDetails, fee uint64) (Transaction, error) {
func constructBtcTransaction(network *Network, outputs []OutputDetails) (Transaction, error) {
transaction := wire.NewMsgTx(wire.TxVersion)

outValues := make(map[string]int64)
Expand All @@ -120,17 +120,13 @@ func constructBtcTransaction(network *Network, outputs []OutputDetails, fee uint

transaction.AddTxIn(input)

value := lockupTx.MsgTx().TxOut[output.Vout].Value
value := lockupTx.MsgTx().TxOut[output.Vout].Value - int64(output.Fee)
//nolint:gosimple
existingValue, _ := outValues[output.Address]
outValues[output.Address] = existingValue + value

}

outLen := uint64(len(outValues))
feePerOutput := fee / outLen
feeRemainder := fee % outLen

for rawAddress, value := range outValues {
outputAddress, err := btcutil.DecodeAddress(rawAddress, network.Btc)
if err != nil {
Expand All @@ -143,12 +139,9 @@ func constructBtcTransaction(network *Network, outputs []OutputDetails, fee uint
return nil, err
}

// give the remainder to the first output
fee := feePerOutput + feeRemainder
feeRemainder = 0
transaction.AddTxOut(&wire.TxOut{
PkScript: outputScript,
Value: value - int64(fee),
Value: value,
})
}

Expand Down
19 changes: 12 additions & 7 deletions boltz/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ const (
TransactionConfirmed
TransactionLockupFailed
TransactionClaimPending

TransactionServerMempoool
TransactionServerConfirmed
)

var swapUpdateEventStrings = map[string]SwapUpdateEvent{
Expand All @@ -35,13 +38,15 @@ var swapUpdateEventStrings = map[string]SwapUpdateEvent{

"channel.created": ChannelCreated,

"transaction.failed": TransactionFailed,
"transaction.mempool": TransactionMempool,
"transaction.claimed": TransactionClaimed,
"transaction.refunded": TransactionRefunded,
"transaction.confirmed": TransactionConfirmed,
"transaction.lockupFailed": TransactionLockupFailed,
"transaction.claim.pending": TransactionClaimPending,
"transaction.failed": TransactionFailed,
"transaction.mempool": TransactionMempool,
"transaction.claimed": TransactionClaimed,
"transaction.refunded": TransactionRefunded,
"transaction.confirmed": TransactionConfirmed,
"transaction.lockupFailed": TransactionLockupFailed,
"transaction.claim.pending": TransactionClaimPending,
"transaction.server.mempool": TransactionServerMempoool,
"transaction.server.confirmed": TransactionServerConfirmed,
}

var CompletedStatus = []string{
Expand Down
Loading
Loading