mirror of
https://github.com/lightninglabs/loop.git
synced 2026-08-13 12:33:03 +02:00
instantout: enforce the accepted swap fee
Carry the accepted quote into each request, persist it, and reject invoices above that limit. Preserve compatibility for requests that omit the cap while distinguishing an explicit zero.
This commit is contained in:
parent
b596eabab3
commit
e772f8ccfa
14 changed files with 260 additions and 12 deletions
|
|
@ -4467,7 +4467,11 @@ type InstantOutRequest struct {
|
|||
OutgoingChanSet []uint64 `protobuf:"varint,2,rep,packed,name=outgoing_chan_set,json=outgoingChanSet,proto3" json:"outgoing_chan_set,omitempty"`
|
||||
// An optional address to sweep the onchain funds to. If not set, the funds
|
||||
// will be swept to the wallet's internal address.
|
||||
DestAddr string `protobuf:"bytes,3,opt,name=dest_addr,json=destAddr,proto3" json:"dest_addr,omitempty"`
|
||||
DestAddr string `protobuf:"bytes,3,opt,name=dest_addr,json=destAddr,proto3" json:"dest_addr,omitempty"`
|
||||
// Types that are valid to be assigned to MaxSwapFee:
|
||||
//
|
||||
// *InstantOutRequest_MaxSwapFeeSat
|
||||
MaxSwapFee isInstantOutRequest_MaxSwapFee `protobuf_oneof:"max_swap_fee"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
|
@ -4523,6 +4527,36 @@ func (x *InstantOutRequest) GetDestAddr() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func (x *InstantOutRequest) GetMaxSwapFee() isInstantOutRequest_MaxSwapFee {
|
||||
if x != nil {
|
||||
return x.MaxSwapFee
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *InstantOutRequest) GetMaxSwapFeeSat() int64 {
|
||||
if x != nil {
|
||||
if x, ok := x.MaxSwapFee.(*InstantOutRequest_MaxSwapFeeSat); ok {
|
||||
return x.MaxSwapFeeSat
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type isInstantOutRequest_MaxSwapFee interface {
|
||||
isInstantOutRequest_MaxSwapFee()
|
||||
}
|
||||
|
||||
type InstantOutRequest_MaxSwapFeeSat struct {
|
||||
// The maximum off-chain swap fee that may be charged for the swap. If
|
||||
// this field is omitted, no fee cap is applied for compatibility with
|
||||
// clients that predate this field. An explicitly set value of zero
|
||||
// rejects any positive swap fee.
|
||||
MaxSwapFeeSat int64 `protobuf:"varint,4,opt,name=max_swap_fee_sat,json=maxSwapFeeSat,proto3,oneof"`
|
||||
}
|
||||
|
||||
func (*InstantOutRequest_MaxSwapFeeSat) isInstantOutRequest_MaxSwapFee() {}
|
||||
|
||||
type InstantOutResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// The hash of the swap preimage.
|
||||
|
|
@ -6964,11 +6998,13 @@ const file_client_proto_rawDesc = "" +
|
|||
"\x06amount\x18\x03 \x01(\x04R\x06amount\x12\x13\n" +
|
||||
"\x05tx_id\x18\x04 \x01(\tR\x04txId\x12\x12\n" +
|
||||
"\x04vout\x18\x05 \x01(\rR\x04vout\x12\x16\n" +
|
||||
"\x06expiry\x18\x06 \x01(\rR\x06expiry\"\x85\x01\n" +
|
||||
"\x06expiry\x18\x06 \x01(\rR\x06expiry\"\xc0\x01\n" +
|
||||
"\x11InstantOutRequest\x12'\n" +
|
||||
"\x0freservation_ids\x18\x01 \x03(\fR\x0ereservationIds\x12*\n" +
|
||||
"\x11outgoing_chan_set\x18\x02 \x03(\x04R\x0foutgoingChanSet\x12\x1b\n" +
|
||||
"\tdest_addr\x18\x03 \x01(\tR\bdestAddr\"t\n" +
|
||||
"\tdest_addr\x18\x03 \x01(\tR\bdestAddr\x12)\n" +
|
||||
"\x10max_swap_fee_sat\x18\x04 \x01(\x03H\x00R\rmaxSwapFeeSatB\x0e\n" +
|
||||
"\fmax_swap_fee\"t\n" +
|
||||
"\x12InstantOutResponse\x12(\n" +
|
||||
"\x10instant_out_hash\x18\x01 \x01(\fR\x0einstantOutHash\x12\x1e\n" +
|
||||
"\vsweep_tx_id\x18\x02 \x01(\tR\tsweepTxId\x12\x14\n" +
|
||||
|
|
@ -7490,6 +7526,9 @@ func file_client_proto_init() {
|
|||
(*SweepHtlcResponse_Published)(nil),
|
||||
(*SweepHtlcResponse_Failed)(nil),
|
||||
}
|
||||
file_client_proto_msgTypes[48].OneofWrappers = []any{
|
||||
(*InstantOutRequest_MaxSwapFeeSat)(nil),
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
|
|
|
|||
|
|
@ -1685,6 +1685,16 @@ message InstantOutRequest {
|
|||
will be swept to the wallet's internal address.
|
||||
*/
|
||||
string dest_addr = 3;
|
||||
|
||||
oneof max_swap_fee {
|
||||
/*
|
||||
The maximum off-chain swap fee that may be charged for the swap. If
|
||||
this field is omitted, no fee cap is applied for compatibility with
|
||||
clients that predate this field. An explicitly set value of zero
|
||||
rejects any positive swap fee.
|
||||
*/
|
||||
int64 max_swap_fee_sat = 4;
|
||||
}
|
||||
}
|
||||
|
||||
message InstantOutResponse {
|
||||
|
|
|
|||
|
|
@ -1917,6 +1917,11 @@
|
|||
"dest_addr": {
|
||||
"type": "string",
|
||||
"description": "An optional address to sweep the onchain funds to. If not set, the funds\nwill be swept to the wallet's internal address."
|
||||
},
|
||||
"max_swap_fee_sat": {
|
||||
"type": "string",
|
||||
"format": "int64",
|
||||
"description": "The maximum off-chain swap fee that may be charged for the swap. If\nthis field is omitted, no fee cap is applied for compatibility with\nclients that predate this field. An explicitly set value of zero\nrejects any positive swap fee."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
32
looprpc/client_test.go
Normal file
32
looprpc/client_test.go
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
package looprpc
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// TestInstantOutMaxSwapFeePresence verifies that an omitted fee cap remains
|
||||
// distinguishable from an explicitly encoded zero while retaining the scalar
|
||||
// field's original wire representation.
|
||||
func TestInstantOutMaxSwapFeePresence(t *testing.T) {
|
||||
request := &InstantOutRequest{}
|
||||
if err := proto.Unmarshal(nil, request); err != nil {
|
||||
t.Fatalf("unable to unmarshal omitted cap: %v", err)
|
||||
}
|
||||
if request.GetMaxSwapFee() != nil {
|
||||
t.Fatal("omitted cap unexpectedly has presence")
|
||||
}
|
||||
|
||||
// Field four, encoded as a varint with value zero. This is the same wire
|
||||
// representation used before the field gained presence semantics.
|
||||
if err := proto.Unmarshal([]byte{0x20, 0x00}, request); err != nil {
|
||||
t.Fatalf("unable to unmarshal explicit zero cap: %v", err)
|
||||
}
|
||||
if request.GetMaxSwapFee() == nil {
|
||||
t.Fatal("explicit zero cap lost presence")
|
||||
}
|
||||
if request.GetMaxSwapFeeSat() != 0 {
|
||||
t.Fatalf("expected zero cap, got %d", request.GetMaxSwapFeeSat())
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue