diff --git a/app/src/types/generated/lnd_pb.d.ts b/app/src/types/generated/lnd_pb.d.ts index 4bdbde587..347abb79c 100644 --- a/app/src/types/generated/lnd_pb.d.ts +++ b/app/src/types/generated/lnd_pb.d.ts @@ -1773,6 +1773,11 @@ export class ChannelCloseSummary extends jspb.Message { getZeroConfConfirmedScid(): string; setZeroConfConfirmedScid(value: string): void; + getCustomChannelData(): Uint8Array | string; + getCustomChannelData_asU8(): Uint8Array; + getCustomChannelData_asB64(): string; + setCustomChannelData(value: Uint8Array | string): void; + serializeBinary(): Uint8Array; toObject(includeInstance?: boolean): ChannelCloseSummary.AsObject; static toObject(includeInstance: boolean, msg: ChannelCloseSummary): ChannelCloseSummary.AsObject; @@ -1800,6 +1805,7 @@ export namespace ChannelCloseSummary { resolutionsList: Array, aliasScidsList: Array, zeroConfConfirmedScid: string, + customChannelData: Uint8Array | string, } export interface ClosureTypeMap { @@ -7376,6 +7382,8 @@ export class RPCMiddlewareRequest extends jspb.Message { getMsgId(): string; setMsgId(value: string): void; + getMetadataPairsMap(): jspb.Map; + clearMetadataPairsMap(): void; getInterceptTypeCase(): RPCMiddlewareRequest.InterceptTypeCase; serializeBinary(): Uint8Array; toObject(includeInstance?: boolean): RPCMiddlewareRequest.AsObject; @@ -7397,6 +7405,7 @@ export namespace RPCMiddlewareRequest { response?: RPCMessage.AsObject, regComplete: boolean, msgId: string, + metadataPairsMap: Array<[string, MetadataValues.AsObject]>, } export enum InterceptTypeCase { @@ -7408,6 +7417,28 @@ export namespace RPCMiddlewareRequest { } } +export class MetadataValues extends jspb.Message { + clearValuesList(): void; + getValuesList(): Array; + setValuesList(value: Array): void; + addValues(value: string, index?: number): string; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): MetadataValues.AsObject; + static toObject(includeInstance: boolean, msg: MetadataValues): MetadataValues.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: MetadataValues, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): MetadataValues; + static deserializeBinaryFromReader(message: MetadataValues, reader: jspb.BinaryReader): MetadataValues; +} + +export namespace MetadataValues { + export type AsObject = { + valuesList: Array, + } +} + export class StreamAuth extends jspb.Message { getMethodFullUri(): string; setMethodFullUri(value: string): void; diff --git a/app/src/types/generated/lnd_pb.js b/app/src/types/generated/lnd_pb.js index 858bfa42b..5202df5b9 100644 --- a/app/src/types/generated/lnd_pb.js +++ b/app/src/types/generated/lnd_pb.js @@ -171,6 +171,7 @@ goog.exportSymbol('proto.lnrpc.MPPRecord', null, global); goog.exportSymbol('proto.lnrpc.MacaroonId', null, global); goog.exportSymbol('proto.lnrpc.MacaroonPermission', null, global); goog.exportSymbol('proto.lnrpc.MacaroonPermissionList', null, global); +goog.exportSymbol('proto.lnrpc.MetadataValues', null, global); goog.exportSymbol('proto.lnrpc.MiddlewareRegistration', null, global); goog.exportSymbol('proto.lnrpc.MultiChanBackup', null, global); goog.exportSymbol('proto.lnrpc.NetworkInfo', null, global); @@ -4505,6 +4506,27 @@ if (goog.DEBUG && !COMPILED) { */ proto.lnrpc.RPCMiddlewareRequest.displayName = 'proto.lnrpc.RPCMiddlewareRequest'; } +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.lnrpc.MetadataValues = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, proto.lnrpc.MetadataValues.repeatedFields_, null); +}; +goog.inherits(proto.lnrpc.MetadataValues, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.lnrpc.MetadataValues.displayName = 'proto.lnrpc.MetadataValues'; +} /** * Generated by JsPbCodeGenerator. * @param {Array=} opt_data Optional initial data array, typically from a @@ -17005,7 +17027,8 @@ proto.lnrpc.ChannelCloseSummary.toObject = function(includeInstance, msg) { resolutionsList: jspb.Message.toObjectList(msg.getResolutionsList(), proto.lnrpc.Resolution.toObject, includeInstance), aliasScidsList: (f = jspb.Message.getRepeatedField(msg, 14)) == null ? undefined : f, - zeroConfConfirmedScid: jspb.Message.getFieldWithDefault(msg, 15, "0") + zeroConfConfirmedScid: jspb.Message.getFieldWithDefault(msg, 15, "0"), + customChannelData: msg.getCustomChannelData_asB64() }; if (includeInstance) { @@ -17105,6 +17128,10 @@ proto.lnrpc.ChannelCloseSummary.deserializeBinaryFromReader = function(msg, read var value = /** @type {string} */ (reader.readUint64String()); msg.setZeroConfConfirmedScid(value); break; + case 16: + var value = /** @type {!Uint8Array} */ (reader.readBytes()); + msg.setCustomChannelData(value); + break; default: reader.skipField(); break; @@ -17240,6 +17267,13 @@ proto.lnrpc.ChannelCloseSummary.serializeBinaryToWriter = function(message, writ f ); } + f = message.getCustomChannelData_asU8(); + if (f.length > 0) { + writer.writeBytes( + 16, + f + ); + } }; @@ -17564,6 +17598,48 @@ proto.lnrpc.ChannelCloseSummary.prototype.setZeroConfConfirmedScid = function(va }; +/** + * optional bytes custom_channel_data = 16; + * @return {!(string|Uint8Array)} + */ +proto.lnrpc.ChannelCloseSummary.prototype.getCustomChannelData = function() { + return /** @type {!(string|Uint8Array)} */ (jspb.Message.getFieldWithDefault(this, 16, "")); +}; + + +/** + * optional bytes custom_channel_data = 16; + * This is a type-conversion wrapper around `getCustomChannelData()` + * @return {string} + */ +proto.lnrpc.ChannelCloseSummary.prototype.getCustomChannelData_asB64 = function() { + return /** @type {string} */ (jspb.Message.bytesAsB64( + this.getCustomChannelData())); +}; + + +/** + * optional bytes custom_channel_data = 16; + * Note that Uint8Array is not supported on all browsers. + * @see http://caniuse.com/Uint8Array + * This is a type-conversion wrapper around `getCustomChannelData()` + * @return {!Uint8Array} + */ +proto.lnrpc.ChannelCloseSummary.prototype.getCustomChannelData_asU8 = function() { + return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8( + this.getCustomChannelData())); +}; + + +/** + * @param {!(string|Uint8Array)} value + * @return {!proto.lnrpc.ChannelCloseSummary} returns this + */ +proto.lnrpc.ChannelCloseSummary.prototype.setCustomChannelData = function(value) { + return jspb.Message.setProto3BytesField(this, 16, value); +}; + + @@ -57081,7 +57157,8 @@ proto.lnrpc.RPCMiddlewareRequest.toObject = function(includeInstance, msg) { request: (f = msg.getRequest()) && proto.lnrpc.RPCMessage.toObject(includeInstance, f), response: (f = msg.getResponse()) && proto.lnrpc.RPCMessage.toObject(includeInstance, f), regComplete: jspb.Message.getBooleanFieldWithDefault(msg, 8, false), - msgId: jspb.Message.getFieldWithDefault(msg, 7, "0") + msgId: jspb.Message.getFieldWithDefault(msg, 7, "0"), + metadataPairsMap: (f = msg.getMetadataPairsMap()) ? f.toObject(includeInstance, proto.lnrpc.MetadataValues.toObject) : [] }; if (includeInstance) { @@ -57153,6 +57230,12 @@ proto.lnrpc.RPCMiddlewareRequest.deserializeBinaryFromReader = function(msg, rea var value = /** @type {string} */ (reader.readUint64String()); msg.setMsgId(value); break; + case 9: + var value = msg.getMetadataPairsMap(); + reader.readMessage(value, function(message, reader) { + jspb.Map.deserializeBinary(message, reader, jspb.BinaryReader.prototype.readString, jspb.BinaryReader.prototype.readMessage, proto.lnrpc.MetadataValues.deserializeBinaryFromReader, "", new proto.lnrpc.MetadataValues()); + }); + break; default: reader.skipField(); break; @@ -57241,6 +57324,10 @@ proto.lnrpc.RPCMiddlewareRequest.serializeBinaryToWriter = function(message, wri f ); } + f = message.getMetadataPairsMap(true); + if (f && f.getLength() > 0) { + f.serializeBinary(9, writer, jspb.BinaryWriter.prototype.writeString, jspb.BinaryWriter.prototype.writeMessage, proto.lnrpc.MetadataValues.serializeBinaryToWriter); + } }; @@ -57487,6 +57574,185 @@ proto.lnrpc.RPCMiddlewareRequest.prototype.setMsgId = function(value) { }; +/** + * map metadata_pairs = 9; + * @param {boolean=} opt_noLazyCreate Do not create the map if + * empty, instead returning `undefined` + * @return {!jspb.Map} + */ +proto.lnrpc.RPCMiddlewareRequest.prototype.getMetadataPairsMap = function(opt_noLazyCreate) { + return /** @type {!jspb.Map} */ ( + jspb.Message.getMapField(this, 9, opt_noLazyCreate, + proto.lnrpc.MetadataValues)); +}; + + +/** + * Clears values from the map. The map will be non-null. + * @return {!proto.lnrpc.RPCMiddlewareRequest} returns this + */ +proto.lnrpc.RPCMiddlewareRequest.prototype.clearMetadataPairsMap = function() { + this.getMetadataPairsMap().clear(); + return this; +}; + + + +/** + * List of repeated fields within this message type. + * @private {!Array} + * @const + */ +proto.lnrpc.MetadataValues.repeatedFields_ = [1]; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.lnrpc.MetadataValues.prototype.toObject = function(opt_includeInstance) { + return proto.lnrpc.MetadataValues.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.lnrpc.MetadataValues} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.lnrpc.MetadataValues.toObject = function(includeInstance, msg) { + var f, obj = { + valuesList: (f = jspb.Message.getRepeatedField(msg, 1)) == null ? undefined : f + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.lnrpc.MetadataValues} + */ +proto.lnrpc.MetadataValues.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.lnrpc.MetadataValues; + return proto.lnrpc.MetadataValues.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.lnrpc.MetadataValues} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.lnrpc.MetadataValues} + */ +proto.lnrpc.MetadataValues.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {string} */ (reader.readString()); + msg.addValues(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.lnrpc.MetadataValues.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.lnrpc.MetadataValues.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.lnrpc.MetadataValues} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.lnrpc.MetadataValues.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getValuesList(); + if (f.length > 0) { + writer.writeRepeatedString( + 1, + f + ); + } +}; + + +/** + * repeated string values = 1; + * @return {!Array} + */ +proto.lnrpc.MetadataValues.prototype.getValuesList = function() { + return /** @type {!Array} */ (jspb.Message.getRepeatedField(this, 1)); +}; + + +/** + * @param {!Array} value + * @return {!proto.lnrpc.MetadataValues} returns this + */ +proto.lnrpc.MetadataValues.prototype.setValuesList = function(value) { + return jspb.Message.setField(this, 1, value || []); +}; + + +/** + * @param {string} value + * @param {number=} opt_index + * @return {!proto.lnrpc.MetadataValues} returns this + */ +proto.lnrpc.MetadataValues.prototype.addValues = function(value, opt_index) { + return jspb.Message.addToRepeatedField(this, 1, value, opt_index); +}; + + +/** + * Clears the list making it empty but non-null. + * @return {!proto.lnrpc.MetadataValues} returns this + */ +proto.lnrpc.MetadataValues.prototype.clearValuesList = function() { + return this.setValuesList([]); +}; + + diff --git a/app/src/types/generated/loop_pb.d.ts b/app/src/types/generated/loop_pb.d.ts index 903e1f70c..b18d8a6c0 100644 --- a/app/src/types/generated/loop_pb.d.ts +++ b/app/src/types/generated/loop_pb.d.ts @@ -68,6 +68,16 @@ export class LoopOutRequest extends jspb.Message { getPaymentTimeout(): number; setPaymentTimeout(value: number): void; + hasAssetInfo(): boolean; + clearAssetInfo(): void; + getAssetInfo(): AssetLoopOutRequest | undefined; + setAssetInfo(value?: AssetLoopOutRequest): void; + + hasAssetRfqInfo(): boolean; + clearAssetRfqInfo(): void; + getAssetRfqInfo(): AssetRfqInfo | undefined; + setAssetRfqInfo(value?: AssetRfqInfo): void; + serializeBinary(): Uint8Array; toObject(includeInstance?: boolean): LoopOutRequest.AsObject; static toObject(includeInstance: boolean, msg: LoopOutRequest): LoopOutRequest.AsObject; @@ -99,6 +109,8 @@ export namespace LoopOutRequest { isExternalAddr: boolean, reservationIdsList: Array, paymentTimeout: number, + assetInfo?: AssetLoopOutRequest.AsObject, + assetRfqInfo?: AssetRfqInfo.AsObject, } } @@ -278,6 +290,11 @@ export class SwapStatus extends jspb.Message { getLabel(): string; setLabel(value: string): void; + hasAssetInfo(): boolean; + clearAssetInfo(): void; + getAssetInfo(): AssetLoopOutInfo | undefined; + setAssetInfo(value?: AssetLoopOutInfo): void; + serializeBinary(): Uint8Array; toObject(includeInstance?: boolean): SwapStatus.AsObject; static toObject(includeInstance: boolean, msg: SwapStatus): SwapStatus.AsObject; @@ -307,6 +324,7 @@ export namespace SwapStatus { lastHop: Uint8Array | string, outgoingChanSetList: Array, label: string, + assetInfo?: AssetLoopOutInfo.AsObject, } } @@ -316,6 +334,9 @@ export class ListSwapsRequest extends jspb.Message { getListSwapFilter(): ListSwapsFilter | undefined; setListSwapFilter(value?: ListSwapsFilter): void; + getMaxSwaps(): string; + setMaxSwaps(value: string): void; + serializeBinary(): Uint8Array; toObject(includeInstance?: boolean): ListSwapsRequest.AsObject; static toObject(includeInstance: boolean, msg: ListSwapsRequest): ListSwapsRequest.AsObject; @@ -329,6 +350,7 @@ export class ListSwapsRequest extends jspb.Message { export namespace ListSwapsRequest { export type AsObject = { listSwapFilter?: ListSwapsFilter.AsObject, + maxSwaps: string, } } @@ -352,6 +374,12 @@ export class ListSwapsFilter extends jspb.Message { getLoopInLastHop_asB64(): string; setLoopInLastHop(value: Uint8Array | string): void; + getAssetSwapOnly(): boolean; + setAssetSwapOnly(value: boolean): void; + + getStartTimestampNs(): string; + setStartTimestampNs(value: string): void; + serializeBinary(): Uint8Array; toObject(includeInstance?: boolean): ListSwapsFilter.AsObject; static toObject(includeInstance: boolean, msg: ListSwapsFilter): ListSwapsFilter.AsObject; @@ -369,6 +397,8 @@ export namespace ListSwapsFilter { outgoingChanSetList: Array, label: string, loopInLastHop: Uint8Array | string, + assetSwapOnly: boolean, + startTimestampNs: string, } export interface SwapTypeFilterMap { @@ -386,6 +416,9 @@ export class ListSwapsResponse extends jspb.Message { setSwapsList(value: Array): void; addSwaps(value?: SwapStatus, index?: number): SwapStatus; + getNextStartTime(): string; + setNextStartTime(value: string): void; + serializeBinary(): Uint8Array; toObject(includeInstance?: boolean): ListSwapsResponse.AsObject; static toObject(includeInstance: boolean, msg: ListSwapsResponse): ListSwapsResponse.AsObject; @@ -399,6 +432,7 @@ export class ListSwapsResponse extends jspb.Message { export namespace ListSwapsResponse { export type AsObject = { swapsList: Array, + nextStartTime: string, } } @@ -527,6 +561,11 @@ export class QuoteRequest extends jspb.Message { setDepositOutpointsList(value: Array): void; addDepositOutpoints(value: string, index?: number): string; + hasAssetInfo(): boolean; + clearAssetInfo(): void; + getAssetInfo(): AssetLoopOutRequest | undefined; + setAssetInfo(value?: AssetLoopOutRequest): void; + serializeBinary(): Uint8Array; toObject(includeInstance?: boolean): QuoteRequest.AsObject; static toObject(includeInstance: boolean, msg: QuoteRequest): QuoteRequest.AsObject; @@ -547,6 +586,7 @@ export namespace QuoteRequest { loopInRouteHintsList: Array, pb_private: boolean, depositOutpointsList: Array, + assetInfo?: AssetLoopOutRequest.AsObject, } } @@ -603,6 +643,11 @@ export class OutQuoteResponse extends jspb.Message { getConfTarget(): number; setConfTarget(value: number): void; + hasAssetRfqInfo(): boolean; + clearAssetRfqInfo(): void; + getAssetRfqInfo(): AssetRfqInfo | undefined; + setAssetRfqInfo(value?: AssetRfqInfo): void; + serializeBinary(): Uint8Array; toObject(includeInstance?: boolean): OutQuoteResponse.AsObject; static toObject(includeInstance: boolean, msg: OutQuoteResponse): OutQuoteResponse.AsObject; @@ -621,6 +666,7 @@ export namespace OutQuoteResponse { swapPaymentDest: Uint8Array | string, cltvDelta: number, confTarget: number, + assetRfqInfo?: AssetRfqInfo.AsObject, } } @@ -881,6 +927,9 @@ export class GetInfoResponse extends jspb.Message { getLoopInStats(): LoopStats | undefined; setLoopInStats(value?: LoopStats): void; + getCommitHash(): string; + setCommitHash(value: string): void; + serializeBinary(): Uint8Array; toObject(includeInstance?: boolean): GetInfoResponse.AsObject; static toObject(includeInstance: boolean, msg: GetInfoResponse): GetInfoResponse.AsObject; @@ -901,6 +950,7 @@ export namespace GetInfoResponse { tlsCertPath: string, loopOutStats?: LoopStats.AsObject, loopInStats?: LoopStats.AsObject, + commitHash: string, } } @@ -995,6 +1045,8 @@ export class LiquidityParameters extends jspb.Message { getAccountAddrType(): AddressTypeMap[keyof AddressTypeMap]; setAccountAddrType(value: AddressTypeMap[keyof AddressTypeMap]): void; + getEasyAssetParamsMap(): jspb.Map; + clearEasyAssetParamsMap(): void; serializeBinary(): Uint8Array; toObject(includeInstance?: boolean): LiquidityParameters.AsObject; static toObject(includeInstance: boolean, msg: LiquidityParameters): LiquidityParameters.AsObject; @@ -1031,6 +1083,31 @@ export namespace LiquidityParameters { easyAutoloopLocalTargetSat: string, account: string, accountAddrType: AddressTypeMap[keyof AddressTypeMap], + easyAssetParamsMap: Array<[string, EasyAssetAutoloopParams.AsObject]>, + } +} + +export class EasyAssetAutoloopParams extends jspb.Message { + getEnabled(): boolean; + setEnabled(value: boolean): void; + + getLocalTargetAssetAmt(): string; + setLocalTargetAssetAmt(value: string): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): EasyAssetAutoloopParams.AsObject; + static toObject(includeInstance: boolean, msg: EasyAssetAutoloopParams): EasyAssetAutoloopParams.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: EasyAssetAutoloopParams, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): EasyAssetAutoloopParams; + static deserializeBinaryFromReader(message: EasyAssetAutoloopParams, reader: jspb.BinaryReader): EasyAssetAutoloopParams; +} + +export namespace EasyAssetAutoloopParams { + export type AsObject = { + enabled: boolean, + localTargetAssetAmt: string, } } @@ -1647,6 +1724,9 @@ export class WithdrawDepositsRequest extends jspb.Message { getSatPerVbyte(): string; setSatPerVbyte(value: string): void; + getAmount(): string; + setAmount(value: string): void; + serializeBinary(): Uint8Array; toObject(includeInstance?: boolean): WithdrawDepositsRequest.AsObject; static toObject(includeInstance: boolean, msg: WithdrawDepositsRequest): WithdrawDepositsRequest.AsObject; @@ -1663,6 +1743,7 @@ export namespace WithdrawDepositsRequest { all: boolean, destAddr: string, satPerVbyte: string, + amount: string, } } @@ -1670,8 +1751,8 @@ export class WithdrawDepositsResponse extends jspb.Message { getWithdrawalTxHash(): string; setWithdrawalTxHash(value: string): void; - getPkScript(): string; - setPkScript(value: string): void; + getAddress(): string; + setAddress(value: string): void; serializeBinary(): Uint8Array; toObject(includeInstance?: boolean): WithdrawDepositsResponse.AsObject; @@ -1686,7 +1767,7 @@ export class WithdrawDepositsResponse extends jspb.Message { export namespace WithdrawDepositsResponse { export type AsObject = { withdrawalTxHash: string, - pkScript: string, + address: string, } } @@ -2072,6 +2153,146 @@ export namespace StaticAddressLoopInResponse { } } +export class AssetLoopOutRequest extends jspb.Message { + getAssetId(): Uint8Array | string; + getAssetId_asU8(): Uint8Array; + getAssetId_asB64(): string; + setAssetId(value: Uint8Array | string): void; + + getAssetEdgeNode(): Uint8Array | string; + getAssetEdgeNode_asU8(): Uint8Array; + getAssetEdgeNode_asB64(): string; + setAssetEdgeNode(value: Uint8Array | string): void; + + getMaxLimitMultiplier(): number; + setMaxLimitMultiplier(value: number): void; + + getExpiry(): string; + setExpiry(value: string): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): AssetLoopOutRequest.AsObject; + static toObject(includeInstance: boolean, msg: AssetLoopOutRequest): AssetLoopOutRequest.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: AssetLoopOutRequest, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): AssetLoopOutRequest; + static deserializeBinaryFromReader(message: AssetLoopOutRequest, reader: jspb.BinaryReader): AssetLoopOutRequest; +} + +export namespace AssetLoopOutRequest { + export type AsObject = { + assetId: Uint8Array | string, + assetEdgeNode: Uint8Array | string, + maxLimitMultiplier: number, + expiry: string, + } +} + +export class AssetRfqInfo extends jspb.Message { + getPrepayRfqId(): Uint8Array | string; + getPrepayRfqId_asU8(): Uint8Array; + getPrepayRfqId_asB64(): string; + setPrepayRfqId(value: Uint8Array | string): void; + + getMaxPrepayAssetAmt(): string; + setMaxPrepayAssetAmt(value: string): void; + + hasPrepayAssetRate(): boolean; + clearPrepayAssetRate(): void; + getPrepayAssetRate(): FixedPoint | undefined; + setPrepayAssetRate(value?: FixedPoint): void; + + getSwapRfqId(): Uint8Array | string; + getSwapRfqId_asU8(): Uint8Array; + getSwapRfqId_asB64(): string; + setSwapRfqId(value: Uint8Array | string): void; + + getMaxSwapAssetAmt(): string; + setMaxSwapAssetAmt(value: string): void; + + hasSwapAssetRate(): boolean; + clearSwapAssetRate(): void; + getSwapAssetRate(): FixedPoint | undefined; + setSwapAssetRate(value?: FixedPoint): void; + + getAssetName(): string; + setAssetName(value: string): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): AssetRfqInfo.AsObject; + static toObject(includeInstance: boolean, msg: AssetRfqInfo): AssetRfqInfo.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: AssetRfqInfo, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): AssetRfqInfo; + static deserializeBinaryFromReader(message: AssetRfqInfo, reader: jspb.BinaryReader): AssetRfqInfo; +} + +export namespace AssetRfqInfo { + export type AsObject = { + prepayRfqId: Uint8Array | string, + maxPrepayAssetAmt: string, + prepayAssetRate?: FixedPoint.AsObject, + swapRfqId: Uint8Array | string, + maxSwapAssetAmt: string, + swapAssetRate?: FixedPoint.AsObject, + assetName: string, + } +} + +export class FixedPoint extends jspb.Message { + getCoefficient(): string; + setCoefficient(value: string): void; + + getScale(): number; + setScale(value: number): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): FixedPoint.AsObject; + static toObject(includeInstance: boolean, msg: FixedPoint): FixedPoint.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: FixedPoint, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): FixedPoint; + static deserializeBinaryFromReader(message: FixedPoint, reader: jspb.BinaryReader): FixedPoint; +} + +export namespace FixedPoint { + export type AsObject = { + coefficient: string, + scale: number, + } +} + +export class AssetLoopOutInfo extends jspb.Message { + getAssetId(): string; + setAssetId(value: string): void; + + getAssetName(): string; + setAssetName(value: string): void; + + getAssetCostOffchain(): string; + setAssetCostOffchain(value: string): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): AssetLoopOutInfo.AsObject; + static toObject(includeInstance: boolean, msg: AssetLoopOutInfo): AssetLoopOutInfo.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: AssetLoopOutInfo, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): AssetLoopOutInfo; + static deserializeBinaryFromReader(message: AssetLoopOutInfo, reader: jspb.BinaryReader): AssetLoopOutInfo; +} + +export namespace AssetLoopOutInfo { + export type AsObject = { + assetId: string, + assetName: string, + assetCostOffchain: string, + } +} + export interface AddressTypeMap { ADDRESS_TYPE_UNKNOWN: 0; TAPROOT_PUBKEY: 1; diff --git a/app/src/types/generated/loop_pb.js b/app/src/types/generated/loop_pb.js index 37d7766be..bc97b330c 100644 --- a/app/src/types/generated/loop_pb.js +++ b/app/src/types/generated/loop_pb.js @@ -29,14 +29,19 @@ goog.object.extend(proto, swapserverrpc_common_pb); goog.exportSymbol('proto.looprpc.AbandonSwapRequest', null, global); goog.exportSymbol('proto.looprpc.AbandonSwapResponse', null, global); goog.exportSymbol('proto.looprpc.AddressType', null, global); +goog.exportSymbol('proto.looprpc.AssetLoopOutInfo', null, global); +goog.exportSymbol('proto.looprpc.AssetLoopOutRequest', null, global); +goog.exportSymbol('proto.looprpc.AssetRfqInfo', null, global); goog.exportSymbol('proto.looprpc.AutoReason', null, global); goog.exportSymbol('proto.looprpc.ClientReservation', null, global); goog.exportSymbol('proto.looprpc.Deposit', null, global); goog.exportSymbol('proto.looprpc.DepositState', null, global); goog.exportSymbol('proto.looprpc.Disqualified', null, global); +goog.exportSymbol('proto.looprpc.EasyAssetAutoloopParams', null, global); goog.exportSymbol('proto.looprpc.FailureReason', null, global); goog.exportSymbol('proto.looprpc.FetchL402TokenRequest', null, global); goog.exportSymbol('proto.looprpc.FetchL402TokenResponse', null, global); +goog.exportSymbol('proto.looprpc.FixedPoint', null, global); goog.exportSymbol('proto.looprpc.GetInfoRequest', null, global); goog.exportSymbol('proto.looprpc.GetInfoResponse', null, global); goog.exportSymbol('proto.looprpc.GetLiquidityParamsRequest', null, global); @@ -665,6 +670,27 @@ if (goog.DEBUG && !COMPILED) { */ proto.looprpc.LiquidityParameters.displayName = 'proto.looprpc.LiquidityParameters'; } +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.looprpc.EasyAssetAutoloopParams = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.looprpc.EasyAssetAutoloopParams, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.looprpc.EasyAssetAutoloopParams.displayName = 'proto.looprpc.EasyAssetAutoloopParams'; +} /** * Generated by JsPbCodeGenerator. * @param {Array=} opt_data Optional initial data array, typically from a @@ -1421,6 +1447,90 @@ if (goog.DEBUG && !COMPILED) { */ proto.looprpc.StaticAddressLoopInResponse.displayName = 'proto.looprpc.StaticAddressLoopInResponse'; } +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.looprpc.AssetLoopOutRequest = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.looprpc.AssetLoopOutRequest, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.looprpc.AssetLoopOutRequest.displayName = 'proto.looprpc.AssetLoopOutRequest'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.looprpc.AssetRfqInfo = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.looprpc.AssetRfqInfo, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.looprpc.AssetRfqInfo.displayName = 'proto.looprpc.AssetRfqInfo'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.looprpc.FixedPoint = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.looprpc.FixedPoint, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.looprpc.FixedPoint.displayName = 'proto.looprpc.FixedPoint'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.looprpc.AssetLoopOutInfo = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.looprpc.AssetLoopOutInfo, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.looprpc.AssetLoopOutInfo.displayName = 'proto.looprpc.AssetLoopOutInfo'; +} /** * List of repeated fields within this message type. @@ -1478,7 +1588,9 @@ proto.looprpc.LoopOutRequest.toObject = function(includeInstance, msg) { accountAddrType: jspb.Message.getFieldWithDefault(msg, 16, 0), isExternalAddr: jspb.Message.getBooleanFieldWithDefault(msg, 17, false), reservationIdsList: msg.getReservationIdsList_asB64(), - paymentTimeout: jspb.Message.getFieldWithDefault(msg, 19, 0) + paymentTimeout: jspb.Message.getFieldWithDefault(msg, 19, 0), + assetInfo: (f = msg.getAssetInfo()) && proto.looprpc.AssetLoopOutRequest.toObject(includeInstance, f), + assetRfqInfo: (f = msg.getAssetRfqInfo()) && proto.looprpc.AssetRfqInfo.toObject(includeInstance, f) }; if (includeInstance) { @@ -1593,6 +1705,16 @@ proto.looprpc.LoopOutRequest.deserializeBinaryFromReader = function(msg, reader) var value = /** @type {number} */ (reader.readUint32()); msg.setPaymentTimeout(value); break; + case 20: + var value = new proto.looprpc.AssetLoopOutRequest; + reader.readMessage(value,proto.looprpc.AssetLoopOutRequest.deserializeBinaryFromReader); + msg.setAssetInfo(value); + break; + case 21: + var value = new proto.looprpc.AssetRfqInfo; + reader.readMessage(value,proto.looprpc.AssetRfqInfo.deserializeBinaryFromReader); + msg.setAssetRfqInfo(value); + break; default: reader.skipField(); break; @@ -1755,6 +1877,22 @@ proto.looprpc.LoopOutRequest.serializeBinaryToWriter = function(message, writer) f ); } + f = message.getAssetInfo(); + if (f != null) { + writer.writeMessage( + 20, + f, + proto.looprpc.AssetLoopOutRequest.serializeBinaryToWriter + ); + } + f = message.getAssetRfqInfo(); + if (f != null) { + writer.writeMessage( + 21, + f, + proto.looprpc.AssetRfqInfo.serializeBinaryToWriter + ); + } }; @@ -2162,6 +2300,80 @@ proto.looprpc.LoopOutRequest.prototype.setPaymentTimeout = function(value) { }; +/** + * optional AssetLoopOutRequest asset_info = 20; + * @return {?proto.looprpc.AssetLoopOutRequest} + */ +proto.looprpc.LoopOutRequest.prototype.getAssetInfo = function() { + return /** @type{?proto.looprpc.AssetLoopOutRequest} */ ( + jspb.Message.getWrapperField(this, proto.looprpc.AssetLoopOutRequest, 20)); +}; + + +/** + * @param {?proto.looprpc.AssetLoopOutRequest|undefined} value + * @return {!proto.looprpc.LoopOutRequest} returns this +*/ +proto.looprpc.LoopOutRequest.prototype.setAssetInfo = function(value) { + return jspb.Message.setWrapperField(this, 20, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.looprpc.LoopOutRequest} returns this + */ +proto.looprpc.LoopOutRequest.prototype.clearAssetInfo = function() { + return this.setAssetInfo(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.looprpc.LoopOutRequest.prototype.hasAssetInfo = function() { + return jspb.Message.getField(this, 20) != null; +}; + + +/** + * optional AssetRfqInfo asset_rfq_info = 21; + * @return {?proto.looprpc.AssetRfqInfo} + */ +proto.looprpc.LoopOutRequest.prototype.getAssetRfqInfo = function() { + return /** @type{?proto.looprpc.AssetRfqInfo} */ ( + jspb.Message.getWrapperField(this, proto.looprpc.AssetRfqInfo, 21)); +}; + + +/** + * @param {?proto.looprpc.AssetRfqInfo|undefined} value + * @return {!proto.looprpc.LoopOutRequest} returns this +*/ +proto.looprpc.LoopOutRequest.prototype.setAssetRfqInfo = function(value) { + return jspb.Message.setWrapperField(this, 21, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.looprpc.LoopOutRequest} returns this + */ +proto.looprpc.LoopOutRequest.prototype.clearAssetRfqInfo = function() { + return this.setAssetRfqInfo(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.looprpc.LoopOutRequest.prototype.hasAssetRfqInfo = function() { + return jspb.Message.getField(this, 21) != null; +}; + + /** * List of repeated fields within this message type. @@ -3076,7 +3288,8 @@ proto.looprpc.SwapStatus.toObject = function(includeInstance, msg) { costOffchain: jspb.Message.getFieldWithDefault(msg, 10, "0"), lastHop: msg.getLastHop_asB64(), outgoingChanSetList: (f = jspb.Message.getRepeatedField(msg, 17)) == null ? undefined : f, - label: jspb.Message.getFieldWithDefault(msg, 15, "") + label: jspb.Message.getFieldWithDefault(msg, 15, ""), + assetInfo: (f = msg.getAssetInfo()) && proto.looprpc.AssetLoopOutInfo.toObject(includeInstance, f) }; if (includeInstance) { @@ -3183,6 +3396,11 @@ proto.looprpc.SwapStatus.deserializeBinaryFromReader = function(msg, reader) { var value = /** @type {string} */ (reader.readString()); msg.setLabel(value); break; + case 19: + var value = new proto.looprpc.AssetLoopOutInfo; + reader.readMessage(value,proto.looprpc.AssetLoopOutInfo.deserializeBinaryFromReader); + msg.setAssetInfo(value); + break; default: reader.skipField(); break; @@ -3331,6 +3549,14 @@ proto.looprpc.SwapStatus.serializeBinaryToWriter = function(message, writer) { f ); } + f = message.getAssetInfo(); + if (f != null) { + writer.writeMessage( + 19, + f, + proto.looprpc.AssetLoopOutInfo.serializeBinaryToWriter + ); + } }; @@ -3707,6 +3933,43 @@ proto.looprpc.SwapStatus.prototype.setLabel = function(value) { }; +/** + * optional AssetLoopOutInfo asset_info = 19; + * @return {?proto.looprpc.AssetLoopOutInfo} + */ +proto.looprpc.SwapStatus.prototype.getAssetInfo = function() { + return /** @type{?proto.looprpc.AssetLoopOutInfo} */ ( + jspb.Message.getWrapperField(this, proto.looprpc.AssetLoopOutInfo, 19)); +}; + + +/** + * @param {?proto.looprpc.AssetLoopOutInfo|undefined} value + * @return {!proto.looprpc.SwapStatus} returns this +*/ +proto.looprpc.SwapStatus.prototype.setAssetInfo = function(value) { + return jspb.Message.setWrapperField(this, 19, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.looprpc.SwapStatus} returns this + */ +proto.looprpc.SwapStatus.prototype.clearAssetInfo = function() { + return this.setAssetInfo(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.looprpc.SwapStatus.prototype.hasAssetInfo = function() { + return jspb.Message.getField(this, 19) != null; +}; + + @@ -3739,7 +4002,8 @@ proto.looprpc.ListSwapsRequest.prototype.toObject = function(opt_includeInstance */ proto.looprpc.ListSwapsRequest.toObject = function(includeInstance, msg) { var f, obj = { - listSwapFilter: (f = msg.getListSwapFilter()) && proto.looprpc.ListSwapsFilter.toObject(includeInstance, f) + listSwapFilter: (f = msg.getListSwapFilter()) && proto.looprpc.ListSwapsFilter.toObject(includeInstance, f), + maxSwaps: jspb.Message.getFieldWithDefault(msg, 2, "0") }; if (includeInstance) { @@ -3781,6 +4045,10 @@ proto.looprpc.ListSwapsRequest.deserializeBinaryFromReader = function(msg, reade reader.readMessage(value,proto.looprpc.ListSwapsFilter.deserializeBinaryFromReader); msg.setListSwapFilter(value); break; + case 2: + var value = /** @type {string} */ (reader.readUint64String()); + msg.setMaxSwaps(value); + break; default: reader.skipField(); break; @@ -3818,6 +4086,13 @@ proto.looprpc.ListSwapsRequest.serializeBinaryToWriter = function(message, write proto.looprpc.ListSwapsFilter.serializeBinaryToWriter ); } + f = message.getMaxSwaps(); + if (parseInt(f, 10) !== 0) { + writer.writeUint64String( + 2, + f + ); + } }; @@ -3858,6 +4133,24 @@ proto.looprpc.ListSwapsRequest.prototype.hasListSwapFilter = function() { }; +/** + * optional uint64 max_swaps = 2; + * @return {string} + */ +proto.looprpc.ListSwapsRequest.prototype.getMaxSwaps = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "0")); +}; + + +/** + * @param {string} value + * @return {!proto.looprpc.ListSwapsRequest} returns this + */ +proto.looprpc.ListSwapsRequest.prototype.setMaxSwaps = function(value) { + return jspb.Message.setProto3StringIntField(this, 2, value); +}; + + /** * List of repeated fields within this message type. @@ -3901,7 +4194,9 @@ proto.looprpc.ListSwapsFilter.toObject = function(includeInstance, msg) { pendingOnly: jspb.Message.getBooleanFieldWithDefault(msg, 2, false), outgoingChanSetList: (f = jspb.Message.getRepeatedField(msg, 3)) == null ? undefined : f, label: jspb.Message.getFieldWithDefault(msg, 4, ""), - loopInLastHop: msg.getLoopInLastHop_asB64() + loopInLastHop: msg.getLoopInLastHop_asB64(), + assetSwapOnly: jspb.Message.getBooleanFieldWithDefault(msg, 6, false), + startTimestampNs: jspb.Message.getFieldWithDefault(msg, 7, "0") }; if (includeInstance) { @@ -3960,6 +4255,14 @@ proto.looprpc.ListSwapsFilter.deserializeBinaryFromReader = function(msg, reader var value = /** @type {!Uint8Array} */ (reader.readBytes()); msg.setLoopInLastHop(value); break; + case 6: + var value = /** @type {boolean} */ (reader.readBool()); + msg.setAssetSwapOnly(value); + break; + case 7: + var value = /** @type {string} */ (reader.readInt64String()); + msg.setStartTimestampNs(value); + break; default: reader.skipField(); break; @@ -4024,6 +4327,20 @@ proto.looprpc.ListSwapsFilter.serializeBinaryToWriter = function(message, writer f ); } + f = message.getAssetSwapOnly(); + if (f) { + writer.writeBool( + 6, + f + ); + } + f = message.getStartTimestampNs(); + if (parseInt(f, 10) !== 0) { + writer.writeInt64String( + 7, + f + ); + } }; @@ -4169,36 +4486,72 @@ proto.looprpc.ListSwapsFilter.prototype.setLoopInLastHop = function(value) { }; - /** - * List of repeated fields within this message type. - * @private {!Array} - * @const + * optional bool asset_swap_only = 6; + * @return {boolean} */ -proto.looprpc.ListSwapsResponse.repeatedFields_ = [1]; - +proto.looprpc.ListSwapsFilter.prototype.getAssetSwapOnly = function() { + return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 6, false)); +}; -if (jspb.Message.GENERATE_TO_OBJECT) { /** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} + * @param {boolean} value + * @return {!proto.looprpc.ListSwapsFilter} returns this */ -proto.looprpc.ListSwapsResponse.prototype.toObject = function(opt_includeInstance) { - return proto.looprpc.ListSwapsResponse.toObject(opt_includeInstance, this); +proto.looprpc.ListSwapsFilter.prototype.setAssetSwapOnly = function(value) { + return jspb.Message.setProto3BooleanField(this, 6, value); }; /** - * Static version of the {@see toObject} method. + * optional int64 start_timestamp_ns = 7; + * @return {string} + */ +proto.looprpc.ListSwapsFilter.prototype.getStartTimestampNs = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 7, "0")); +}; + + +/** + * @param {string} value + * @return {!proto.looprpc.ListSwapsFilter} returns this + */ +proto.looprpc.ListSwapsFilter.prototype.setStartTimestampNs = function(value) { + return jspb.Message.setProto3StringIntField(this, 7, value); +}; + + + +/** + * List of repeated fields within this message type. + * @private {!Array} + * @const + */ +proto.looprpc.ListSwapsResponse.repeatedFields_ = [1]; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.looprpc.ListSwapsResponse.prototype.toObject = function(opt_includeInstance) { + return proto.looprpc.ListSwapsResponse.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. * @param {boolean|undefined} includeInstance Deprecated. Whether to include * the JSPB instance for transitional soy proto support: * http://goto/soy-param-migration @@ -4209,7 +4562,8 @@ proto.looprpc.ListSwapsResponse.prototype.toObject = function(opt_includeInstanc proto.looprpc.ListSwapsResponse.toObject = function(includeInstance, msg) { var f, obj = { swapsList: jspb.Message.toObjectList(msg.getSwapsList(), - proto.looprpc.SwapStatus.toObject, includeInstance) + proto.looprpc.SwapStatus.toObject, includeInstance), + nextStartTime: jspb.Message.getFieldWithDefault(msg, 2, "0") }; if (includeInstance) { @@ -4251,6 +4605,10 @@ proto.looprpc.ListSwapsResponse.deserializeBinaryFromReader = function(msg, read reader.readMessage(value,proto.looprpc.SwapStatus.deserializeBinaryFromReader); msg.addSwaps(value); break; + case 2: + var value = /** @type {string} */ (reader.readInt64String()); + msg.setNextStartTime(value); + break; default: reader.skipField(); break; @@ -4288,6 +4646,13 @@ proto.looprpc.ListSwapsResponse.serializeBinaryToWriter = function(message, writ proto.looprpc.SwapStatus.serializeBinaryToWriter ); } + f = message.getNextStartTime(); + if (parseInt(f, 10) !== 0) { + writer.writeInt64String( + 2, + f + ); + } }; @@ -4329,6 +4694,24 @@ proto.looprpc.ListSwapsResponse.prototype.clearSwapsList = function() { }; +/** + * optional int64 next_start_time = 2; + * @return {string} + */ +proto.looprpc.ListSwapsResponse.prototype.getNextStartTime = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "0")); +}; + + +/** + * @param {string} value + * @return {!proto.looprpc.ListSwapsResponse} returns this + */ +proto.looprpc.ListSwapsResponse.prototype.setNextStartTime = function(value) { + return jspb.Message.setProto3StringIntField(this, 2, value); +}; + + @@ -5011,7 +5394,8 @@ proto.looprpc.QuoteRequest.toObject = function(includeInstance, msg) { loopInRouteHintsList: jspb.Message.toObjectList(msg.getLoopInRouteHintsList(), swapserverrpc_common_pb.RouteHint.toObject, includeInstance), pb_private: jspb.Message.getBooleanFieldWithDefault(msg, 7, false), - depositOutpointsList: (f = jspb.Message.getRepeatedField(msg, 8)) == null ? undefined : f + depositOutpointsList: (f = jspb.Message.getRepeatedField(msg, 8)) == null ? undefined : f, + assetInfo: (f = msg.getAssetInfo()) && proto.looprpc.AssetLoopOutRequest.toObject(includeInstance, f) }; if (includeInstance) { @@ -5081,6 +5465,11 @@ proto.looprpc.QuoteRequest.deserializeBinaryFromReader = function(msg, reader) { var value = /** @type {string} */ (reader.readString()); msg.addDepositOutpoints(value); break; + case 9: + var value = new proto.looprpc.AssetLoopOutRequest; + reader.readMessage(value,proto.looprpc.AssetLoopOutRequest.deserializeBinaryFromReader); + msg.setAssetInfo(value); + break; default: reader.skipField(); break; @@ -5167,6 +5556,14 @@ proto.looprpc.QuoteRequest.serializeBinaryToWriter = function(message, writer) { f ); } + f = message.getAssetInfo(); + if (f != null) { + writer.writeMessage( + 9, + f, + proto.looprpc.AssetLoopOutRequest.serializeBinaryToWriter + ); + } }; @@ -5377,6 +5774,43 @@ proto.looprpc.QuoteRequest.prototype.clearDepositOutpointsList = function() { }; +/** + * optional AssetLoopOutRequest asset_info = 9; + * @return {?proto.looprpc.AssetLoopOutRequest} + */ +proto.looprpc.QuoteRequest.prototype.getAssetInfo = function() { + return /** @type{?proto.looprpc.AssetLoopOutRequest} */ ( + jspb.Message.getWrapperField(this, proto.looprpc.AssetLoopOutRequest, 9)); +}; + + +/** + * @param {?proto.looprpc.AssetLoopOutRequest|undefined} value + * @return {!proto.looprpc.QuoteRequest} returns this +*/ +proto.looprpc.QuoteRequest.prototype.setAssetInfo = function(value) { + return jspb.Message.setWrapperField(this, 9, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.looprpc.QuoteRequest} returns this + */ +proto.looprpc.QuoteRequest.prototype.clearAssetInfo = function() { + return this.setAssetInfo(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.looprpc.QuoteRequest.prototype.hasAssetInfo = function() { + return jspb.Message.getField(this, 9) != null; +}; + + @@ -5634,7 +6068,8 @@ proto.looprpc.OutQuoteResponse.toObject = function(includeInstance, msg) { htlcSweepFeeSat: jspb.Message.getFieldWithDefault(msg, 3, "0"), swapPaymentDest: msg.getSwapPaymentDest_asB64(), cltvDelta: jspb.Message.getFieldWithDefault(msg, 5, 0), - confTarget: jspb.Message.getFieldWithDefault(msg, 6, 0) + confTarget: jspb.Message.getFieldWithDefault(msg, 6, 0), + assetRfqInfo: (f = msg.getAssetRfqInfo()) && proto.looprpc.AssetRfqInfo.toObject(includeInstance, f) }; if (includeInstance) { @@ -5695,6 +6130,11 @@ proto.looprpc.OutQuoteResponse.deserializeBinaryFromReader = function(msg, reade var value = /** @type {number} */ (reader.readInt32()); msg.setConfTarget(value); break; + case 7: + var value = new proto.looprpc.AssetRfqInfo; + reader.readMessage(value,proto.looprpc.AssetRfqInfo.deserializeBinaryFromReader); + msg.setAssetRfqInfo(value); + break; default: reader.skipField(); break; @@ -5766,6 +6206,14 @@ proto.looprpc.OutQuoteResponse.serializeBinaryToWriter = function(message, write f ); } + f = message.getAssetRfqInfo(); + if (f != null) { + writer.writeMessage( + 7, + f, + proto.looprpc.AssetRfqInfo.serializeBinaryToWriter + ); + } }; @@ -5901,6 +6349,43 @@ proto.looprpc.OutQuoteResponse.prototype.setConfTarget = function(value) { }; +/** + * optional AssetRfqInfo asset_rfq_info = 7; + * @return {?proto.looprpc.AssetRfqInfo} + */ +proto.looprpc.OutQuoteResponse.prototype.getAssetRfqInfo = function() { + return /** @type{?proto.looprpc.AssetRfqInfo} */ ( + jspb.Message.getWrapperField(this, proto.looprpc.AssetRfqInfo, 7)); +}; + + +/** + * @param {?proto.looprpc.AssetRfqInfo|undefined} value + * @return {!proto.looprpc.OutQuoteResponse} returns this +*/ +proto.looprpc.OutQuoteResponse.prototype.setAssetRfqInfo = function(value) { + return jspb.Message.setWrapperField(this, 7, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.looprpc.OutQuoteResponse} returns this + */ +proto.looprpc.OutQuoteResponse.prototype.clearAssetRfqInfo = function() { + return this.setAssetRfqInfo(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.looprpc.OutQuoteResponse.prototype.hasAssetRfqInfo = function() { + return jspb.Message.getField(this, 7) != null; +}; + + /** * List of repeated fields within this message type. @@ -7541,7 +8026,8 @@ proto.looprpc.GetInfoResponse.toObject = function(includeInstance, msg) { macaroonPath: jspb.Message.getFieldWithDefault(msg, 5, ""), tlsCertPath: jspb.Message.getFieldWithDefault(msg, 6, ""), loopOutStats: (f = msg.getLoopOutStats()) && proto.looprpc.LoopStats.toObject(includeInstance, f), - loopInStats: (f = msg.getLoopInStats()) && proto.looprpc.LoopStats.toObject(includeInstance, f) + loopInStats: (f = msg.getLoopInStats()) && proto.looprpc.LoopStats.toObject(includeInstance, f), + commitHash: jspb.Message.getFieldWithDefault(msg, 9, "") }; if (includeInstance) { @@ -7612,6 +8098,10 @@ proto.looprpc.GetInfoResponse.deserializeBinaryFromReader = function(msg, reader reader.readMessage(value,proto.looprpc.LoopStats.deserializeBinaryFromReader); msg.setLoopInStats(value); break; + case 9: + var value = /** @type {string} */ (reader.readString()); + msg.setCommitHash(value); + break; default: reader.skipField(); break; @@ -7699,6 +8189,13 @@ proto.looprpc.GetInfoResponse.serializeBinaryToWriter = function(message, writer proto.looprpc.LoopStats.serializeBinaryToWriter ); } + f = message.getCommitHash(); + if (f.length > 0) { + writer.writeString( + 9, + f + ); + } }; @@ -7884,6 +8381,24 @@ proto.looprpc.GetInfoResponse.prototype.hasLoopInStats = function() { }; +/** + * optional string commit_hash = 9; + * @return {string} + */ +proto.looprpc.GetInfoResponse.prototype.getCommitHash = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 9, "")); +}; + + +/** + * @param {string} value + * @return {!proto.looprpc.GetInfoResponse} returns this + */ +proto.looprpc.GetInfoResponse.prototype.setCommitHash = function(value) { + return jspb.Message.setProto3StringField(this, 9, value); +}; + + @@ -8048,7 +8563,8 @@ proto.looprpc.LiquidityParameters.toObject = function(includeInstance, msg) { easyAutoloop: jspb.Message.getBooleanFieldWithDefault(msg, 21, false), easyAutoloopLocalTargetSat: jspb.Message.getFieldWithDefault(msg, 22, "0"), account: jspb.Message.getFieldWithDefault(msg, 23, ""), - accountAddrType: jspb.Message.getFieldWithDefault(msg, 24, 0) + accountAddrType: jspb.Message.getFieldWithDefault(msg, 24, 0), + easyAssetParamsMap: (f = msg.getEasyAssetParamsMap()) ? f.toObject(includeInstance, proto.looprpc.EasyAssetAutoloopParams.toObject) : [] }; if (includeInstance) { @@ -8182,6 +8698,12 @@ proto.looprpc.LiquidityParameters.deserializeBinaryFromReader = function(msg, re var value = /** @type {!proto.looprpc.AddressType} */ (reader.readEnum()); msg.setAccountAddrType(value); break; + case 25: + var value = msg.getEasyAssetParamsMap(); + reader.readMessage(value, function(message, reader) { + jspb.Map.deserializeBinary(message, reader, jspb.BinaryReader.prototype.readString, jspb.BinaryReader.prototype.readMessage, proto.looprpc.EasyAssetAutoloopParams.deserializeBinaryFromReader, "", new proto.looprpc.EasyAssetAutoloopParams()); + }); + break; default: reader.skipField(); break; @@ -8380,6 +8902,10 @@ proto.looprpc.LiquidityParameters.serializeBinaryToWriter = function(message, wr f ); } + f = message.getEasyAssetParamsMap(true); + if (f && f.getLength() > 0) { + f.serializeBinary(25, writer, jspb.BinaryWriter.prototype.writeString, jspb.BinaryWriter.prototype.writeMessage, proto.looprpc.EasyAssetAutoloopParams.serializeBinaryToWriter); + } }; @@ -8835,6 +9361,29 @@ proto.looprpc.LiquidityParameters.prototype.setAccountAddrType = function(value) }; +/** + * map easy_asset_params = 25; + * @param {boolean=} opt_noLazyCreate Do not create the map if + * empty, instead returning `undefined` + * @return {!jspb.Map} + */ +proto.looprpc.LiquidityParameters.prototype.getEasyAssetParamsMap = function(opt_noLazyCreate) { + return /** @type {!jspb.Map} */ ( + jspb.Message.getMapField(this, 25, opt_noLazyCreate, + proto.looprpc.EasyAssetAutoloopParams)); +}; + + +/** + * Clears values from the map. The map will be non-null. + * @return {!proto.looprpc.LiquidityParameters} returns this + */ +proto.looprpc.LiquidityParameters.prototype.clearEasyAssetParamsMap = function() { + this.getEasyAssetParamsMap().clear(); + return this; +}; + + @@ -8851,8 +9400,8 @@ if (jspb.Message.GENERATE_TO_OBJECT) { * http://goto/soy-param-migration * @return {!Object} */ -proto.looprpc.LiquidityRule.prototype.toObject = function(opt_includeInstance) { - return proto.looprpc.LiquidityRule.toObject(opt_includeInstance, this); +proto.looprpc.EasyAssetAutoloopParams.prototype.toObject = function(opt_includeInstance) { + return proto.looprpc.EasyAssetAutoloopParams.toObject(opt_includeInstance, this); }; @@ -8861,18 +9410,14 @@ proto.looprpc.LiquidityRule.prototype.toObject = function(opt_includeInstance) { * @param {boolean|undefined} includeInstance Deprecated. Whether to include * the JSPB instance for transitional soy proto support: * http://goto/soy-param-migration - * @param {!proto.looprpc.LiquidityRule} msg The msg instance to transform. + * @param {!proto.looprpc.EasyAssetAutoloopParams} msg The msg instance to transform. * @return {!Object} * @suppress {unusedLocalVariables} f is only used for nested messages */ -proto.looprpc.LiquidityRule.toObject = function(includeInstance, msg) { +proto.looprpc.EasyAssetAutoloopParams.toObject = function(includeInstance, msg) { var f, obj = { - channelId: jspb.Message.getFieldWithDefault(msg, 1, "0"), - swapType: jspb.Message.getFieldWithDefault(msg, 6, 0), - pubkey: msg.getPubkey_asB64(), - type: jspb.Message.getFieldWithDefault(msg, 2, 0), - incomingThreshold: jspb.Message.getFieldWithDefault(msg, 3, 0), - outgoingThreshold: jspb.Message.getFieldWithDefault(msg, 4, 0) + enabled: jspb.Message.getBooleanFieldWithDefault(msg, 1, false), + localTargetAssetAmt: jspb.Message.getFieldWithDefault(msg, 2, "0") }; if (includeInstance) { @@ -8886,23 +9431,23 @@ proto.looprpc.LiquidityRule.toObject = function(includeInstance, msg) { /** * Deserializes binary data (in protobuf wire format). * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.looprpc.LiquidityRule} + * @return {!proto.looprpc.EasyAssetAutoloopParams} */ -proto.looprpc.LiquidityRule.deserializeBinary = function(bytes) { +proto.looprpc.EasyAssetAutoloopParams.deserializeBinary = function(bytes) { var reader = new jspb.BinaryReader(bytes); - var msg = new proto.looprpc.LiquidityRule; - return proto.looprpc.LiquidityRule.deserializeBinaryFromReader(msg, reader); + var msg = new proto.looprpc.EasyAssetAutoloopParams; + return proto.looprpc.EasyAssetAutoloopParams.deserializeBinaryFromReader(msg, reader); }; /** * Deserializes binary data (in protobuf wire format) from the * given reader into the given message object. - * @param {!proto.looprpc.LiquidityRule} msg The message object to deserialize into. + * @param {!proto.looprpc.EasyAssetAutoloopParams} msg The message object to deserialize into. * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.looprpc.LiquidityRule} + * @return {!proto.looprpc.EasyAssetAutoloopParams} */ -proto.looprpc.LiquidityRule.deserializeBinaryFromReader = function(msg, reader) { +proto.looprpc.EasyAssetAutoloopParams.deserializeBinaryFromReader = function(msg, reader) { while (reader.nextField()) { if (reader.isEndGroup()) { break; @@ -8910,28 +9455,12 @@ proto.looprpc.LiquidityRule.deserializeBinaryFromReader = function(msg, reader) var field = reader.getFieldNumber(); switch (field) { case 1: - var value = /** @type {string} */ (reader.readUint64String()); - msg.setChannelId(value); - break; - case 6: - var value = /** @type {!proto.looprpc.SwapType} */ (reader.readEnum()); - msg.setSwapType(value); - break; - case 5: - var value = /** @type {!Uint8Array} */ (reader.readBytes()); - msg.setPubkey(value); + var value = /** @type {boolean} */ (reader.readBool()); + msg.setEnabled(value); break; case 2: - var value = /** @type {!proto.looprpc.LiquidityRuleType} */ (reader.readEnum()); - msg.setType(value); - break; - case 3: - var value = /** @type {number} */ (reader.readUint32()); - msg.setIncomingThreshold(value); - break; - case 4: - var value = /** @type {number} */ (reader.readUint32()); - msg.setOutgoingThreshold(value); + var value = /** @type {string} */ (reader.readUint64String()); + msg.setLocalTargetAssetAmt(value); break; default: reader.skipField(); @@ -8946,9 +9475,9 @@ proto.looprpc.LiquidityRule.deserializeBinaryFromReader = function(msg, reader) * Serializes the message to binary data (in protobuf wire format). * @return {!Uint8Array} */ -proto.looprpc.LiquidityRule.prototype.serializeBinary = function() { +proto.looprpc.EasyAssetAutoloopParams.prototype.serializeBinary = function() { var writer = new jspb.BinaryWriter(); - proto.looprpc.LiquidityRule.serializeBinaryToWriter(this, writer); + proto.looprpc.EasyAssetAutoloopParams.serializeBinaryToWriter(this, writer); return writer.getResultBuffer(); }; @@ -8956,59 +9485,239 @@ proto.looprpc.LiquidityRule.prototype.serializeBinary = function() { /** * Serializes the given message to binary data (in protobuf wire * format), writing to the given BinaryWriter. - * @param {!proto.looprpc.LiquidityRule} message + * @param {!proto.looprpc.EasyAssetAutoloopParams} message * @param {!jspb.BinaryWriter} writer * @suppress {unusedLocalVariables} f is only used for nested messages */ -proto.looprpc.LiquidityRule.serializeBinaryToWriter = function(message, writer) { +proto.looprpc.EasyAssetAutoloopParams.serializeBinaryToWriter = function(message, writer) { var f = undefined; - f = message.getChannelId(); - if (parseInt(f, 10) !== 0) { - writer.writeUint64String( + f = message.getEnabled(); + if (f) { + writer.writeBool( 1, f ); } - f = message.getSwapType(); - if (f !== 0.0) { - writer.writeEnum( - 6, - f - ); - } - f = message.getPubkey_asU8(); - if (f.length > 0) { - writer.writeBytes( - 5, - f - ); - } - f = message.getType(); - if (f !== 0.0) { - writer.writeEnum( + f = message.getLocalTargetAssetAmt(); + if (parseInt(f, 10) !== 0) { + writer.writeUint64String( 2, f ); } - f = message.getIncomingThreshold(); - if (f !== 0) { - writer.writeUint32( - 3, - f - ); - } - f = message.getOutgoingThreshold(); - if (f !== 0) { - writer.writeUint32( - 4, - f - ); - } }; /** - * optional uint64 channel_id = 1; + * optional bool enabled = 1; + * @return {boolean} + */ +proto.looprpc.EasyAssetAutoloopParams.prototype.getEnabled = function() { + return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 1, false)); +}; + + +/** + * @param {boolean} value + * @return {!proto.looprpc.EasyAssetAutoloopParams} returns this + */ +proto.looprpc.EasyAssetAutoloopParams.prototype.setEnabled = function(value) { + return jspb.Message.setProto3BooleanField(this, 1, value); +}; + + +/** + * optional uint64 local_target_asset_amt = 2; + * @return {string} + */ +proto.looprpc.EasyAssetAutoloopParams.prototype.getLocalTargetAssetAmt = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "0")); +}; + + +/** + * @param {string} value + * @return {!proto.looprpc.EasyAssetAutoloopParams} returns this + */ +proto.looprpc.EasyAssetAutoloopParams.prototype.setLocalTargetAssetAmt = function(value) { + return jspb.Message.setProto3StringIntField(this, 2, value); +}; + + + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.looprpc.LiquidityRule.prototype.toObject = function(opt_includeInstance) { + return proto.looprpc.LiquidityRule.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.looprpc.LiquidityRule} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.looprpc.LiquidityRule.toObject = function(includeInstance, msg) { + var f, obj = { + channelId: jspb.Message.getFieldWithDefault(msg, 1, "0"), + swapType: jspb.Message.getFieldWithDefault(msg, 6, 0), + pubkey: msg.getPubkey_asB64(), + type: jspb.Message.getFieldWithDefault(msg, 2, 0), + incomingThreshold: jspb.Message.getFieldWithDefault(msg, 3, 0), + outgoingThreshold: jspb.Message.getFieldWithDefault(msg, 4, 0) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.looprpc.LiquidityRule} + */ +proto.looprpc.LiquidityRule.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.looprpc.LiquidityRule; + return proto.looprpc.LiquidityRule.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.looprpc.LiquidityRule} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.looprpc.LiquidityRule} + */ +proto.looprpc.LiquidityRule.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {string} */ (reader.readUint64String()); + msg.setChannelId(value); + break; + case 6: + var value = /** @type {!proto.looprpc.SwapType} */ (reader.readEnum()); + msg.setSwapType(value); + break; + case 5: + var value = /** @type {!Uint8Array} */ (reader.readBytes()); + msg.setPubkey(value); + break; + case 2: + var value = /** @type {!proto.looprpc.LiquidityRuleType} */ (reader.readEnum()); + msg.setType(value); + break; + case 3: + var value = /** @type {number} */ (reader.readUint32()); + msg.setIncomingThreshold(value); + break; + case 4: + var value = /** @type {number} */ (reader.readUint32()); + msg.setOutgoingThreshold(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.looprpc.LiquidityRule.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.looprpc.LiquidityRule.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.looprpc.LiquidityRule} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.looprpc.LiquidityRule.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getChannelId(); + if (parseInt(f, 10) !== 0) { + writer.writeUint64String( + 1, + f + ); + } + f = message.getSwapType(); + if (f !== 0.0) { + writer.writeEnum( + 6, + f + ); + } + f = message.getPubkey_asU8(); + if (f.length > 0) { + writer.writeBytes( + 5, + f + ); + } + f = message.getType(); + if (f !== 0.0) { + writer.writeEnum( + 2, + f + ); + } + f = message.getIncomingThreshold(); + if (f !== 0) { + writer.writeUint32( + 3, + f + ); + } + f = message.getOutgoingThreshold(); + if (f !== 0) { + writer.writeUint32( + 4, + f + ); + } +}; + + +/** + * optional uint64 channel_id = 1; * @return {string} */ proto.looprpc.LiquidityRule.prototype.getChannelId = function() { @@ -13099,7 +13808,8 @@ proto.looprpc.WithdrawDepositsRequest.toObject = function(includeInstance, msg) proto.looprpc.OutPoint.toObject, includeInstance), all: jspb.Message.getBooleanFieldWithDefault(msg, 2, false), destAddr: jspb.Message.getFieldWithDefault(msg, 3, ""), - satPerVbyte: jspb.Message.getFieldWithDefault(msg, 4, "0") + satPerVbyte: jspb.Message.getFieldWithDefault(msg, 4, "0"), + amount: jspb.Message.getFieldWithDefault(msg, 5, "0") }; if (includeInstance) { @@ -13153,6 +13863,10 @@ proto.looprpc.WithdrawDepositsRequest.deserializeBinaryFromReader = function(msg var value = /** @type {string} */ (reader.readInt64String()); msg.setSatPerVbyte(value); break; + case 5: + var value = /** @type {string} */ (reader.readInt64String()); + msg.setAmount(value); + break; default: reader.skipField(); break; @@ -13211,6 +13925,13 @@ proto.looprpc.WithdrawDepositsRequest.serializeBinaryToWriter = function(message f ); } + f = message.getAmount(); + if (parseInt(f, 10) !== 0) { + writer.writeInt64String( + 5, + f + ); + } }; @@ -13306,6 +14027,24 @@ proto.looprpc.WithdrawDepositsRequest.prototype.setSatPerVbyte = function(value) }; +/** + * optional int64 amount = 5; + * @return {string} + */ +proto.looprpc.WithdrawDepositsRequest.prototype.getAmount = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 5, "0")); +}; + + +/** + * @param {string} value + * @return {!proto.looprpc.WithdrawDepositsRequest} returns this + */ +proto.looprpc.WithdrawDepositsRequest.prototype.setAmount = function(value) { + return jspb.Message.setProto3StringIntField(this, 5, value); +}; + + @@ -13339,7 +14078,7 @@ proto.looprpc.WithdrawDepositsResponse.prototype.toObject = function(opt_include proto.looprpc.WithdrawDepositsResponse.toObject = function(includeInstance, msg) { var f, obj = { withdrawalTxHash: jspb.Message.getFieldWithDefault(msg, 1, ""), - pkScript: jspb.Message.getFieldWithDefault(msg, 2, "") + address: jspb.Message.getFieldWithDefault(msg, 2, "") }; if (includeInstance) { @@ -13382,7 +14121,7 @@ proto.looprpc.WithdrawDepositsResponse.deserializeBinaryFromReader = function(ms break; case 2: var value = /** @type {string} */ (reader.readString()); - msg.setPkScript(value); + msg.setAddress(value); break; default: reader.skipField(); @@ -13420,7 +14159,7 @@ proto.looprpc.WithdrawDepositsResponse.serializeBinaryToWriter = function(messag f ); } - f = message.getPkScript(); + f = message.getAddress(); if (f.length > 0) { writer.writeString( 2, @@ -13449,10 +14188,10 @@ proto.looprpc.WithdrawDepositsResponse.prototype.setWithdrawalTxHash = function( /** - * optional string pk_script = 2; + * optional string address = 2; * @return {string} */ -proto.looprpc.WithdrawDepositsResponse.prototype.getPkScript = function() { +proto.looprpc.WithdrawDepositsResponse.prototype.getAddress = function() { return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); }; @@ -13461,7 +14200,7 @@ proto.looprpc.WithdrawDepositsResponse.prototype.getPkScript = function() { * @param {string} value * @return {!proto.looprpc.WithdrawDepositsResponse} returns this */ -proto.looprpc.WithdrawDepositsResponse.prototype.setPkScript = function(value) { +proto.looprpc.WithdrawDepositsResponse.prototype.setAddress = function(value) { return jspb.Message.setProto3StringField(this, 2, value); }; @@ -16229,6 +16968,1024 @@ proto.looprpc.StaticAddressLoopInResponse.prototype.setPaymentTimeoutSeconds = f }; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.looprpc.AssetLoopOutRequest.prototype.toObject = function(opt_includeInstance) { + return proto.looprpc.AssetLoopOutRequest.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.looprpc.AssetLoopOutRequest} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.looprpc.AssetLoopOutRequest.toObject = function(includeInstance, msg) { + var f, obj = { + assetId: msg.getAssetId_asB64(), + assetEdgeNode: msg.getAssetEdgeNode_asB64(), + maxLimitMultiplier: jspb.Message.getFloatingPointFieldWithDefault(msg, 3, 0.0), + expiry: jspb.Message.getFieldWithDefault(msg, 4, "0") + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.looprpc.AssetLoopOutRequest} + */ +proto.looprpc.AssetLoopOutRequest.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.looprpc.AssetLoopOutRequest; + return proto.looprpc.AssetLoopOutRequest.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.looprpc.AssetLoopOutRequest} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.looprpc.AssetLoopOutRequest} + */ +proto.looprpc.AssetLoopOutRequest.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {!Uint8Array} */ (reader.readBytes()); + msg.setAssetId(value); + break; + case 2: + var value = /** @type {!Uint8Array} */ (reader.readBytes()); + msg.setAssetEdgeNode(value); + break; + case 3: + var value = /** @type {number} */ (reader.readDouble()); + msg.setMaxLimitMultiplier(value); + break; + case 4: + var value = /** @type {string} */ (reader.readInt64String()); + msg.setExpiry(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.looprpc.AssetLoopOutRequest.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.looprpc.AssetLoopOutRequest.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.looprpc.AssetLoopOutRequest} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.looprpc.AssetLoopOutRequest.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getAssetId_asU8(); + if (f.length > 0) { + writer.writeBytes( + 1, + f + ); + } + f = message.getAssetEdgeNode_asU8(); + if (f.length > 0) { + writer.writeBytes( + 2, + f + ); + } + f = message.getMaxLimitMultiplier(); + if (f !== 0.0) { + writer.writeDouble( + 3, + f + ); + } + f = message.getExpiry(); + if (parseInt(f, 10) !== 0) { + writer.writeInt64String( + 4, + f + ); + } +}; + + +/** + * optional bytes asset_id = 1; + * @return {!(string|Uint8Array)} + */ +proto.looprpc.AssetLoopOutRequest.prototype.getAssetId = function() { + return /** @type {!(string|Uint8Array)} */ (jspb.Message.getFieldWithDefault(this, 1, "")); +}; + + +/** + * optional bytes asset_id = 1; + * This is a type-conversion wrapper around `getAssetId()` + * @return {string} + */ +proto.looprpc.AssetLoopOutRequest.prototype.getAssetId_asB64 = function() { + return /** @type {string} */ (jspb.Message.bytesAsB64( + this.getAssetId())); +}; + + +/** + * optional bytes asset_id = 1; + * Note that Uint8Array is not supported on all browsers. + * @see http://caniuse.com/Uint8Array + * This is a type-conversion wrapper around `getAssetId()` + * @return {!Uint8Array} + */ +proto.looprpc.AssetLoopOutRequest.prototype.getAssetId_asU8 = function() { + return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8( + this.getAssetId())); +}; + + +/** + * @param {!(string|Uint8Array)} value + * @return {!proto.looprpc.AssetLoopOutRequest} returns this + */ +proto.looprpc.AssetLoopOutRequest.prototype.setAssetId = function(value) { + return jspb.Message.setProto3BytesField(this, 1, value); +}; + + +/** + * optional bytes asset_edge_node = 2; + * @return {!(string|Uint8Array)} + */ +proto.looprpc.AssetLoopOutRequest.prototype.getAssetEdgeNode = function() { + return /** @type {!(string|Uint8Array)} */ (jspb.Message.getFieldWithDefault(this, 2, "")); +}; + + +/** + * optional bytes asset_edge_node = 2; + * This is a type-conversion wrapper around `getAssetEdgeNode()` + * @return {string} + */ +proto.looprpc.AssetLoopOutRequest.prototype.getAssetEdgeNode_asB64 = function() { + return /** @type {string} */ (jspb.Message.bytesAsB64( + this.getAssetEdgeNode())); +}; + + +/** + * optional bytes asset_edge_node = 2; + * Note that Uint8Array is not supported on all browsers. + * @see http://caniuse.com/Uint8Array + * This is a type-conversion wrapper around `getAssetEdgeNode()` + * @return {!Uint8Array} + */ +proto.looprpc.AssetLoopOutRequest.prototype.getAssetEdgeNode_asU8 = function() { + return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8( + this.getAssetEdgeNode())); +}; + + +/** + * @param {!(string|Uint8Array)} value + * @return {!proto.looprpc.AssetLoopOutRequest} returns this + */ +proto.looprpc.AssetLoopOutRequest.prototype.setAssetEdgeNode = function(value) { + return jspb.Message.setProto3BytesField(this, 2, value); +}; + + +/** + * optional double max_limit_multiplier = 3; + * @return {number} + */ +proto.looprpc.AssetLoopOutRequest.prototype.getMaxLimitMultiplier = function() { + return /** @type {number} */ (jspb.Message.getFloatingPointFieldWithDefault(this, 3, 0.0)); +}; + + +/** + * @param {number} value + * @return {!proto.looprpc.AssetLoopOutRequest} returns this + */ +proto.looprpc.AssetLoopOutRequest.prototype.setMaxLimitMultiplier = function(value) { + return jspb.Message.setProto3FloatField(this, 3, value); +}; + + +/** + * optional int64 expiry = 4; + * @return {string} + */ +proto.looprpc.AssetLoopOutRequest.prototype.getExpiry = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 4, "0")); +}; + + +/** + * @param {string} value + * @return {!proto.looprpc.AssetLoopOutRequest} returns this + */ +proto.looprpc.AssetLoopOutRequest.prototype.setExpiry = function(value) { + return jspb.Message.setProto3StringIntField(this, 4, value); +}; + + + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.looprpc.AssetRfqInfo.prototype.toObject = function(opt_includeInstance) { + return proto.looprpc.AssetRfqInfo.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.looprpc.AssetRfqInfo} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.looprpc.AssetRfqInfo.toObject = function(includeInstance, msg) { + var f, obj = { + prepayRfqId: msg.getPrepayRfqId_asB64(), + maxPrepayAssetAmt: jspb.Message.getFieldWithDefault(msg, 2, "0"), + prepayAssetRate: (f = msg.getPrepayAssetRate()) && proto.looprpc.FixedPoint.toObject(includeInstance, f), + swapRfqId: msg.getSwapRfqId_asB64(), + maxSwapAssetAmt: jspb.Message.getFieldWithDefault(msg, 4, "0"), + swapAssetRate: (f = msg.getSwapAssetRate()) && proto.looprpc.FixedPoint.toObject(includeInstance, f), + assetName: jspb.Message.getFieldWithDefault(msg, 5, "") + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.looprpc.AssetRfqInfo} + */ +proto.looprpc.AssetRfqInfo.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.looprpc.AssetRfqInfo; + return proto.looprpc.AssetRfqInfo.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.looprpc.AssetRfqInfo} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.looprpc.AssetRfqInfo} + */ +proto.looprpc.AssetRfqInfo.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {!Uint8Array} */ (reader.readBytes()); + msg.setPrepayRfqId(value); + break; + case 2: + var value = /** @type {string} */ (reader.readUint64String()); + msg.setMaxPrepayAssetAmt(value); + break; + case 6: + var value = new proto.looprpc.FixedPoint; + reader.readMessage(value,proto.looprpc.FixedPoint.deserializeBinaryFromReader); + msg.setPrepayAssetRate(value); + break; + case 3: + var value = /** @type {!Uint8Array} */ (reader.readBytes()); + msg.setSwapRfqId(value); + break; + case 4: + var value = /** @type {string} */ (reader.readUint64String()); + msg.setMaxSwapAssetAmt(value); + break; + case 7: + var value = new proto.looprpc.FixedPoint; + reader.readMessage(value,proto.looprpc.FixedPoint.deserializeBinaryFromReader); + msg.setSwapAssetRate(value); + break; + case 5: + var value = /** @type {string} */ (reader.readString()); + msg.setAssetName(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.looprpc.AssetRfqInfo.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.looprpc.AssetRfqInfo.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.looprpc.AssetRfqInfo} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.looprpc.AssetRfqInfo.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getPrepayRfqId_asU8(); + if (f.length > 0) { + writer.writeBytes( + 1, + f + ); + } + f = message.getMaxPrepayAssetAmt(); + if (parseInt(f, 10) !== 0) { + writer.writeUint64String( + 2, + f + ); + } + f = message.getPrepayAssetRate(); + if (f != null) { + writer.writeMessage( + 6, + f, + proto.looprpc.FixedPoint.serializeBinaryToWriter + ); + } + f = message.getSwapRfqId_asU8(); + if (f.length > 0) { + writer.writeBytes( + 3, + f + ); + } + f = message.getMaxSwapAssetAmt(); + if (parseInt(f, 10) !== 0) { + writer.writeUint64String( + 4, + f + ); + } + f = message.getSwapAssetRate(); + if (f != null) { + writer.writeMessage( + 7, + f, + proto.looprpc.FixedPoint.serializeBinaryToWriter + ); + } + f = message.getAssetName(); + if (f.length > 0) { + writer.writeString( + 5, + f + ); + } +}; + + +/** + * optional bytes prepay_rfq_id = 1; + * @return {!(string|Uint8Array)} + */ +proto.looprpc.AssetRfqInfo.prototype.getPrepayRfqId = function() { + return /** @type {!(string|Uint8Array)} */ (jspb.Message.getFieldWithDefault(this, 1, "")); +}; + + +/** + * optional bytes prepay_rfq_id = 1; + * This is a type-conversion wrapper around `getPrepayRfqId()` + * @return {string} + */ +proto.looprpc.AssetRfqInfo.prototype.getPrepayRfqId_asB64 = function() { + return /** @type {string} */ (jspb.Message.bytesAsB64( + this.getPrepayRfqId())); +}; + + +/** + * optional bytes prepay_rfq_id = 1; + * Note that Uint8Array is not supported on all browsers. + * @see http://caniuse.com/Uint8Array + * This is a type-conversion wrapper around `getPrepayRfqId()` + * @return {!Uint8Array} + */ +proto.looprpc.AssetRfqInfo.prototype.getPrepayRfqId_asU8 = function() { + return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8( + this.getPrepayRfqId())); +}; + + +/** + * @param {!(string|Uint8Array)} value + * @return {!proto.looprpc.AssetRfqInfo} returns this + */ +proto.looprpc.AssetRfqInfo.prototype.setPrepayRfqId = function(value) { + return jspb.Message.setProto3BytesField(this, 1, value); +}; + + +/** + * optional uint64 max_prepay_asset_amt = 2; + * @return {string} + */ +proto.looprpc.AssetRfqInfo.prototype.getMaxPrepayAssetAmt = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "0")); +}; + + +/** + * @param {string} value + * @return {!proto.looprpc.AssetRfqInfo} returns this + */ +proto.looprpc.AssetRfqInfo.prototype.setMaxPrepayAssetAmt = function(value) { + return jspb.Message.setProto3StringIntField(this, 2, value); +}; + + +/** + * optional FixedPoint prepay_asset_rate = 6; + * @return {?proto.looprpc.FixedPoint} + */ +proto.looprpc.AssetRfqInfo.prototype.getPrepayAssetRate = function() { + return /** @type{?proto.looprpc.FixedPoint} */ ( + jspb.Message.getWrapperField(this, proto.looprpc.FixedPoint, 6)); +}; + + +/** + * @param {?proto.looprpc.FixedPoint|undefined} value + * @return {!proto.looprpc.AssetRfqInfo} returns this +*/ +proto.looprpc.AssetRfqInfo.prototype.setPrepayAssetRate = function(value) { + return jspb.Message.setWrapperField(this, 6, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.looprpc.AssetRfqInfo} returns this + */ +proto.looprpc.AssetRfqInfo.prototype.clearPrepayAssetRate = function() { + return this.setPrepayAssetRate(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.looprpc.AssetRfqInfo.prototype.hasPrepayAssetRate = function() { + return jspb.Message.getField(this, 6) != null; +}; + + +/** + * optional bytes swap_rfq_id = 3; + * @return {!(string|Uint8Array)} + */ +proto.looprpc.AssetRfqInfo.prototype.getSwapRfqId = function() { + return /** @type {!(string|Uint8Array)} */ (jspb.Message.getFieldWithDefault(this, 3, "")); +}; + + +/** + * optional bytes swap_rfq_id = 3; + * This is a type-conversion wrapper around `getSwapRfqId()` + * @return {string} + */ +proto.looprpc.AssetRfqInfo.prototype.getSwapRfqId_asB64 = function() { + return /** @type {string} */ (jspb.Message.bytesAsB64( + this.getSwapRfqId())); +}; + + +/** + * optional bytes swap_rfq_id = 3; + * Note that Uint8Array is not supported on all browsers. + * @see http://caniuse.com/Uint8Array + * This is a type-conversion wrapper around `getSwapRfqId()` + * @return {!Uint8Array} + */ +proto.looprpc.AssetRfqInfo.prototype.getSwapRfqId_asU8 = function() { + return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8( + this.getSwapRfqId())); +}; + + +/** + * @param {!(string|Uint8Array)} value + * @return {!proto.looprpc.AssetRfqInfo} returns this + */ +proto.looprpc.AssetRfqInfo.prototype.setSwapRfqId = function(value) { + return jspb.Message.setProto3BytesField(this, 3, value); +}; + + +/** + * optional uint64 max_swap_asset_amt = 4; + * @return {string} + */ +proto.looprpc.AssetRfqInfo.prototype.getMaxSwapAssetAmt = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 4, "0")); +}; + + +/** + * @param {string} value + * @return {!proto.looprpc.AssetRfqInfo} returns this + */ +proto.looprpc.AssetRfqInfo.prototype.setMaxSwapAssetAmt = function(value) { + return jspb.Message.setProto3StringIntField(this, 4, value); +}; + + +/** + * optional FixedPoint swap_asset_rate = 7; + * @return {?proto.looprpc.FixedPoint} + */ +proto.looprpc.AssetRfqInfo.prototype.getSwapAssetRate = function() { + return /** @type{?proto.looprpc.FixedPoint} */ ( + jspb.Message.getWrapperField(this, proto.looprpc.FixedPoint, 7)); +}; + + +/** + * @param {?proto.looprpc.FixedPoint|undefined} value + * @return {!proto.looprpc.AssetRfqInfo} returns this +*/ +proto.looprpc.AssetRfqInfo.prototype.setSwapAssetRate = function(value) { + return jspb.Message.setWrapperField(this, 7, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.looprpc.AssetRfqInfo} returns this + */ +proto.looprpc.AssetRfqInfo.prototype.clearSwapAssetRate = function() { + return this.setSwapAssetRate(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.looprpc.AssetRfqInfo.prototype.hasSwapAssetRate = function() { + return jspb.Message.getField(this, 7) != null; +}; + + +/** + * optional string asset_name = 5; + * @return {string} + */ +proto.looprpc.AssetRfqInfo.prototype.getAssetName = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 5, "")); +}; + + +/** + * @param {string} value + * @return {!proto.looprpc.AssetRfqInfo} returns this + */ +proto.looprpc.AssetRfqInfo.prototype.setAssetName = function(value) { + return jspb.Message.setProto3StringField(this, 5, value); +}; + + + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.looprpc.FixedPoint.prototype.toObject = function(opt_includeInstance) { + return proto.looprpc.FixedPoint.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.looprpc.FixedPoint} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.looprpc.FixedPoint.toObject = function(includeInstance, msg) { + var f, obj = { + coefficient: jspb.Message.getFieldWithDefault(msg, 1, ""), + scale: jspb.Message.getFieldWithDefault(msg, 2, 0) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.looprpc.FixedPoint} + */ +proto.looprpc.FixedPoint.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.looprpc.FixedPoint; + return proto.looprpc.FixedPoint.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.looprpc.FixedPoint} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.looprpc.FixedPoint} + */ +proto.looprpc.FixedPoint.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {string} */ (reader.readString()); + msg.setCoefficient(value); + break; + case 2: + var value = /** @type {number} */ (reader.readUint32()); + msg.setScale(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.looprpc.FixedPoint.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.looprpc.FixedPoint.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.looprpc.FixedPoint} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.looprpc.FixedPoint.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getCoefficient(); + if (f.length > 0) { + writer.writeString( + 1, + f + ); + } + f = message.getScale(); + if (f !== 0) { + writer.writeUint32( + 2, + f + ); + } +}; + + +/** + * optional string coefficient = 1; + * @return {string} + */ +proto.looprpc.FixedPoint.prototype.getCoefficient = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); +}; + + +/** + * @param {string} value + * @return {!proto.looprpc.FixedPoint} returns this + */ +proto.looprpc.FixedPoint.prototype.setCoefficient = function(value) { + return jspb.Message.setProto3StringField(this, 1, value); +}; + + +/** + * optional uint32 scale = 2; + * @return {number} + */ +proto.looprpc.FixedPoint.prototype.getScale = function() { + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 2, 0)); +}; + + +/** + * @param {number} value + * @return {!proto.looprpc.FixedPoint} returns this + */ +proto.looprpc.FixedPoint.prototype.setScale = function(value) { + return jspb.Message.setProto3IntField(this, 2, value); +}; + + + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.looprpc.AssetLoopOutInfo.prototype.toObject = function(opt_includeInstance) { + return proto.looprpc.AssetLoopOutInfo.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.looprpc.AssetLoopOutInfo} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.looprpc.AssetLoopOutInfo.toObject = function(includeInstance, msg) { + var f, obj = { + assetId: jspb.Message.getFieldWithDefault(msg, 1, ""), + assetName: jspb.Message.getFieldWithDefault(msg, 2, ""), + assetCostOffchain: jspb.Message.getFieldWithDefault(msg, 3, "0") + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.looprpc.AssetLoopOutInfo} + */ +proto.looprpc.AssetLoopOutInfo.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.looprpc.AssetLoopOutInfo; + return proto.looprpc.AssetLoopOutInfo.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.looprpc.AssetLoopOutInfo} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.looprpc.AssetLoopOutInfo} + */ +proto.looprpc.AssetLoopOutInfo.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {string} */ (reader.readString()); + msg.setAssetId(value); + break; + case 2: + var value = /** @type {string} */ (reader.readString()); + msg.setAssetName(value); + break; + case 3: + var value = /** @type {string} */ (reader.readUint64String()); + msg.setAssetCostOffchain(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.looprpc.AssetLoopOutInfo.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.looprpc.AssetLoopOutInfo.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.looprpc.AssetLoopOutInfo} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.looprpc.AssetLoopOutInfo.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getAssetId(); + if (f.length > 0) { + writer.writeString( + 1, + f + ); + } + f = message.getAssetName(); + if (f.length > 0) { + writer.writeString( + 2, + f + ); + } + f = message.getAssetCostOffchain(); + if (parseInt(f, 10) !== 0) { + writer.writeUint64String( + 3, + f + ); + } +}; + + +/** + * optional string asset_id = 1; + * @return {string} + */ +proto.looprpc.AssetLoopOutInfo.prototype.getAssetId = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); +}; + + +/** + * @param {string} value + * @return {!proto.looprpc.AssetLoopOutInfo} returns this + */ +proto.looprpc.AssetLoopOutInfo.prototype.setAssetId = function(value) { + return jspb.Message.setProto3StringField(this, 1, value); +}; + + +/** + * optional string asset_name = 2; + * @return {string} + */ +proto.looprpc.AssetLoopOutInfo.prototype.getAssetName = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); +}; + + +/** + * @param {string} value + * @return {!proto.looprpc.AssetLoopOutInfo} returns this + */ +proto.looprpc.AssetLoopOutInfo.prototype.setAssetName = function(value) { + return jspb.Message.setProto3StringField(this, 2, value); +}; + + +/** + * optional uint64 asset_cost_offchain = 3; + * @return {string} + */ +proto.looprpc.AssetLoopOutInfo.prototype.getAssetCostOffchain = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, "0")); +}; + + +/** + * @param {string} value + * @return {!proto.looprpc.AssetLoopOutInfo} returns this + */ +proto.looprpc.AssetLoopOutInfo.prototype.setAssetCostOffchain = function(value) { + return jspb.Message.setProto3StringIntField(this, 3, value); +}; + + /** * @enum {number} */ diff --git a/app/src/util/tests/sampleData.ts b/app/src/util/tests/sampleData.ts index a1b3505c7..4521d35b9 100644 --- a/app/src/util/tests/sampleData.ts +++ b/app/src/util/tests/sampleData.ts @@ -258,6 +258,7 @@ export const lndChannelEvent: Required = { resolutionsList: [], aliasScidsList: [], zeroConfConfirmedScid: '', + customChannelData: '', }, activeChannel: { fundingTxidBytes: txIdBytes, @@ -360,6 +361,7 @@ export const loopListSwaps: LOOP.ListSwapsResponse.AsObject = { outgoingChanSetList: ['123456789'], htlcAddressP2tr: '', })), + nextStartTime: '', }; export const loopOutTerms: LOOP.OutTermsResponse.AsObject = { diff --git a/docs/release-notes/release-notes-0.14.2.md b/docs/release-notes/release-notes-0.14.2.md index 6e91c8932..e0cc00577 100644 --- a/docs/release-notes/release-notes-0.14.2.md +++ b/docs/release-notes/release-notes-0.14.2.md @@ -55,14 +55,23 @@ ### LND +* Updated [`lnd` to + `v0.19.0-beta.rc2`](https://github.com/lightninglabs/lightning-terminal/pull/987). + ### Loop +* Updated [Loop to + `v0.30.0-beta`](https://github.com/lightninglabs/lightning-terminal/pull/987). + ### Pool ### Faraday ### Taproot Assets +* Updated [`tapd` to + `v0.5.2`](https://github.com/lightninglabs/lightning-terminal/pull/987). + # Contributors (Alphabetical Order) * Elle Mouton diff --git a/go.mod b/go.mod index 290263012..19987e8a7 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/btcsuite/btcd/btcutil v1.1.5 github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 github.com/btcsuite/btclog/v2 v2.0.1-0.20250110154127-3ae4bf1cb318 - github.com/btcsuite/btcwallet/walletdb v1.4.4 + github.com/btcsuite/btcwallet/walletdb v1.5.1 github.com/davecgh/go-spew v1.1.1 github.com/go-errors/errors v1.0.1 github.com/golang-migrate/migrate/v4 v4.17.0 @@ -21,20 +21,20 @@ require ( github.com/lightninglabs/lightning-node-connect v0.3.3-alpha.0.20250306111457-cad4234830cc github.com/lightninglabs/lightning-terminal/autopilotserverrpc v0.0.2 github.com/lightninglabs/lightning-terminal/litrpc v1.0.1 - github.com/lightninglabs/lndclient v0.19.0-3 - github.com/lightninglabs/loop v0.29.0-beta.rc2.0.20250306160707-1091a628755c - github.com/lightninglabs/loop/looprpc v1.0.4-0.20250306160707-1091a628755c - github.com/lightninglabs/loop/swapserverrpc v1.0.13-0.20250306160707-1091a628755c + github.com/lightninglabs/lndclient v0.19.0-4 + github.com/lightninglabs/loop v0.31.0-beta.0.20250425065236-7e81916829d9 + github.com/lightninglabs/loop/looprpc v1.0.6 + github.com/lightninglabs/loop/swapserverrpc v1.0.13 github.com/lightninglabs/pool v0.6.5-beta.0.20250305125211-4e860ec4e77f github.com/lightninglabs/pool/auctioneerrpc v1.1.3-0.20250305125211-4e860ec4e77f github.com/lightninglabs/pool/poolrpc v1.0.1-0.20250305125211-4e860ec4e77f - github.com/lightninglabs/taproot-assets v0.5.2-0.20250416114205-2da076df4b4e - github.com/lightningnetwork/lnd v0.19.0-beta.rc1.0.20250327183348-eb822a5e117f + github.com/lightninglabs/taproot-assets v0.5.2-0.20250424162728-b6000498210d + github.com/lightningnetwork/lnd v0.19.0-beta.rc3 github.com/lightningnetwork/lnd/cert v1.2.2 github.com/lightningnetwork/lnd/clock v1.1.1 github.com/lightningnetwork/lnd/fn v1.2.3 github.com/lightningnetwork/lnd/fn/v2 v2.0.8 - github.com/lightningnetwork/lnd/kvdb v1.4.13 + github.com/lightningnetwork/lnd/kvdb v1.4.16 github.com/lightningnetwork/lnd/tlv v1.3.0 github.com/lightningnetwork/lnd/tor v1.1.6 github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f @@ -57,7 +57,7 @@ require ( require ( dario.cat/mergo v1.0.1 // indirect github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect - github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect github.com/NebulousLabs/fastrand v0.0.0-20181203155948-6fb6489aac4e // indirect github.com/NebulousLabs/go-upnp v0.0.0-20180202185039-29b680b06c82 // indirect github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect @@ -68,11 +68,11 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/btcsuite/btcd/btcutil/psbt v1.1.10 // indirect github.com/btcsuite/btclog v0.0.0-20241003133417-09c4e92e319c // indirect - github.com/btcsuite/btcwallet v0.16.12 // indirect + github.com/btcsuite/btcwallet v0.16.13 // indirect github.com/btcsuite/btcwallet/wallet/txauthor v1.3.5 // indirect github.com/btcsuite/btcwallet/wallet/txrules v1.2.2 // indirect github.com/btcsuite/btcwallet/wallet/txsizes v1.2.5 // indirect - github.com/btcsuite/btcwallet/wtxmgr v1.5.4 // indirect + github.com/btcsuite/btcwallet/wtxmgr v1.5.6 // indirect github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd // indirect github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 // indirect github.com/btcsuite/winsvc v1.0.0 // indirect @@ -80,7 +80,6 @@ require ( github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/containerd/continuity v0.3.0 // indirect - github.com/coreos/bbolt v1.3.3 // indirect github.com/coreos/go-semver v0.3.0 // indirect github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect @@ -91,7 +90,7 @@ require ( github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect github.com/docker/cli v28.0.1+incompatible // indirect github.com/docker/docker v28.0.1+incompatible // indirect - github.com/docker/go-connections v0.4.0 // indirect + github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/fergusstrange/embedded-postgres v1.25.0 // indirect @@ -144,7 +143,7 @@ require ( github.com/lightningnetwork/lightning-onion v1.2.1-0.20240712235311-98bd56499dfb // indirect github.com/lightningnetwork/lnd/healthcheck v1.2.6 // indirect github.com/lightningnetwork/lnd/queue v1.1.1 // indirect - github.com/lightningnetwork/lnd/sqldb v1.0.7 // indirect + github.com/lightningnetwork/lnd/sqldb v1.0.9 // indirect github.com/lightningnetwork/lnd/ticker v1.1.1 // indirect github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796 // indirect github.com/mattn/go-isatty v0.0.20 // indirect @@ -159,7 +158,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/ncruces/go-strftime v0.1.9 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.0.2 // indirect + github.com/opencontainers/image-spec v1.1.0 // indirect github.com/opencontainers/runc v1.2.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect @@ -194,25 +193,25 @@ require ( go.etcd.io/etcd/raft/v3 v3.5.12 // indirect go.etcd.io/etcd/server/v3 v3.5.12 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect go.opentelemetry.io/otel v1.35.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.20.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.20.0 // indirect go.opentelemetry.io/otel/metric v1.35.0 // indirect go.opentelemetry.io/otel/sdk v1.35.0 // indirect go.opentelemetry.io/otel/trace v1.35.0 // indirect - go.opentelemetry.io/proto/otlp v1.0.0 // indirect + go.opentelemetry.io/proto/otlp v1.3.1 // indirect go.uber.org/atomic v1.10.0 // indirect go.uber.org/mock v0.4.0 // indirect go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.23.0 // indirect - golang.org/x/mod v0.17.0 // indirect + golang.org/x/mod v0.21.0 // indirect golang.org/x/sys v0.31.0 // indirect golang.org/x/term v0.30.0 // indirect golang.org/x/text v0.23.0 // indirect - golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect - google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b // indirect + golang.org/x/time v0.5.0 // indirect + golang.org/x/tools v0.24.0 // indirect + google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect gopkg.in/errgo.v1 v1.0.1 // indirect @@ -237,4 +236,10 @@ replace ( // taproot-assets dependency to function properly. replace google.golang.org/protobuf => github.com/lightninglabs/protobuf-go-hex-display v1.34.2-hex-display +// We are using a fork of the migration library in tapd with custom +// functionality that did not yet make it into the upstream repository. Because +// it is a replace in the tapd repository, it doesn't get propagated here +// automatically, so we need to add it manually. +replace github.com/golang-migrate/migrate/v4 => github.com/lightninglabs/migrate/v4 v4.18.2-9023d66a-fork-pr-2 + go 1.23.6 diff --git a/go.sum b/go.sum index 22dce9014..3443d3720 100644 --- a/go.sum +++ b/go.sum @@ -36,7 +36,6 @@ cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRY cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= -cloud.google.com/go v0.110.10 h1:LXy9GEO+timppncPIAZoOj3l58LIU9k+kn48AN7IO3Y= cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= @@ -173,13 +172,10 @@ cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63 cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU= cloud.google.com/go/compute v1.19.1/go.mod h1:6ylj3a05WF8leseCdIf77NK0g1ey+nj5IKd5/kvShxE= -cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk= cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= -cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= @@ -611,8 +607,8 @@ github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0 github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g= github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= -github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= -github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/NebulousLabs/fastrand v0.0.0-20181203155948-6fb6489aac4e h1:n+DcnTNkQnHlwpsrHoQtkrJIO7CBx029fw6oR4vIob4= github.com/NebulousLabs/fastrand v0.0.0-20181203155948-6fb6489aac4e/go.mod h1:Bdzq+51GR4/0DIhaICZEOm+OHvXGwwB2trKZ8B4Y6eQ= github.com/NebulousLabs/go-upnp v0.0.0-20180202185039-29b680b06c82 h1:MG93+PZYs9PyEsj/n5/haQu2gK0h4tUtSy9ejtMwWa0= @@ -674,18 +670,18 @@ github.com/btcsuite/btclog v0.0.0-20241003133417-09c4e92e319c/go.mod h1:w7xnGOhw github.com/btcsuite/btclog/v2 v2.0.1-0.20250110154127-3ae4bf1cb318 h1:oCjIcinPt7XQ644MP/22JcjYEC84qRc3bRBH0d7Hhd4= github.com/btcsuite/btclog/v2 v2.0.1-0.20250110154127-3ae4bf1cb318/go.mod h1:XItGUfVOxotJL8kkuk2Hj3EVow5KCugXl3wWfQ6K0AE= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= -github.com/btcsuite/btcwallet v0.16.12 h1:9SREKY892i1xTGlGLcu6x7O+WSQFn6+uQrSuskAOqh0= -github.com/btcsuite/btcwallet v0.16.12/go.mod h1:jBn+ThFrx/QqW0nXiGvXtJytju4aVoW7C0hY4s/+9vo= +github.com/btcsuite/btcwallet v0.16.13 h1:JGu+wrihQ0I00ODb3w92JtBPbrHxZhbcvU01O+e+lKw= +github.com/btcsuite/btcwallet v0.16.13/go.mod h1:H6dfoZcWPonM2wbVsR2ZBY0PKNZKdQyLAmnX8vL9JFA= github.com/btcsuite/btcwallet/wallet/txauthor v1.3.5 h1:Rr0njWI3r341nhSPesKQ2JF+ugDSzdPoeckS75SeDZk= github.com/btcsuite/btcwallet/wallet/txauthor v1.3.5/go.mod h1:+tXJ3Ym0nlQc/iHSwW1qzjmPs3ev+UVWMbGgfV1OZqU= github.com/btcsuite/btcwallet/wallet/txrules v1.2.2 h1:YEO+Lx1ZJJAtdRrjuhXjWrYsmAk26wLTlNzxt2q0lhk= github.com/btcsuite/btcwallet/wallet/txrules v1.2.2/go.mod h1:4v+grppsDpVn91SJv+mZT7B8hEV4nSmpREM4I8Uohws= github.com/btcsuite/btcwallet/wallet/txsizes v1.2.5 h1:93o5Xz9dYepBP4RMFUc9RGIFXwqP2volSWRkYJFrNtI= github.com/btcsuite/btcwallet/wallet/txsizes v1.2.5/go.mod h1:lQ+e9HxZ85QP7r3kdxItkiMSloSLg1PEGis5o5CXUQw= -github.com/btcsuite/btcwallet/walletdb v1.4.4 h1:BDel6iT/ltYSIYKs0YbjwnEDi7xR3yzABIsQxN2F1L8= -github.com/btcsuite/btcwallet/walletdb v1.4.4/go.mod h1:jk/hvpLFINF0C1kfTn0bfx2GbnFT+Nvnj6eblZALfjs= -github.com/btcsuite/btcwallet/wtxmgr v1.5.4 h1:hJjHy1h/dJwSfD9uDsCwcH21D1iOrus6OrI5gR9E/O0= -github.com/btcsuite/btcwallet/wtxmgr v1.5.4/go.mod h1:lAv0b1Vj9Ig5U8QFm0yiJ9WqPl8yGO/6l7JxdHY1PKE= +github.com/btcsuite/btcwallet/walletdb v1.5.1 h1:HgMhDNCrtEFPC+8q0ei5DQ5U9Tl4RCspA22DEKXlopI= +github.com/btcsuite/btcwallet/walletdb v1.5.1/go.mod h1:jk/hvpLFINF0C1kfTn0bfx2GbnFT+Nvnj6eblZALfjs= +github.com/btcsuite/btcwallet/wtxmgr v1.5.6 h1:Zwvr/rrJYdOLqdBCSr4eICEstnEA+NBUvjIWLkrXaYI= +github.com/btcsuite/btcwallet/wtxmgr v1.5.6/go.mod h1:lzVbDkk/jRao2ib5kge46aLZW1yFc8RFNycdYpnsmZA= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= github.com/btcsuite/golangcrypto v0.0.0-20150304025918-53f62d9b43e8/go.mod h1:tYvUd8KLhm/oXvUeSEs2VlLghFjQt9+ZaF9ghH0JNjc= @@ -727,16 +723,12 @@ github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b h1:ga8SEFjZ60pxLcmhnThWgvH2wg8376yUJmPhEH4H3kw= -github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/datadriven v1.0.2 h1:H9MtNqVoVhvd9nCBwOyDjUEdZCREqbIdCJD93PBm/jA= github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= -github.com/coreos/bbolt v1.3.3 h1:n6AiVyVRKQFNb6mJlwESEvvLoDyiTzXX7ORAUlkeBdY= -github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= @@ -766,16 +758,16 @@ github.com/decred/dcrd/lru v1.1.2 h1:KdCzlkxppuoIDGEvCGah1fZRicrDH36IipvlB1ROkFY github.com/decred/dcrd/lru v1.1.2/go.mod h1:gEdCVgXs1/YoBvFWt7Scgknbhwik3FgVSzlnCcXL2N8= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE= -github.com/dhui/dktest v0.4.0 h1:z05UmuXZHO/bgj/ds2bGMBu8FI4WA+Ag/m3ghL+om7M= -github.com/dhui/dktest v0.4.0/go.mod h1:v/Dbz1LgCBOi2Uki2nUqLBGa83hWBGFMu5MrgMDCc78= +github.com/dhui/dktest v0.4.5 h1:uUfYBIVREmj/Rw6MvgmqNAYzTiKOHJak+enB5Di73MM= +github.com/dhui/dktest v0.4.5/go.mod h1:tmcyeHDKagvlDrz7gDKq4UAJOLIfVZYkfD5OnHDwcCo= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/docker/cli v28.0.1+incompatible h1:g0h5NQNda3/CxIsaZfH4Tyf6vpxFth7PYl3hgCPOKzs= github.com/docker/cli v28.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/docker v28.0.1+incompatible h1:FCHjSRdXhNRFjlHMTv4jUNlIBbTeRjrWfeFuJp7jpo0= github.com/docker/docker v28.0.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= -github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= +github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= @@ -797,8 +789,6 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= github.com/envoyproxy/protoc-gen-validate v0.10.1/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= -github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= -github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fergusstrange/embedded-postgres v1.25.0 h1:sa+k2Ycrtz40eCRPOzI7Ry7TtkWXXJ+YRsxpKMDhxK0= @@ -877,8 +867,6 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang-migrate/migrate/v4 v4.17.0 h1:rd40H3QXU0AA4IoLllFcEAEo9dYKRHYND2gB4p7xcaU= -github.com/golang-migrate/migrate/v4 v4.17.0/go.mod h1:+Cp2mtLP4/aXDTKb9wmXYitdrNx2HGs45rbWAo6OsKM= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v0.0.0-20210429001901-424d2337a529/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -1161,14 +1149,16 @@ github.com/lightninglabs/lightning-node-connect v0.3.3-alpha.0.20250306111457-ca github.com/lightninglabs/lightning-node-connect v0.3.3-alpha.0.20250306111457-cad4234830cc/go.mod h1:yrfNoMrGcWljHoQ31+dCSc0R7mBdYqISQeZABlrdkz4= github.com/lightninglabs/lightning-node-connect/hashmailrpc v1.0.2 h1:Er1miPZD2XZwcfE4xoS5AILqP1mj7kqnhbBSxW9BDxY= github.com/lightninglabs/lightning-node-connect/hashmailrpc v1.0.2/go.mod h1:antQGRDRJiuyQF6l+k6NECCSImgCpwaZapATth2Chv4= -github.com/lightninglabs/lndclient v0.19.0-3 h1:PGGlDaz8x1dXGowDfAWhbuDqXTKNaJyb7SOTrRdG1es= -github.com/lightninglabs/lndclient v0.19.0-3/go.mod h1:5YMrFx00NvcmUHGZRxT4Qw/gOfR5x50/ReJmJ6w0yVk= -github.com/lightninglabs/loop v0.29.0-beta.rc2.0.20250306160707-1091a628755c h1:Ox7SfusBRizc7tOKy9HKXodR7rcvpko08EH9aP/+euQ= -github.com/lightninglabs/loop v0.29.0-beta.rc2.0.20250306160707-1091a628755c/go.mod h1:IzzOw/v4VwKmotJrmPyM8P+FPZ/XBbxa4u2JuDYrtAU= -github.com/lightninglabs/loop/looprpc v1.0.4-0.20250306160707-1091a628755c h1:ueEVZjeUKI3CoTJAdpDbXKHTSd9OfY8OPqTDBjeHhfs= -github.com/lightninglabs/loop/looprpc v1.0.4-0.20250306160707-1091a628755c/go.mod h1:gO5c42iHaY6O7kXmHMqEK0ZZkRXrVDisGP22LkHMDmA= -github.com/lightninglabs/loop/swapserverrpc v1.0.13-0.20250306160707-1091a628755c h1:41URVu1xE88R3kUE1VZGJS50RDWX7wBwVmICBb/0gnw= -github.com/lightninglabs/loop/swapserverrpc v1.0.13-0.20250306160707-1091a628755c/go.mod h1:Ml3gMwe/iTRLvu1QGGZzXcr0DYSa9sJGwKPktLaWtwE= +github.com/lightninglabs/lndclient v0.19.0-4 h1:U+koisg716/i51kf5ENI5+9a1joXcPXeJYl3q0s4/co= +github.com/lightninglabs/lndclient v0.19.0-4/go.mod h1:LP3FM3JGBdvOX8Lum9x1r7q54oiftoqaq4EYhtpp/fk= +github.com/lightninglabs/loop v0.31.0-beta.0.20250425065236-7e81916829d9 h1:wVOSaMFH/1rrX8vYd7MFkv4TjIqPZyYXYWhV5WwVdnA= +github.com/lightninglabs/loop v0.31.0-beta.0.20250425065236-7e81916829d9/go.mod h1:+t9d/gnfPcdHFaOPEdrtJx1Deb+drhlD5EYQ5kpH5hk= +github.com/lightninglabs/loop/looprpc v1.0.6 h1:lvxGIOB2jL67vL9qY5FH1xIVyMZJvqLy1gS0J9dQXwA= +github.com/lightninglabs/loop/looprpc v1.0.6/go.mod h1:VJSzz1Ug/cVCNjE+1jYZ/51DuLnCjbJdF4BtrxTTM8c= +github.com/lightninglabs/loop/swapserverrpc v1.0.13 h1:Qf4L8QBJKzhKRcC8dpvfrrBEXJMF3+XbpomAHEJsRDY= +github.com/lightninglabs/loop/swapserverrpc v1.0.13/go.mod h1:Ml3gMwe/iTRLvu1QGGZzXcr0DYSa9sJGwKPktLaWtwE= +github.com/lightninglabs/migrate/v4 v4.18.2-9023d66a-fork-pr-2 h1:eFjp1dIB2BhhQp/THKrjLdlYuPugO9UU4kDqu91OX/Q= +github.com/lightninglabs/migrate/v4 v4.18.2-9023d66a-fork-pr-2/go.mod h1:99BKpIi6ruaaXRM1A77eqZ+FWPQ3cfRa+ZVy5bmWMaY= github.com/lightninglabs/neutrino v0.16.1 h1:5Kz4ToxncEVkpKC6fwUjXKtFKJhuxlG3sBB3MdJTJjs= github.com/lightninglabs/neutrino v0.16.1/go.mod h1:L+5UAccpUdyM7yDgmQySgixf7xmwBgJtOfs/IP26jCs= github.com/lightninglabs/neutrino/cache v1.1.2 h1:C9DY/DAPaPxbFC+xNNEI/z1SJY9GS3shmlu5hIQ798g= @@ -1181,12 +1171,12 @@ github.com/lightninglabs/pool/poolrpc v1.0.1-0.20250305125211-4e860ec4e77f h1:5p github.com/lightninglabs/pool/poolrpc v1.0.1-0.20250305125211-4e860ec4e77f/go.mod h1:lGs2hSVZ+GFpdv3btaIl9icG5/gz7BBRfvmD2iqqNl0= github.com/lightninglabs/protobuf-go-hex-display v1.34.2-hex-display h1:w7FM5LH9Z6CpKxl13mS48idsu6F+cEZf0lkyiV+Dq9g= github.com/lightninglabs/protobuf-go-hex-display v1.34.2-hex-display/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= -github.com/lightninglabs/taproot-assets v0.5.2-0.20250416114205-2da076df4b4e h1:37sk9Wmkh9QFjnqR8eHIhCi8x0uIQL0F2fpcQI25I9g= -github.com/lightninglabs/taproot-assets v0.5.2-0.20250416114205-2da076df4b4e/go.mod h1:e3SjXbbi4xKhOzq54c672Z/j9UTRq5DLJGx/URgVTJo= +github.com/lightninglabs/taproot-assets v0.5.2-0.20250424162728-b6000498210d h1:8WcOFToO9iY62c6ghbAaJfVP8qudzdrK89OXiOri9K4= +github.com/lightninglabs/taproot-assets v0.5.2-0.20250424162728-b6000498210d/go.mod h1:6kQm7VC4yWAwczJaxfOWlCOQ4TuzfCLUkGKBwVONN7k= github.com/lightningnetwork/lightning-onion v1.2.1-0.20240712235311-98bd56499dfb h1:yfM05S8DXKhuCBp5qSMZdtSwvJ+GFzl94KbXMNB1JDY= github.com/lightningnetwork/lightning-onion v1.2.1-0.20240712235311-98bd56499dfb/go.mod h1:c0kvRShutpj3l6B9WtTsNTBUtjSmjZXbJd9ZBRQOSKI= -github.com/lightningnetwork/lnd v0.19.0-beta.rc1.0.20250327183348-eb822a5e117f h1:+Bejv2Ij/ryUjLacBd5au0acMH0AYs0lhb7ki5rx9ms= -github.com/lightningnetwork/lnd v0.19.0-beta.rc1.0.20250327183348-eb822a5e117f/go.mod h1:BP+neeFpmeAA7o5hu3zp3FwOEl26idSyPV9zBOavp6E= +github.com/lightningnetwork/lnd v0.19.0-beta.rc3 h1:XWMlyZvBrp69AnQqrshLOOPZjOl4hFWR1RD4ceCXt9k= +github.com/lightningnetwork/lnd v0.19.0-beta.rc3/go.mod h1:bASjjAiZsoEtHFo0imi5m4z/8m9afdIpu+Wz7rUXink= github.com/lightningnetwork/lnd/cert v1.2.2 h1:71YK6hogeJtxSxw2teq3eGeuy4rHGKcFf0d0Uy4qBjI= github.com/lightningnetwork/lnd/cert v1.2.2/go.mod h1:jQmFn/Ez4zhDgq2hnYSw8r35bqGVxViXhX6Cd7HXM6U= github.com/lightningnetwork/lnd/clock v1.1.1 h1:OfR3/zcJd2RhH0RU+zX/77c0ZiOnIMsDIBjgjWdZgA0= @@ -1197,12 +1187,12 @@ github.com/lightningnetwork/lnd/fn/v2 v2.0.8 h1:r2SLz7gZYQPVc3IZhU82M66guz3Zk2oY github.com/lightningnetwork/lnd/fn/v2 v2.0.8/go.mod h1:TOzwrhjB/Azw1V7aa8t21ufcQmdsQOQMDtxVOQWNl8s= github.com/lightningnetwork/lnd/healthcheck v1.2.6 h1:1sWhqr93GdkWy4+6U7JxBfcyZIE78MhIHTJZfPx7qqI= github.com/lightningnetwork/lnd/healthcheck v1.2.6/go.mod h1:Mu02um4CWY/zdTOvFje7WJgJcHyX2zq/FG3MhOAiGaQ= -github.com/lightningnetwork/lnd/kvdb v1.4.13 h1:fe3sFBxsgcXl16G1zj6O/wZf0hbBHOxFe8pCgmnHZxM= -github.com/lightningnetwork/lnd/kvdb v1.4.13/go.mod h1:1y0Z81CGQu4SMpcnAie/oK4tzgEqFQqFdj6k3fz2s8s= +github.com/lightningnetwork/lnd/kvdb v1.4.16 h1:9BZgWdDfjmHRHLS97cz39bVuBAqMc4/p3HX1xtUdbDI= +github.com/lightningnetwork/lnd/kvdb v1.4.16/go.mod h1:HW+bvwkxNaopkz3oIgBV6NEnV4jCEZCACFUcNg4xSjM= github.com/lightningnetwork/lnd/queue v1.1.1 h1:99ovBlpM9B0FRCGYJo6RSFDlt8/vOkQQZznVb18iNMI= github.com/lightningnetwork/lnd/queue v1.1.1/go.mod h1:7A6nC1Qrm32FHuhx/mi1cieAiBZo5O6l8IBIoQxvkz4= -github.com/lightningnetwork/lnd/sqldb v1.0.7 h1:wQ4DdHY++uwxwth2CHL7s+duGqmMLaoIRBOQCa9HPTk= -github.com/lightningnetwork/lnd/sqldb v1.0.7/go.mod h1:OG09zL/PHPaBJefp4HsPz2YLUJ+zIQHbpgCtLnOx8I4= +github.com/lightningnetwork/lnd/sqldb v1.0.9 h1:7OHi+Hui823mB/U9NzCdlZTAGSVdDCbjp33+6d/Q+G0= +github.com/lightningnetwork/lnd/sqldb v1.0.9/go.mod h1:OG09zL/PHPaBJefp4HsPz2YLUJ+zIQHbpgCtLnOx8I4= github.com/lightningnetwork/lnd/ticker v1.1.1 h1:J/b6N2hibFtC7JLV77ULQp++QLtCwT6ijJlbdiZFbSM= github.com/lightningnetwork/lnd/ticker v1.1.1/go.mod h1:waPTRAAcwtu7Ji3+3k+u/xH5GHovTsCoSVpho0KDvdA= github.com/lightningnetwork/lnd/tlv v1.3.0 h1:exS/KCPEgpOgviIttfiXAPaUqw2rHQrnUOpP7HPBPiY= @@ -1277,8 +1267,8 @@ github.com/onsi/gomega v1.26.0 h1:03cDLK28U6hWvCAns6NeydX3zIm4SF3ci69ulidS32Q= github.com/onsi/gomega v1.26.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= -github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= +github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= github.com/opencontainers/runc v1.2.0 h1:qke7ZVCmJcKrJVY2iHJVC+0kql9uYdkusOPsQOOeBw4= github.com/opencontainers/runc v1.2.0/go.mod h1:/PXzF0h531HTMsYQnmxXkBD7YaGShm/2zcRB79dksUc= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -1445,14 +1435,14 @@ go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 h1:SpGay3w+nEwMpfVnbqOLH5gY52/foP8RE8UzTZ1pdSE= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ= go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.20.0 h1:DeFD0VgTZ+Cj6hxravYYZE2W4GlneVH81iAOPjZkzk8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.20.0/go.mod h1:GijYcYmNpX1KazD5JmWGsi4P7dDTTTnfv1UbGn84MnU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 h1:dIIDULZJpgdiHz5tXrTgKIMLkus6jEFa7x5SOKcyR7E= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0/go.mod h1:jlRVBe7+Z1wyxFSUs48L6OBQZ5JwH2Hg/Vbl+t9rAgI= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.20.0 h1:gvmNvqrPYovvyRmCSygkUDyL8lC5Tl845MLEwqpxhEU= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.20.0/go.mod h1:vNUq47TGFioo+ffTSnKNdob241vePmtNZnAODKapKd0= go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= @@ -1464,8 +1454,8 @@ go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= -go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= -go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= +go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= +go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -1569,8 +1559,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1674,8 +1664,6 @@ golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= -golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= -golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1831,8 +1819,9 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1903,8 +1892,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= +golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -2123,8 +2112,8 @@ google.golang.org/genproto v0.0.0-20230323212658-478b75c54725/go.mod h1:UUQDJDOl google.golang.org/genproto v0.0.0-20230330154414-c0448cd141ea/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= google.golang.org/genproto v0.0.0-20230331144136-dcfb400f0633/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= -google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b h1:+YaDE2r2OG8t/z5qmsh7Y+XXwCbvadxxZ0YY6mTdrVA= -google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:CgAqfJo+Xmu0GwA0411Ht3OU3OntXwsGmrmjI8ioGXI= +google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y= +google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s= google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 h1:wKguEg1hsxI2/L3hUYrpo1RVi48K+uTyzKqprwLXsb8= google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo= google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs= diff --git a/itest/assets_test.go b/itest/assets_test.go index 63d59335c..8ab67e598 100644 --- a/itest/assets_test.go +++ b/itest/assets_test.go @@ -17,6 +17,8 @@ import ( "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" "github.com/davecgh/go-spew/spew" + taprootassets "github.com/lightninglabs/taproot-assets" + "github.com/lightninglabs/taproot-assets/asset" tapfn "github.com/lightninglabs/taproot-assets/fn" "github.com/lightninglabs/taproot-assets/itest" "github.com/lightninglabs/taproot-assets/proof" @@ -36,6 +38,7 @@ import ( "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc/invoicesrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc" + "github.com/lightningnetwork/lnd/lnrpc/walletrpc" "github.com/lightningnetwork/lnd/lntest/rpc" "github.com/lightningnetwork/lnd/lntest/wait" "github.com/lightningnetwork/lnd/lntypes" @@ -258,14 +261,15 @@ func createTestAssetNetwork(t *harnessTest, net *NetworkHarness, charlieTap, // Make sure the channel shows the correct asset information. assertAssetChan( t.t, charlieTap.node, daveTap.node, charlieFundingAmount, - mintedAsset, + []*taprpc.Asset{mintedAsset}, ) assertAssetChan( - t.t, daveTap.node, yaraTap.node, daveFundingAmount, mintedAsset, + t.t, daveTap.node, yaraTap.node, daveFundingAmount, + []*taprpc.Asset{mintedAsset}, ) assertAssetChan( t.t, erinTap.node, fabiaTap.node, erinFundingAmount, - mintedAsset, + []*taprpc.Asset{mintedAsset}, ) chanPointCD := &lnrpc.ChannelPoint{ @@ -290,6 +294,281 @@ func createTestAssetNetwork(t *harnessTest, net *NetworkHarness, charlieTap, return chanPointCD, chanPointDY, chanPointEF } +// createTestAssetNetworkGroupKey sets up a test network with Charlie, Dave, +// Erin and Fabia and creates asset channels between Charlie->Dave and +// Erin-Fabia in a way that there are two equally sized asset pieces for each +// minted asset (currently limited to exactly two assets). The channels are then +// confirmed and balances asserted. +func createTestAssetNetworkGroupKey(ctx context.Context, t *harnessTest, + net *NetworkHarness, charlieTap, daveTap, erinTap, fabiaTap, + universeTap *tapClient, mintedAssets []*taprpc.Asset, + charlieFundingAmount, erinFundingAmount uint64, + pushSat int64) (*lnrpc.ChannelPoint, *lnrpc.ChannelPoint) { + + var groupKey []byte + for _, mintedAsset := range mintedAssets { + require.NotNil(t.t, mintedAsset.AssetGroup) + + if groupKey == nil { + groupKey = mintedAsset.AssetGroup.TweakedGroupKey + + continue + } + + require.Equal( + t.t, groupKey, mintedAsset.AssetGroup.TweakedGroupKey, + ) + } + + // We first do a transfer to Charlie by itself, so we get the correct + // asset pieces that we want for the channel funding. + sendAssetsAndAssert( + ctx, t, charlieTap, charlieTap, universeTap, mintedAssets[0], + charlieFundingAmount/2, 0, 1, 0, + ) + sendAssetsAndAssert( + ctx, t, charlieTap, charlieTap, universeTap, mintedAssets[1], + charlieFundingAmount/2, 1, 2, 0, + ) + + // We need to send some assets to Erin, so he can fund an asset channel + // with Fabia. + sendAssetsAndAssert( + ctx, t, erinTap, charlieTap, universeTap, mintedAssets[0], + erinFundingAmount/2, 2, 1, charlieFundingAmount/2, + ) + sendAssetsAndAssert( + ctx, t, erinTap, charlieTap, universeTap, mintedAssets[1], + erinFundingAmount/2, 3, 2, charlieFundingAmount/2, + ) + + // Then we burn everything but a single asset piece. We do this to make + // sure that the channel funding code will select the correct asset + // UTXOs during the channel funding. Otherwise, it's super hard to + // predict what exactly goes into the channel funding transaction. And + // this way it's also easier to assert overall balances. + assetID1 := mintedAssets[0].AssetGenesis.AssetId + assetID2 := mintedAssets[1].AssetGenesis.AssetId + burnAmount1 := mintedAssets[0].Amount - charlieFundingAmount/2 - + erinFundingAmount/2 - 1 + _, err := charlieTap.BurnAsset(ctx, &taprpc.BurnAssetRequest{ + Asset: &taprpc.BurnAssetRequest_AssetId{ + AssetId: assetID1, + }, + AmountToBurn: burnAmount1, + ConfirmationText: taprootassets.AssetBurnConfirmationText, + }) + require.NoError(t.t, err) + + mineBlocks(t, net, 1, 1) + + burnAmount2 := mintedAssets[1].Amount - charlieFundingAmount/2 - + erinFundingAmount/2 - 1 + _, err = charlieTap.BurnAsset(ctx, &taprpc.BurnAssetRequest{ + Asset: &taprpc.BurnAssetRequest_AssetId{ + AssetId: assetID2, + }, + AmountToBurn: burnAmount2, + ConfirmationText: taprootassets.AssetBurnConfirmationText, + }) + require.NoError(t.t, err) + + mineBlocks(t, net, 1, 1) + + t.Logf("Opening asset channels...") + + // The first channel we create has a push amount, so Charlie can receive + // payments immediately and not run into the channel reserve issue. + fundRespCD, err := charlieTap.FundChannel( + ctx, &tchrpc.FundChannelRequest{ + AssetAmount: charlieFundingAmount, + GroupKey: groupKey, + PeerPubkey: daveTap.node.PubKey[:], + FeeRateSatPerVbyte: 5, + PushSat: pushSat, + }, + ) + require.NoError(t.t, err) + t.Logf("Funded channel between Charlie and Dave: %v", fundRespCD) + + fundRespEF, err := erinTap.FundChannel( + ctx, &tchrpc.FundChannelRequest{ + AssetAmount: erinFundingAmount, + GroupKey: groupKey, + PeerPubkey: fabiaTap.node.PubKey[:], + FeeRateSatPerVbyte: 5, + PushSat: pushSat, + }, + ) + require.NoError(t.t, err) + t.Logf("Funded channel between Erin and Fabia: %v", fundRespEF) + + // Make sure the pending channel shows up in the list and has the + // custom records set as JSON. + assertPendingChannels( + t.t, charlieTap.node, mintedAssets[0], 1, + charlieFundingAmount/2, 0, + ) + assertPendingChannels( + t.t, charlieTap.node, mintedAssets[1], 1, + charlieFundingAmount/2, 0, + ) + assertPendingChannels( + t.t, erinTap.node, mintedAssets[0], 1, erinFundingAmount/2, 0, + ) + assertPendingChannels( + t.t, erinTap.node, mintedAssets[1], 1, erinFundingAmount/2, 0, + ) + + // Now that we've looked at the pending channels, let's actually confirm + // all three of them. + mineBlocks(t, net, 6, 2) + + var id1, id2 asset.ID + copy(id1[:], assetID1) + copy(id2[:], assetID2) + + fundingTree1, err := tapscript.NewChannelFundingScriptTreeUniqueID( + id1, + ) + require.NoError(t.t, err) + fundingScriptKey1 := fundingTree1.TaprootKey + fundingScriptTreeBytes1 := fundingScriptKey1.SerializeCompressed() + + fundingTree2, err := tapscript.NewChannelFundingScriptTreeUniqueID( + id2, + ) + require.NoError(t.t, err) + fundingScriptKey2 := fundingTree2.TaprootKey + fundingScriptTreeBytes2 := fundingScriptKey2.SerializeCompressed() + + // TODO(guggero): Those asset balances should be 1, 1, 0, 0 + // respectively, but because we now have unique script keys, we need + // https://github.com/lightninglabs/taproot-assets/pull/1198 first. + assertAssetBalance(t.t, charlieTap, assetID1, 25001) + assertAssetBalance(t.t, charlieTap, assetID2, 25001) + assertAssetBalance(t.t, erinTap, assetID1, 25000) + assertAssetBalance(t.t, erinTap, assetID2, 25000) + + // There should be two asset pieces for Charlie for both asset IDs, one + // in the channel and one with a single unit from the burn. + assertNumAssetOutputs(t.t, charlieTap, assetID1, 2) + assertNumAssetOutputs(t.t, charlieTap, assetID2, 2) + assertAssetExists( + t.t, charlieTap, assetID1, charlieFundingAmount/2, + fundingScriptKey1, false, true, true, + ) + assertAssetExists( + t.t, charlieTap, assetID1, 1, nil, true, false, false, + ) + assertAssetExists( + t.t, charlieTap, assetID2, charlieFundingAmount/2, + fundingScriptKey2, false, true, true, + ) + assertAssetExists( + t.t, charlieTap, assetID2, 1, nil, true, false, false, + ) + + // Erin should just have one output for each asset ID, the one in the + // channel. + assertNumAssetOutputs(t.t, erinTap, assetID1, 1) + assertNumAssetOutputs(t.t, erinTap, assetID2, 1) + assertAssetExists( + t.t, erinTap, assetID1, erinFundingAmount/2, fundingScriptKey1, + false, true, true, + ) + assertAssetExists( + t.t, erinTap, assetID2, erinFundingAmount/2, fundingScriptKey2, + false, true, true, + ) + + // Assert that the proofs for both channels has been uploaded to the + // designated Universe server. + assertUniverseProofExists( + t.t, universeTap, assetID1, groupKey, fundingScriptTreeBytes1, + fmt.Sprintf("%v:%v", fundRespCD.Txid, fundRespCD.OutputIndex), + ) + assertUniverseProofExists( + t.t, universeTap, assetID2, groupKey, fundingScriptTreeBytes2, + fmt.Sprintf("%v:%v", fundRespCD.Txid, fundRespCD.OutputIndex), + ) + assertUniverseProofExists( + t.t, universeTap, assetID1, groupKey, fundingScriptTreeBytes1, + fmt.Sprintf("%v:%v", fundRespEF.Txid, fundRespEF.OutputIndex), + ) + assertUniverseProofExists( + t.t, universeTap, assetID2, groupKey, fundingScriptTreeBytes2, + fmt.Sprintf("%v:%v", fundRespEF.Txid, fundRespEF.OutputIndex), + ) + + // Make sure the channel shows the correct asset information. + assertAssetChan( + t.t, charlieTap.node, daveTap.node, charlieFundingAmount, + mintedAssets, + ) + assertAssetChan( + t.t, erinTap.node, fabiaTap.node, erinFundingAmount, + mintedAssets, + ) + + chanPointCD := &lnrpc.ChannelPoint{ + OutputIndex: uint32(fundRespCD.OutputIndex), + FundingTxid: &lnrpc.ChannelPoint_FundingTxidStr{ + FundingTxidStr: fundRespCD.Txid, + }, + } + chanPointEF := &lnrpc.ChannelPoint{ + OutputIndex: uint32(fundRespEF.OutputIndex), + FundingTxid: &lnrpc.ChannelPoint_FundingTxidStr{ + FundingTxidStr: fundRespEF.Txid, + }, + } + + return chanPointCD, chanPointEF +} + +// sendAssetsAndAssert sends the given amount of assets to the recipient and +// asserts that the transfer was successful. It also checks that the asset +// balance of the sender and recipient is as expected. +func sendAssetsAndAssert(ctx context.Context, t *harnessTest, + recipient, sender, universe *tapClient, mintedAsset *taprpc.Asset, + assetSendAmount uint64, idx, numTransfers int, + previousSentAmount uint64) { + + assetID := mintedAsset.AssetGenesis.AssetId + recipientAddr, err := recipient.NewAddr(ctx, &taprpc.NewAddrRequest{ + Amt: assetSendAmount, + AssetId: assetID, + ProofCourierAddr: fmt.Sprintf( + "%s://%s", proof.UniverseRpcCourierType, + universe.node.Cfg.LitAddr(), + ), + }) + require.NoError(t.t, err) + + t.Logf("Sending %v asset units to %s...", assetSendAmount, + recipient.node.Cfg.Name) + + // We assume that we sent the same size in a previous send. + totalSent := assetSendAmount + previousSentAmount + + // Send the assets to recipient. + itest.AssertAddrCreated( + t.t, recipient, mintedAsset, recipientAddr, + ) + sendResp, err := sender.SendAsset(ctx, &taprpc.SendAssetRequest{ + TapAddrs: []string{recipientAddr.Encoded}, + }) + require.NoError(t.t, err) + itest.ConfirmAndAssertOutboundTransfer( + t.t, t.lndHarness.Miner.Client, sender, sendResp, + assetID, + []uint64{mintedAsset.Amount - totalSent, assetSendAmount}, + idx, idx+1, + ) + itest.AssertNonInteractiveRecvComplete(t.t, recipient, numTransfers) +} + func assertNumAssetUTXOs(t *testing.T, tapdClient *tapClient, numUTXOs int) *taprpc.ListUtxosResponse { @@ -390,8 +669,8 @@ func syncUniverses(t *testing.T, universe *tapClient, nodes ...*HarnessNode) { func assertUniverseProofExists(t *testing.T, universe *tapClient, assetID, groupKey, scriptKey []byte, outpoint string) *taprpc.Asset { - t.Logf("Asserting proof outpoint=%v, script_key=%x", outpoint, - scriptKey) + t.Logf("Asserting proof outpoint=%v, script_key=%x, asset_id=%x, "+ + "group_key=%x", outpoint, scriptKey, assetID, groupKey) req := &universerpc.UniverseKey{ Id: &universerpc.ID{ @@ -473,7 +752,7 @@ func assertPendingChannels(t *testing.T, node *HarnessNode, pendingChan.Channel.CustomChannelData, &pendingJSON, ) require.NoError(t, err) - require.Len(t, pendingJSON.FundingAssets, 1) + require.GreaterOrEqual(t, len(pendingJSON.FundingAssets), 1) require.NotZero(t, pendingJSON.Capacity) @@ -494,9 +773,7 @@ func assertPendingChannels(t *testing.T, node *HarnessNode, // Check the balance of the pending channel. assetID := mintedAsset.AssetGenesis.AssetId pendingLocalBalance, pendingRemoteBalance, _, _ := - getAssetChannelBalance( - t, node, assetID, true, - ) + getAssetChannelBalance(t, node, [][]byte{assetID}, true) require.EqualValues(t, localSum, pendingLocalBalance) require.EqualValues(t, remoteSum, pendingRemoteBalance) } @@ -517,7 +794,7 @@ func haveFundingAsset(assetChannel *rfqmsg.JsonAssetChannel, } func assertAssetChan(t *testing.T, src, dst *HarnessNode, fundingAmount uint64, - mintedAsset *taprpc.Asset) { + channelAssets []*taprpc.Asset) { err := wait.NoError(func() error { a, err := getChannelCustomData(src, dst) @@ -525,10 +802,12 @@ func assertAssetChan(t *testing.T, src, dst *HarnessNode, fundingAmount uint64, return err } - assetID := mintedAsset.AssetGenesis.AssetId - if !haveFundingAsset(a, assetID) { - return fmt.Errorf("expected asset ID %x, to "+ - "be in channel", assetID) + for _, channelAsset := range channelAssets { + assetID := channelAsset.AssetGenesis.AssetId + if !haveFundingAsset(a, assetID) { + return fmt.Errorf("expected asset ID %x, to "+ + "be in channel", assetID) + } } if a.Capacity != fundingAmount { @@ -538,10 +817,12 @@ func assertAssetChan(t *testing.T, src, dst *HarnessNode, fundingAmount uint64, // Check the decimal display of the channel funding blob. If no // explicit value was set, we assume and expect the value of 0. + // We only need to check the first funding asset, since we + // enforce them to be the same. var expectedDecimalDisplay uint8 - if mintedAsset.DecimalDisplay != nil { + if channelAssets[0].DecimalDisplay != nil { expectedDecimalDisplay = uint8( - mintedAsset.DecimalDisplay.DecimalDisplay, + channelAssets[0].DecimalDisplay.DecimalDisplay, ) } @@ -629,15 +910,15 @@ func getChannelCustomData(src, dst *HarnessNode) (*rfqmsg.JsonAssetChannel, err) } - if len(assetData.FundingAssets) != 1 { - return nil, fmt.Errorf("expected 1 asset, got %d", + if len(assetData.FundingAssets) == 0 { + return nil, fmt.Errorf("expected at least 1 asset, got %d", len(assetData.FundingAssets)) } return &assetData, nil } -func getAssetChannelBalance(t *testing.T, node *HarnessNode, assetID []byte, +func getAssetChannelBalance(t *testing.T, node *HarnessNode, assetIDs [][]byte, pending bool) (uint64, uint64, uint64, uint64) { ctxb := context.Background() @@ -649,18 +930,34 @@ func getAssetChannelBalance(t *testing.T, node *HarnessNode, assetID []byte, ) require.NoError(t, err) + // In case there are no channels, the custom channel data will just be + // empty. Which means the total asset balance is zero. + if len(balance.CustomChannelData) == 0 { + return 0, 0, 0, 0 + } + var assetBalance rfqmsg.JsonAssetChannelBalances err = json.Unmarshal(balance.CustomChannelData, &assetBalance) - require.NoError(t, err) + require.NoErrorf(t, err, "json: '%x'", balance.CustomChannelData) balances := assetBalance.OpenChannels if pending { balances = assetBalance.PendingChannels } + idMatch := func(assetIDString string) bool { + for _, groupedID := range assetIDs { + if assetIDString == hex.EncodeToString(groupedID) { + return true + } + } + + return false + } + var localSum, remoteSum uint64 for assetIDString := range balances { - if assetIDString != hex.EncodeToString(assetID) { + if !idMatch(assetIDString) { continue } @@ -741,12 +1038,6 @@ func sendAssetKeySendPayment(t *testing.T, src, dst *HarnessNode, amt uint64, opt(cfg) } - // Nullify assetID if group key is set. RPC methods won't accept both so - // let's prioritize the group key if set. - if len(cfg.groupKey) > 0 { - assetID = nil - } - ctxb := context.Background() ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout) defer cancel() @@ -773,12 +1064,20 @@ func sendAssetKeySendPayment(t *testing.T, src, dst *HarnessNode, amt uint64, TimeoutSeconds: int32(PaymentTimeout.Seconds()), } - stream, err := srcTapd.SendPayment(ctxt, &tchrpc.SendPaymentRequest{ - AssetId: assetID, + request := &tchrpc.SendPaymentRequest{ AssetAmount: amt, - GroupKey: cfg.groupKey, PaymentRequest: sendReq, - }) + } + + switch { + case len(cfg.groupKey) > 0: + request.GroupKey = cfg.groupKey + + default: + request.AssetId = assetID + } + + stream, err := srcTapd.SendPayment(ctxt, request) require.NoError(t, err) result, err := getAssetPaymentResult(stream, false) @@ -964,12 +1263,6 @@ func defaultPayConfig() *payConfig { type payOpt func(*payConfig) -func withGroupKey(groupKey []byte) payOpt { - return func(c *payConfig) { - c.groupKey = groupKey - } -} - func withSmallShards() payOpt { return func(c *payConfig) { c.smallShards = true @@ -1015,6 +1308,12 @@ func withAllowOverpay() payOpt { } } +func withGroupKey(groupKey []byte) payOpt { + return func(c *payConfig) { + c.groupKey = groupKey + } +} + func payInvoiceWithAssets(t *testing.T, payer, rfqPeer *HarnessNode, payReq string, assetID []byte, opts ...payOpt) (uint64, rfqmath.BigIntFixedPoint) { @@ -1024,12 +1323,6 @@ func payInvoiceWithAssets(t *testing.T, payer, rfqPeer *HarnessNode, opt(cfg) } - // Nullify assetID if group key is set. RPC methods won't accept both so - // let's prioritize the group key if set. - if len(cfg.groupKey) > 0 { - assetID = []byte{} - } - ctxb := context.Background() ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout) defer cancel() @@ -1058,14 +1351,22 @@ func payInvoiceWithAssets(t *testing.T, payer, rfqPeer *HarnessNode, copy(rfqBytes, i[:]) }) - stream, err := payerTapd.SendPayment(ctxt, &tchrpc.SendPaymentRequest{ - AssetId: assetID, + request := &tchrpc.SendPaymentRequest{ PeerPubkey: rfqPeer.PubKey[:], - GroupKey: cfg.groupKey, PaymentRequest: sendReq, RfqId: rfqBytes, AllowOverpay: cfg.allowOverpay, - }) + } + + switch { + case len(cfg.groupKey) > 0: + request.GroupKey = cfg.groupKey + + default: + request.AssetId = assetID + } + + stream, err := payerTapd.SendPayment(ctxt, request) require.NoError(t, err) // If an error is returned by the RPC method (meaning the stream itself @@ -1155,12 +1456,6 @@ func createAssetInvoice(t *testing.T, dstRfqPeer, dst *HarnessNode, opt(cfg) } - // Nullify assetID if group key is set. RPC methods won't accept both so - // let's prioritize the group key if set. - if len(cfg.groupKey) > 0 { - assetID = []byte{} - } - ctxb := context.Background() ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout) defer cancel() @@ -1173,8 +1468,7 @@ func createAssetInvoice(t *testing.T, dstRfqPeer, dst *HarnessNode, dstTapd := newTapClient(t, dst) - resp, err := dstTapd.AddInvoice(ctxt, &tchrpc.AddInvoiceRequest{ - AssetId: assetID, + request := &tchrpc.AddInvoiceRequest{ GroupKey: cfg.groupKey, AssetAmount: assetAmount, PeerPubkey: dstRfqPeer.PubKey[:], @@ -1183,7 +1477,17 @@ func createAssetInvoice(t *testing.T, dstRfqPeer, dst *HarnessNode, "%d units", assetAmount), Expiry: timeoutSeconds, }, - }) + } + + switch { + case len(cfg.groupKey) > 0: + request.GroupKey = cfg.groupKey + + default: + request.AssetId = assetID + } + + resp, err := dstTapd.AddInvoice(ctxt, request) if cfg.errSubStr != "" { require.ErrorContains(t, err, cfg.errSubStr) @@ -1339,12 +1643,6 @@ func createAssetHodlInvoice(t *testing.T, dstRfqPeer, dst *HarnessNode, opt(cfg) } - // Nullify assetID if group key is set. RPC methods won't accept both so - // let's prioritize the group key if set. - if len(cfg.groupKey) > 0 { - assetID = []byte{} - } - ctxb := context.Background() ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout) defer cancel() @@ -1364,10 +1662,7 @@ func createAssetHodlInvoice(t *testing.T, dstRfqPeer, dst *HarnessNode, require.NoError(t, err) payHash := preimage.Hash() - - resp, err := dstTapd.AddInvoice(ctxt, &tchrpc.AddInvoiceRequest{ - AssetId: assetID, - GroupKey: cfg.groupKey, + request := &tchrpc.AddInvoiceRequest{ AssetAmount: assetAmount, PeerPubkey: dstRfqPeer.PubKey[:], InvoiceRequest: &lnrpc.Invoice{ @@ -1378,7 +1673,17 @@ func createAssetHodlInvoice(t *testing.T, dstRfqPeer, dst *HarnessNode, HodlInvoice: &tchrpc.HodlInvoice{ PaymentHash: payHash[:], }, - }) + } + + switch { + case len(cfg.groupKey) > 0: + request.GroupKey = cfg.groupKey + + default: + request.AssetId = assetID + } + + resp, err := dstTapd.AddInvoice(ctxt, request) require.NoError(t, err) decodedInvoice, err := dst.DecodePayReq(ctxt, &lnrpc.PayReqString{ @@ -1396,7 +1701,7 @@ func createAssetHodlInvoice(t *testing.T, dstRfqPeer, dst *HarnessNode, require.EqualValues(t, uint64(numMSats), uint64(decodedInvoice.NumMsat)) - t.Logf("Got quote for %d sats at %v msat/unit from peer %x with SCID "+ + t.Logf("Got quote for %d msat at %v msat/unit from peer %x with SCID "+ "%d", decodedInvoice.NumMsat, mSatPerUnit, dstRfqPeer.PubKey[:], resp.AcceptedBuyQuote.Scid) @@ -1428,12 +1733,12 @@ func waitForSendEvent(t *testing.T, // transaction. type coOpCloseBalanceCheck func(t *testing.T, local, remote *HarnessNode, closeTx *wire.MsgTx, closeUpdate *lnrpc.ChannelCloseUpdate, - assetID, groupKey []byte, universeTap *tapClient) + assetIDs [][]byte, groupKey []byte, universeTap *tapClient) // noOpCoOpCloseBalanceCheck is a no-op implementation of the co-op close // balance check that can be used in tests. func noOpCoOpCloseBalanceCheck(_ *testing.T, _, _ *HarnessNode, _ *wire.MsgTx, - _ *lnrpc.ChannelCloseUpdate, _, _ []byte, _ *tapClient) { + _ *lnrpc.ChannelCloseUpdate, _ [][]byte, _ []byte, _ *tapClient) { // This is a no-op function. } @@ -1442,7 +1747,7 @@ func noOpCoOpCloseBalanceCheck(_ *testing.T, _, _ *HarnessNode, _ *wire.MsgTx, // node and asserts the final balances of the closing transaction. func closeAssetChannelAndAssert(t *harnessTest, net *NetworkHarness, local, remote *HarnessNode, chanPoint *lnrpc.ChannelPoint, - assetID, groupKey []byte, universeTap *tapClient, + assetIDs [][]byte, groupKey []byte, universeTap *tapClient, balanceCheck coOpCloseBalanceCheck) { t.t.Helper() @@ -1482,7 +1787,7 @@ func closeAssetChannelAndAssert(t *harnessTest, net *NetworkHarness, // Check the final balance of the closing transaction. balanceCheck( - t.t, local, remote, closeTx, closeUpdate, assetID, groupKey, + t.t, local, remote, closeTx, closeUpdate, assetIDs, groupKey, universeTap, ) @@ -1499,10 +1804,10 @@ func assertDefaultCoOpCloseBalance(remoteBtcBalance, return func(t *testing.T, local, remote *HarnessNode, closeTx *wire.MsgTx, closeUpdate *lnrpc.ChannelCloseUpdate, - assetID, groupKey []byte, universeTap *tapClient) { + assetIDs [][]byte, groupKey []byte, universeTap *tapClient) { defaultCoOpCloseBalanceCheck( - t, local, remote, closeTx, closeUpdate, assetID, + t, local, remote, closeTx, closeUpdate, assetIDs, groupKey, universeTap, remoteBtcBalance, remoteAssetBalance, ) @@ -1515,8 +1820,8 @@ func assertDefaultCoOpCloseBalance(remoteBtcBalance, // with the boolean variables. func defaultCoOpCloseBalanceCheck(t *testing.T, local, remote *HarnessNode, closeTx *wire.MsgTx, closeUpdate *lnrpc.ChannelCloseUpdate, - assetID, groupKey []byte, universeTap *tapClient, remoteBtcBalance, - remoteAssetBalance bool) { + assetIDs [][]byte, groupKey []byte, universeTap *tapClient, + remoteBtcBalance, remoteAssetBalance bool) { // With the channel closed, we'll now assert that the co-op close // transaction was inserted into the local universe. @@ -1623,11 +1928,15 @@ func defaultCoOpCloseBalanceCheck(t *testing.T, local, remote *HarnessNode, ) require.NoError(t, err) + assetIDStrings := fn.Map(hex.EncodeToString, assetIDs) for assetIDStr, scriptKeyStr := range localAssetCloseOut.ScriptKeys { scriptKeyBytes, err := hex.DecodeString(scriptKeyStr) require.NoError(t, err) - require.Equal(t, hex.EncodeToString(assetID), assetIDStr) + require.Contains(t, assetIDStrings, assetIDStr) + + assetID, err := hex.DecodeString(assetIDStr) + require.NoError(t, err) a := assertUniverseProofExists( t, universeTap, assetID, groupKey, scriptKeyBytes, @@ -1665,7 +1974,10 @@ func defaultCoOpCloseBalanceCheck(t *testing.T, local, remote *HarnessNode, scriptKeyBytes, err := hex.DecodeString(scriptKeyStr) require.NoError(t, err) - require.Equal(t, hex.EncodeToString(assetID), assetIDStr) + require.Contains(t, assetIDStrings, assetIDStr) + + assetID, err := hex.DecodeString(assetIDStr) + require.NoError(t, err) a := assertUniverseProofExists( t, universeTap, assetID, groupKey, scriptKeyBytes, @@ -1687,8 +1999,8 @@ func defaultCoOpCloseBalanceCheck(t *testing.T, local, remote *HarnessNode, // function that can be used when the initiator has a zero asset balance. func initiatorZeroAssetBalanceCoOpBalanceCheck(t *testing.T, _, remote *HarnessNode, closeTx *wire.MsgTx, - closeUpdate *lnrpc.ChannelCloseUpdate, assetID, groupKey []byte, - universeTap *tapClient) { + closeUpdate *lnrpc.ChannelCloseUpdate, assetIDs [][]byte, + groupKey []byte, universeTap *tapClient) { // With the channel closed, we'll now assert that the co-op close // transaction was inserted into the local universe. @@ -1734,11 +2046,15 @@ func initiatorZeroAssetBalanceCoOpBalanceCheck(t *testing.T, _, ) require.NoError(t, err) + assetIDStrings := fn.Map(hex.EncodeToString, assetIDs) for assetIDStr, scriptKeyStr := range remoteAssetCloseOut.ScriptKeys { scriptKeyBytes, err := hex.DecodeString(scriptKeyStr) require.NoError(t, err) - require.Equal(t, hex.EncodeToString(assetID), assetIDStr) + require.Contains(t, assetIDStrings, assetIDStr) + + assetID, err := hex.DecodeString(assetIDStr) + require.NoError(t, err) a := assertUniverseProofExists( t, universeTap, assetID, groupKey, scriptKeyBytes, @@ -1881,12 +2197,15 @@ func assertAssetBalance(t *testing.T, client *tapClient, assetID []byte, }, } + var lastBalances *taprpc.ListBalancesResponse err := wait.NoError(func() error { assetIDBalances, err := client.ListBalances(ctxt, req) if err != nil { return err } + lastBalances = assetIDBalances + assetIDFound := false for _, balance := range assetIDBalances.AssetBalances { if !bytes.Equal(balance.AssetGenesis.AssetId, assetID) { @@ -1907,11 +2226,16 @@ func assertAssetBalance(t *testing.T, client *tapClient, assetID []byte, return nil }, shortTimeout) if err != nil { - r, err2 := client.ListAssets(ctxb, &taprpc.ListAssetRequest{}) + listAssetsResp, err2 := client.ListAssets( + ctxb, &taprpc.ListAssetRequest{}, + ) require.NoError(t, err2) - t.Logf("Failed to assert expected balance of %d, current "+ - "assets: %v", expectedBalance, toProtoJSON(t, r)) + t.Logf("Failed to assert expected balance of %d for asset ID "+ + "%x: %v", expectedBalance, assetID, err) + + t.Logf("Last balances: %v", toProtoJSON(t, lastBalances)) + t.Logf("Current assets: %v", toProtoJSON(t, listAssetsResp)) utxos, err3 := client.ListUtxos( ctxb, &taprpc.ListUtxosRequest{}, @@ -1924,40 +2248,57 @@ func assertAssetBalance(t *testing.T, client *tapClient, assetID []byte, } } -// assertSpendableBalance differs from assertAssetBalance in that it asserts -// that the entire balance is spendable. We consider something spendable if we -// have a local script key for it. -func assertSpendableBalance(t *testing.T, client *tapClient, assetID []byte, - expectedBalance uint64) { - - t.Helper() +func spendableBalance(client *tapClient, assetID, + groupKey []byte) (uint64, error) { ctxb := context.Background() ctxt, cancel := context.WithTimeout(ctxb, shortTimeout) defer cancel() - err := wait.NoError(func() error { - utxos, err := client.ListUtxos(ctxt, &taprpc.ListUtxosRequest{}) - if err != nil { - return err + utxos, err := client.ListUtxos(ctxt, &taprpc.ListUtxosRequest{}) + if err != nil { + return 0, err + } + + assets := tapfn.FlatMap( + maps.Values(utxos.ManagedUtxos), + func(utxo *taprpc.ManagedUtxo) []*taprpc.Asset { + return utxo.Assets + }, + ) + + relevantAssets := fn.Filter(func(utxo *taprpc.Asset) bool { + if len(groupKey) > 0 { + return bytes.Equal( + utxo.AssetGroup.TweakedGroupKey, groupKey, + ) } - assets := tapfn.FlatMap( - maps.Values(utxos.ManagedUtxos), - func(utxo *taprpc.ManagedUtxo) []*taprpc.Asset { - return utxo.Assets - }, - ) + return bytes.Equal(utxo.AssetGenesis.AssetId, assetID) + }, assets) - relevantAssets := fn.Filter(func(utxo *taprpc.Asset) bool { - return bytes.Equal(utxo.AssetGenesis.AssetId, assetID) - }, assets) + var assetSum uint64 + for _, a := range relevantAssets { + if a.ScriptKeyIsLocal { + assetSum += a.Amount + } + } - var assetSum uint64 - for _, asset := range relevantAssets { - if asset.ScriptKeyIsLocal { - assetSum += asset.Amount - } + return assetSum, nil +} + +// assertSpendableBalance differs from assertAssetBalance in that it asserts +// that the entire balance is spendable. We consider something spendable if we +// have a local script key for it. +func assertSpendableBalance(t *testing.T, client *tapClient, assetID, + groupKey []byte, expectedBalance uint64) { + + t.Helper() + + err := wait.NoError(func() error { + assetSum, err := spendableBalance(client, assetID, groupKey) + if err != nil { + return err } if assetSum != expectedBalance { @@ -1968,16 +2309,19 @@ func assertSpendableBalance(t *testing.T, client *tapClient, assetID []byte, return nil }, shortTimeout) if err != nil { - r, err2 := client.ListAssets(ctxb, &taprpc.ListAssetRequest{}) + ctxb := context.Background() + listResp, err2 := client.ListAssets( + ctxb, &taprpc.ListAssetRequest{}, + ) require.NoError(t, err2) t.Logf("Failed to assert expected balance of %d, current "+ - "assets: %v", expectedBalance, toProtoJSON(t, r)) + "assets: %v", expectedBalance, toProtoJSON(t, listResp)) - utxos, err3 := client.ListUtxos( + utxos, err2 := client.ListUtxos( ctxb, &taprpc.ListUtxosRequest{}, ) - require.NoError(t, err3) + require.NoError(t, err2) t.Logf("Current UTXOs: %v", toProtoJSON(t, utxos)) @@ -2091,8 +2435,27 @@ func logBalance(t *testing.T, nodes []*HarnessNode, assetID []byte, time.Sleep(time.Millisecond * 250) for _, node := range nodes { - local, remote, localSat, remoteSat := - getAssetChannelBalance(t, node, assetID, false) + local, remote, localSat, remoteSat := getAssetChannelBalance( + t, node, [][]byte{assetID}, false, + ) + + t.Logf("%-7s balance: local=%-9d remote=%-9d, localSat=%-9d, "+ + "remoteSat=%-9d (%v)", node.Cfg.Name, local, remote, + localSat, remoteSat, occasion) + } +} + +func logBalanceGroup(t *testing.T, nodes []*HarnessNode, assetIDs [][]byte, + occasion string) { + + t.Helper() + + time.Sleep(time.Millisecond * 250) + + for _, node := range nodes { + local, remote, localSat, remoteSat := getAssetChannelBalance( + t, node, assetIDs, false, + ) t.Logf("%-7s balance: local=%-9d remote=%-9d, localSat=%-9d, "+ "remoteSat=%-9d (%v)", node.Cfg.Name, local, remote, @@ -2325,9 +2688,9 @@ func assertPendingChannelAssetData(t *testing.T, node *HarnessNode, "data: %v", err) } - if len(closeData.FundingAssets) != 1 { - return fmt.Errorf("expected 1 funding asset, got %d", - len(closeData.FundingAssets)) + if len(closeData.FundingAssets) == 0 { + return fmt.Errorf("expected at least 1 funding asset, "+ + "got %d", len(closeData.FundingAssets)) } return nil @@ -2423,3 +2786,449 @@ func assertClosedChannelAssetData(t *testing.T, node *HarnessNode, require.GreaterOrEqual(t, len(closeData.FundingAssets), 1) } + +func findForceCloseTransfer(t *testing.T, node1, node2 *tapClient, + closeTxid *chainhash.Hash) *taprpc.ListTransfersResponse { + + var ( + ctxb = context.Background() + result *taprpc.ListTransfersResponse + err error + ) + fErr := wait.NoError(func() error { + result, err = node1.ListTransfers( + ctxb, &taprpc.ListTransfersRequest{ + AnchorTxid: closeTxid.String(), + }, + ) + if err != nil { + return fmt.Errorf("unable to list node1 transfers: %w", + err) + } + if len(result.Transfers) != 1 { + return fmt.Errorf("node1 is missing force close " + + "transfer") + } + + forceCloseTransfer2, err := node2.ListTransfers( + ctxb, &taprpc.ListTransfersRequest{ + AnchorTxid: closeTxid.String(), + }, + ) + if err != nil { + return fmt.Errorf("unable to list node2 transfers: %w", + err) + } + if len(forceCloseTransfer2.Transfers) != 1 { + return fmt.Errorf("node2 is missing force close " + + "transfer") + } + + return nil + }, defaultTimeout) + require.NoError(t, fErr) + + return result +} + +// assertForceCloseSweeps asserts that the force close sweeps are initiated +// correctly. +func assertForceCloseSweeps(ctx context.Context, net *NetworkHarness, + t *harnessTest, alice, bob *HarnessNode, chanPoint *lnrpc.ChannelPoint, + aliceStartAmount uint64, assetInvoiceAmt, assetsPerMPPShard int, + assetID, groupKey []byte, aliceHodlInvoices, + bobHodlInvoices []assetHodlInvoice, mpp bool) (uint64, uint64) { + + aliceTap := newTapClient(t.t, alice) + bobTap := newTapClient(t.t, bob) + + // At this point, both sides should have 4 (or +4 with MPP) HTLCs + // active. + numHtlcs := 4 + numAdditionalShards := assetInvoiceAmt / assetsPerMPPShard + if mpp { + numHtlcs += numAdditionalShards * 2 + } + t.Logf("Asserting both Alice and Bob have %d HTLCs...", numHtlcs) + assertNumHtlcs(t.t, alice, numHtlcs) + assertNumHtlcs(t.t, bob, numHtlcs) + + // Before we force close, we'll grab the current height, the CSV delay + // needed, and also the absolute timeout of the set of active HTLCs. + closeExpiryInfo := newCloseExpiryInfo(t.t, alice) + + // With all of the HTLCs established, we'll now force close the channel + // with Alice. + t.Logf("Force close by Alice w/ HTLCs...") + _, closeTxid, err := net.CloseChannel(alice, chanPoint, true) + require.NoError(t.t, err) + + t.Logf("Channel closed! Mining blocks, close_txid=%v", closeTxid) + + // The channel should first be in "waiting close" until it confirms. + assertWaitingCloseChannelAssetData(t.t, alice, chanPoint) + + // Next, we'll mine a block which should start the clock ticking on the + // relative timeout for the Alice, and Bob. + // + // After this next block, both of them can start to sweep. + // + // For Alice, she'll go to the second level, revealing her preimage in + // the process. She'll then need to wait for the relative timeout to + // expire before she can sweep her output. + // + // For Bob, since the remote party (Alice) closed, he can try to sweep + // right away after initial confirmation. + mineBlocks(t, net, 1, 1) + + // After force closing, Bob should now have a transfer that tracks the + // force closed commitment transaction. + locateAssetTransfers(t.t, bobTap, *closeTxid) + + t.Logf("Settling Bob's hodl invoice") + + // It should then go to "pending force closed". + assertPendingForceCloseChannelAssetData(t.t, alice, chanPoint) + + // At this point, the commitment transaction has been mined, and we have + // 4 total HTLCs on Alice's commitment transaction: + // + // * 2x outgoing HTLCs from Alice to Bob + // * 2x incoming HTLCs from Bob to Alice (+2 with MPP) + // + // We'll leave half the HTLCs timeout, while pulling the other half. + // To start, we'll signal Bob to settle one of his incoming HTLCs on + // Alice's commitment transaction. For him, this is a remote success + // spend, so there's no CSV delay other than the 1 CSV (carve out), and + // he can spend directly from the commitment transaction. + _, err = bob.InvoicesClient.SettleInvoice( + ctx, &invoicesrpc.SettleInvoiceMsg{ + Preimage: bobHodlInvoices[0].preimage[:], + }, + ) + require.NoError(t.t, err) + + // We'll pause here for Bob to extend the sweep request to the sweeper. + assertSweepExists( + t.t, bob, + walletrpc.WitnessType_TAPROOT_HTLC_ACCEPTED_REMOTE_SUCCESS, + ) + + bobSweepTx1, err := waitForNTxsInMempool( + net.Miner.Client, 1, shortTimeout, + ) + require.NoError(t.t, err) + + // Next, we'll mine an additional block, this should allow Bob to sweep + // both his commitment output, and the incoming HTLC that we just + // settled above. + mineBlocks(t, net, 1, 1) + + // At this point, we should have the next sweep transaction in the + // mempool: Bob's incoming HTLC sweep directly off the commitment + // transaction. + bobSweepTx2, err := waitForNTxsInMempool( + net.Miner.Client, 1, shortTimeout, + ) + require.NoError(t.t, err) + + // We'll now mine the next block, which should confirm Bob's HTLC sweep + // transaction. + mineBlocks(t, net, 1, 1) + + bobSweepTransfer1 := locateAssetTransfers(t.t, bobTap, *bobSweepTx1[0]) + bobSweepTransfer2 := locateAssetTransfers(t.t, bobTap, *bobSweepTx2[0]) + t.Logf("Bob's sweep transfer 1: %v", + toProtoJSON(t.t, bobSweepTransfer1)) + t.Logf("Bob's sweep transfer 2: %v", + toProtoJSON(t.t, bobSweepTransfer2)) + + t.Logf("Confirming Bob's remote HTLC success sweep") + + // Bob's balance should now reflect that he's gained the value of the + // HTLC, in addition to his settled balance. We need to subtract 1 from + // the final balance due to the rounding down of the asset amount during + // RFQ conversion. + bobExpectedBalance := closeExpiryInfo.remoteAssetBalance + + uint64(assetInvoiceAmt-1) + t.Logf("Expecting Bob's balance to be %d", bobExpectedBalance) + assertSpendableBalance( + t.t, bobTap, assetID, groupKey, bobExpectedBalance, + ) + + // With Bob's HTLC settled, we'll now have Alice do the same. For her, + // it'll be a 2nd level sweep, which requires an extra transaction. + // + // Before, we do that though, enough blocks have passed so Alice can now + // sweep her to-local output. So we'll mine an extra block, then assert + // that she's swept everything properly. With the way the sweeper works, + // we need to mine one extra block before the sweeper picks things up. + mineBlocks(t, net, 1, 0) + + aliceSweepTx1, err := waitForNTxsInMempool( + net.Miner.Client, 1, shortTimeout, + ) + require.NoError(t.t, err) + + mineBlocks(t, net, 1, 1) + + aliceSweepTransfer1 := locateAssetTransfers( + t.t, aliceTap, *aliceSweepTx1[0], + ) + t.Logf("Alice's sweep transfer 1: %v", + toProtoJSON(t.t, aliceSweepTransfer1)) + + t.Logf("Confirming Alice's to-local sweep") + + // With this extra block mined, Alice's settled balance should be the + // starting balance, minus the 2 HTLCs, plus her settled balance. + aliceExpectedBalance := aliceStartAmount + aliceExpectedBalance += closeExpiryInfo.localAssetBalance + assertSpendableBalance( + t.t, aliceTap, assetID, groupKey, aliceExpectedBalance, + ) + + t.Logf("Settling Alice's hodl invoice") + + // With her commitment output swept above, we'll now settle one of + // Alice's incoming HTLCs. + _, err = alice.InvoicesClient.SettleInvoice( + ctx, &invoicesrpc.SettleInvoiceMsg{ + Preimage: aliceHodlInvoices[0].preimage[:], + }, + ) + require.NoError(t.t, err) + + // We'll pause here for Alice to extend the sweep request to the + // sweeper. + assertSweepExists( + t.t, alice, + walletrpc.WitnessType_TAPROOT_HTLC_ACCEPTED_LOCAL_SUCCESS, + ) + + // We'll now mine a block, which should trigger Alice's broadcast of the + // second level sweep transaction. + sweepBlocks := mineBlocks(t, net, 1, 0) + + // If the block mined above didn't also mine our sweep, then we'll mine + // one final block which will confirm Alice's sweep transaction. + if len(sweepBlocks[0].Transactions) == 1 { + sweepTx, err := waitForNTxsInMempool( + net.Miner.Client, 1, shortTimeout, + ) + require.NoError(t.t, err) + + // With the sweep transaction in the mempool, we'll mine a block + // to confirm the sweep. + mineBlocks(t, net, 1, 1) + + aliceSweepTransfer := locateAssetTransfers( + t.t, aliceTap, *sweepTx[0], + ) + t.Logf("Alice's first-level sweep transfer: %v", + toProtoJSON(t.t, aliceSweepTransfer)) + } else { + sweepTx := sweepBlocks[0].Transactions[1] + aliceSweepTransfer := locateAssetTransfers( + t.t, aliceTap, sweepTx.TxHash(), + ) + t.Logf("Alice's first-level sweep transfer: %v", + toProtoJSON(t.t, aliceSweepTransfer)) + } + + t.Logf("Confirming Alice's second level remote HTLC success sweep") + + // Next, we'll mine enough blocks to trigger the CSV expiry so Alice can + // sweep the HTLC into her wallet. + mineBlocks(t, net, closeExpiryInfo.csvDelay, 0) + + // We'll pause here and wait until the sweeper recognizes that we've + // offered the second level sweep transaction. + assertSweepExists( + t.t, alice, + //nolint: lll + walletrpc.WitnessType_TAPROOT_HTLC_ACCEPTED_SUCCESS_SECOND_LEVEL, + ) + + t.Logf("Confirming Alice's local HTLC success sweep") + + // Now that we know the sweep was offered, we'll mine an extra block to + // actually trigger a sweeper broadcast. Due to an internal block race + // condition, the sweep transaction may have already been + // published+mined. If so, we don't need to mine the extra block. + sweepBlocks = mineBlocks(t, net, 1, 0) + + // If the block mined above didn't also mine our sweep, then we'll mine + // one final block which will confirm Alice's sweep transaction. + if len(sweepBlocks[0].Transactions) == 1 { + sweepTx, err := waitForNTxsInMempool( + net.Miner.Client, 1, shortTimeout, + ) + require.NoError(t.t, err) + + mineBlocks(t, net, 1, 1) + + aliceSweepTransfer := locateAssetTransfers( + t.t, aliceTap, *sweepTx[0], + ) + t.Logf("Alice's second-level sweep transfer: %v", + toProtoJSON(t.t, aliceSweepTransfer)) + } else { + sweepTx := sweepBlocks[0].Transactions[1] + aliceSweepTransfer := locateAssetTransfers( + t.t, aliceTap, sweepTx.TxHash(), + ) + t.Logf("Alice's second-level sweep transfer: %v", + toProtoJSON(t.t, aliceSweepTransfer)) + } + + // With the sweep transaction confirmed, Alice's balance should have + // incremented by the amt of the HTLC. + aliceExpectedBalance += uint64(assetInvoiceAmt - 1) + assertSpendableBalance( + t.t, aliceTap, assetID, groupKey, aliceExpectedBalance, + ) + + t.Logf("Mining enough blocks to time out the remaining HTLCs") + + // At this point, we've swept two HTLCs: one from the remote commit, and + // one via the second layer. We'll now mine the remaining amount of + // blocks to time out the HTLCs. + blockToMine := closeExpiryInfo.blockTillExpiry( + aliceHodlInvoices[1].preimage.Hash(), + ) + mineBlocks(t, net, blockToMine, 0) + + // We'll wait for both Alice and Bob to present their respective sweeps + // to the sweeper. + numTimeoutHTLCs := 1 + if mpp { + numTimeoutHTLCs += numAdditionalShards + } + assertSweepExists( + t.t, alice, + walletrpc.WitnessType_TAPROOT_HTLC_LOCAL_OFFERED_TIMEOUT, + ) + assertSweepExists( + t.t, bob, + walletrpc.WitnessType_TAPROOT_HTLC_OFFERED_REMOTE_TIMEOUT, + ) + + t.Logf("Confirming initial HTLC timeout txns") + + timeoutSweeps, err := waitForNTxsInMempool( + net.Miner.Client, 2, shortTimeout, + ) + require.NoError(t.t, err) + + t.Logf("Asserting balance on sweeps: %v", timeoutSweeps) + + // Finally, we'll mine a single block to confirm them. + mineBlocks(t, net, 1, 2) + + // Make sure Bob swept all his HTLCs. + bobSweeps, err := bob.WalletKitClient.ListSweeps( + ctx, &walletrpc.ListSweepsRequest{ + Verbose: true, + }, + ) + require.NoError(t.t, err) + + var bobSweepTx *wire.MsgTx + for _, sweep := range bobSweeps.GetTransactionDetails().Transactions { + for _, tx := range timeoutSweeps { + if sweep.TxHash == tx.String() { + txBytes, err := hex.DecodeString(sweep.RawTxHex) + require.NoError(t.t, err) + + bobSweepTx = &wire.MsgTx{} + err = bobSweepTx.Deserialize( + bytes.NewReader(txBytes), + ) + require.NoError(t.t, err) + } + } + } + require.NotNil(t.t, bobSweepTx, "Bob's sweep transaction not found") + + // There's always an extra input that pays for the fees. So we can only + // count the remainder as HTLC inputs. + numSweptHTLCs := len(bobSweepTx.TxIn) - 1 + + // If we didn't yet sweep all HTLCs, then we need to wait for another + // sweep. + if numSweptHTLCs < numTimeoutHTLCs { + assertSweepExists( + t.t, bob, + // nolint: lll + walletrpc.WitnessType_TAPROOT_HTLC_OFFERED_REMOTE_TIMEOUT, + ) + + t.Logf("Confirming additional HTLC timeout sweep txns") + + additionalTimeoutSweeps, err := waitForNTxsInMempool( + net.Miner.Client, 1, shortTimeout, + ) + require.NoError(t.t, err) + + t.Logf("Asserting balance on additional timeout sweeps: %v", + additionalTimeoutSweeps) + + // Finally, we'll mine a single block to confirm them. + mineBlocks(t, net, 1, 1) + } + + // At this point, Bob's balance should be incremented by an additional + // HTLC value. + bobExpectedBalance += uint64(assetInvoiceAmt - 1) + assertSpendableBalance( + t.t, bobTap, assetID, groupKey, bobExpectedBalance, + ) + + t.Logf("Mining extra blocks for Alice's CSV to expire on 2nd level txn") + + // Next, we'll mine 4 additional blocks to Alice's CSV delay expires for + // the second level timeout output. + mineBlocks(t, net, closeExpiryInfo.csvDelay, 0) + + // Wait for Alice to extend the second level output to the sweeper + // before we mine the next block to the sweeper. + assertSweepExists( + t.t, alice, + walletrpc.WitnessType_TAPROOT_HTLC_OFFERED_TIMEOUT_SECOND_LEVEL, + ) + + t.Logf("Confirming Alice's final timeout sweep") + + // With the way the sweeper works, we'll now need to mine an extra block + // to trigger the sweep. + sweepBlocks = mineBlocks(t, net, 1, 0) + + // If the block mined above didn't also mine our sweep, then we'll mine + // one final block which will confirm Alice's sweep transaction. + if len(sweepBlocks[0].Transactions) == 1 { + sweepTx, err := waitForNTxsInMempool( + net.Miner.Client, 1, shortTimeout, + ) + require.NoError(t.t, err) + + // We'll mine one final block which will confirm Alice's sweep + // transaction. + mineBlocks(t, net, 1, 1) + + aliceSweepTransfer := locateAssetTransfers( + t.t, aliceTap, *sweepTx[0], + ) + t.Logf("Alice's final timeout sweep transfer: %v", + toProtoJSON(t.t, aliceSweepTransfer)) + } else { + sweepTx := sweepBlocks[0].Transactions[1] + aliceSweepTransfer := locateAssetTransfers( + t.t, aliceTap, sweepTx.TxHash(), + ) + t.Logf("Alice's final timeout sweep transfer: %v", + toProtoJSON(t.t, aliceSweepTransfer)) + } + + return aliceExpectedBalance, bobExpectedBalance +} diff --git a/itest/litd_custom_channels_test.go b/itest/litd_custom_channels_test.go index 80013c486..c50d91467 100644 --- a/itest/litd_custom_channels_test.go +++ b/itest/litd_custom_channels_test.go @@ -3,7 +3,6 @@ package itest import ( "bytes" "context" - "encoding/hex" "fmt" "math" "math/big" @@ -14,7 +13,6 @@ import ( "github.com/btcsuite/btcd/btcec/v2/schnorr" "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg/chainhash" - "github.com/btcsuite/btcd/wire" "github.com/lightninglabs/taproot-assets/asset" "github.com/lightninglabs/taproot-assets/itest" "github.com/lightninglabs/taproot-assets/proof" @@ -30,10 +28,9 @@ import ( "github.com/lightningnetwork/lnd/fn" "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc/invoicesrpc" - "github.com/lightningnetwork/lnd/lnrpc/walletrpc" "github.com/lightningnetwork/lnd/lntest" + "github.com/lightningnetwork/lnd/lntest/node" "github.com/lightningnetwork/lnd/lntest/port" - "github.com/lightningnetwork/lnd/lntest/wait" "github.com/lightningnetwork/lnd/lnwallet/chainfee" "github.com/lightningnetwork/lnd/lnwire" "github.com/stretchr/testify/require" @@ -109,18 +106,13 @@ func testCustomChannelsLarge(_ context.Context, net *NetworkHarness, lndArgs := slices.Clone(lndArgsTemplate) litdArgs := slices.Clone(litdArgsTemplate) - // Explicitly set the proof courier as Zane (now has no other role - // other than proof shuffling), otherwise a hashmail courier will be - // used. For the funding transaction, we're just posting it and don't - // expect a true receiver. - zane, err := net.NewNode( - t.t, "Zane", lndArgs, false, true, litdArgs..., - ) - require.NoError(t.t, err) - + // We use Charlie as the proof courier. But in order for Charlie to also + // use itself, we need to define its port upfront. + charliePort := port.NextAvailablePort() litdArgs = append(litdArgs, fmt.Sprintf( "--taproot-assets.proofcourieraddr=%s://%s", - proof.UniverseRpcCourierType, zane.Cfg.LitAddr(), + proof.UniverseRpcCourierType, + fmt.Sprintf(node.ListenerFormat, charliePort), )) // The topology we are going for looks like the following: @@ -139,8 +131,8 @@ func testCustomChannelsLarge(_ context.Context, net *NetworkHarness, // with tapd included. We also need specific flags to be enabled, so we // create 5 completely new nodes, ignoring the two default nodes that // are created by the harness. - charlie, err := net.NewNode( - t.t, "Charlie", lndArgs, false, true, litdArgs..., + charlie, err := net.NewNodeWithPort( + t.t, "Charlie", lndArgs, false, true, charliePort, litdArgs..., ) require.NoError(t.t, err) @@ -175,7 +167,7 @@ func testCustomChannelsLarge(_ context.Context, net *NetworkHarness, assertChannelKnown(t.t, charlie, channelOp) assertChannelKnown(t.t, fabia, channelOp) - universeTap := newTapClient(t.t, zane) + universeTap := newTapClient(t.t, charlie) charlieTap := newTapClient(t.t, charlie) daveTap := newTapClient(t.t, dave) erinTap := newTapClient(t.t, erin) @@ -283,7 +275,7 @@ func testCustomChannelsLarge(_ context.Context, net *NetworkHarness, // balance is on the non-initiator (recipient) side. t.Logf("Closing Charlie -> Dave channel") closeAssetChannelAndAssert( - t, net, charlie, dave, chanPointCD, assetID, nil, + t, net, charlie, dave, chanPointCD, [][]byte{assetID}, nil, universeTap, initiatorZeroAssetBalanceCoOpBalanceCheck, ) } @@ -296,18 +288,13 @@ func testCustomChannels(ctx context.Context, net *NetworkHarness, lndArgs := slices.Clone(lndArgsTemplate) litdArgs := slices.Clone(litdArgsTemplate) - // Explicitly set the proof courier as Zane (now has no other role - // other than proof shuffling), otherwise a hashmail courier will be - // used. For the funding transaction, we're just posting it and don't - // expect a true receiver. - zane, err := net.NewNode( - t.t, "Zane", lndArgs, false, true, litdArgs..., - ) - require.NoError(t.t, err) - + // We use Charlie as the proof courier. But in order for Charlie to also + // use itself, we need to define its port upfront. + charliePort := port.NextAvailablePort() litdArgs = append(litdArgs, fmt.Sprintf( "--taproot-assets.proofcourieraddr=%s://%s", - proof.UniverseRpcCourierType, zane.Cfg.LitAddr(), + proof.UniverseRpcCourierType, + fmt.Sprintf(node.ListenerFormat, charliePort), )) // The topology we are going for looks like the following: @@ -326,8 +313,8 @@ func testCustomChannels(ctx context.Context, net *NetworkHarness, // with tapd included. We also need specific flags to be enabled, so we // create 5 completely new nodes, ignoring the two default nodes that // are created by the harness. - charlie, err := net.NewNode( - t.t, "Charlie", lndArgs, false, true, litdArgs..., + charlie, err := net.NewNodeWithPort( + t.t, "Charlie", lndArgs, false, true, charliePort, litdArgs..., ) require.NoError(t.t, err) @@ -339,9 +326,7 @@ func testCustomChannels(ctx context.Context, net *NetworkHarness, t.t, "Fabia", lndArgs, false, true, litdArgs..., ) require.NoError(t.t, err) - yara, err := net.NewNode( - t.t, "Yara", lndArgs, false, true, litdArgs..., - ) + yara, err := net.NewNode(t.t, "Yara", lndArgs, false, true, litdArgs...) require.NoError(t.t, err) nodes := []*HarnessNode{charlie, dave, erin, fabia, yara} @@ -362,7 +347,7 @@ func testCustomChannels(ctx context.Context, net *NetworkHarness, assertChannelKnown(t.t, charlie, channelOp) assertChannelKnown(t.t, fabia, channelOp) - universeTap := newTapClient(t.t, zane) + universeTap := newTapClient(t.t, charlie) charlieTap := newTapClient(t.t, charlie) daveTap := newTapClient(t.t, dave) erinTap := newTapClient(t.t, erin) @@ -626,19 +611,19 @@ func testCustomChannels(ctx context.Context, net *NetworkHarness, // ------------ t.Logf("Closing Charlie -> Dave channel") closeAssetChannelAndAssert( - t, net, charlie, dave, chanPointCD, assetID, nil, + t, net, charlie, dave, chanPointCD, [][]byte{assetID}, nil, universeTap, assertDefaultCoOpCloseBalance(true, true), ) t.Logf("Closing Dave -> Yara channel, close initiated by Yara") closeAssetChannelAndAssert( - t, net, yara, dave, chanPointDY, assetID, nil, + t, net, yara, dave, chanPointDY, [][]byte{assetID}, nil, universeTap, assertDefaultCoOpCloseBalance(false, true), ) t.Logf("Closing Erin -> Fabia channel") closeAssetChannelAndAssert( - t, net, erin, fabia, chanPointEF, assetID, nil, + t, net, erin, fabia, chanPointEF, [][]byte{assetID}, nil, universeTap, assertDefaultCoOpCloseBalance(true, true), ) @@ -679,7 +664,9 @@ func testCustomChannels(ctx context.Context, net *NetworkHarness, t.t, universeTap, assetID, nil, fundingScriptTreeBytes, fmt.Sprintf("%v:%v", fundRespCD.Txid, fundRespCD.OutputIndex), ) - assertAssetChan(t.t, charlie, dave, fundingAmount, cents) + assertAssetChan( + t.t, charlie, dave, fundingAmount, []*taprpc.Asset{cents}, + ) // And let's just close the channel again. chanPointCD = &lnrpc.ChannelPoint{ @@ -691,7 +678,7 @@ func testCustomChannels(ctx context.Context, net *NetworkHarness, t.Logf("Closing Charlie -> Dave channel") closeAssetChannelAndAssert( - t, net, charlie, dave, chanPointCD, assetID, nil, + t, net, charlie, dave, chanPointCD, [][]byte{assetID}, nil, universeTap, assertDefaultCoOpCloseBalance(false, false), ) @@ -761,18 +748,13 @@ func testCustomChannelsGroupedAsset(ctx context.Context, net *NetworkHarness, lndArgs := slices.Clone(lndArgsTemplate) litdArgs := slices.Clone(litdArgsTemplate) - // Explicitly set the proof courier as Zane (now has no other role - // other than proof shuffling), otherwise a hashmail courier will be - // used. For the funding transaction, we're just posting it and don't - // expect a true receiver. - zane, err := net.NewNode( - t.t, "Zane", lndArgs, false, true, litdArgs..., - ) - require.NoError(t.t, err) - + // We use Charlie as the proof courier. But in order for Charlie to also + // use itself, we need to define its port upfront. + charliePort := port.NextAvailablePort() litdArgs = append(litdArgs, fmt.Sprintf( "--taproot-assets.proofcourieraddr=%s://%s", - proof.UniverseRpcCourierType, zane.Cfg.LitAddr(), + proof.UniverseRpcCourierType, + fmt.Sprintf(node.ListenerFormat, charliePort), )) // The topology we are going for looks like the following: @@ -791,8 +773,8 @@ func testCustomChannelsGroupedAsset(ctx context.Context, net *NetworkHarness, // with tapd included. We also need specific flags to be enabled, so we // create 5 completely new nodes, ignoring the two default nodes that // are created by the harness. - charlie, err := net.NewNode( - t.t, "Charlie", lndArgs, false, true, litdArgs..., + charlie, err := net.NewNodeWithPort( + t.t, "Charlie", lndArgs, false, true, charliePort, litdArgs..., ) require.NoError(t.t, err) @@ -827,7 +809,7 @@ func testCustomChannelsGroupedAsset(ctx context.Context, net *NetworkHarness, assertChannelKnown(t.t, charlie, channelOp) assertChannelKnown(t.t, fabia, channelOp) - universeTap := newTapClient(t.t, zane) + universeTap := newTapClient(t.t, charlie) charlieTap := newTapClient(t.t, charlie) daveTap := newTapClient(t.t, dave) erinTap := newTapClient(t.t, erin) @@ -1064,19 +1046,19 @@ func testCustomChannelsGroupedAsset(ctx context.Context, net *NetworkHarness, // ------------ t.Logf("Closing Charlie -> Dave channel") closeAssetChannelAndAssert( - t, net, charlie, dave, chanPointCD, assetID, groupID, + t, net, charlie, dave, chanPointCD, [][]byte{assetID}, groupID, universeTap, assertDefaultCoOpCloseBalance(true, true), ) t.Logf("Closing Dave -> Yara channel, close initiated by Yara") closeAssetChannelAndAssert( - t, net, yara, dave, chanPointDY, assetID, groupID, + t, net, yara, dave, chanPointDY, [][]byte{assetID}, groupID, universeTap, assertDefaultCoOpCloseBalance(false, true), ) t.Logf("Closing Erin -> Fabia channel") closeAssetChannelAndAssert( - t, net, erin, fabia, chanPointEF, assetID, groupID, + t, net, erin, fabia, chanPointEF, [][]byte{assetID}, groupID, universeTap, assertDefaultCoOpCloseBalance(true, true), ) @@ -1118,7 +1100,9 @@ func testCustomChannelsGroupedAsset(ctx context.Context, net *NetworkHarness, t.t, universeTap, nil, groupID, fundingScriptTreeBytes, fmt.Sprintf("%v:%v", fundRespCD.Txid, fundRespCD.OutputIndex), ) - assertAssetChan(t.t, charlie, dave, fundingAmount, cents) + assertAssetChan( + t.t, charlie, dave, fundingAmount, []*taprpc.Asset{cents}, + ) // And let's just close the channel again. chanPointCD = &lnrpc.ChannelPoint{ @@ -1130,7 +1114,7 @@ func testCustomChannelsGroupedAsset(ctx context.Context, net *NetworkHarness, t.Logf("Closing Charlie -> Dave channel") closeAssetChannelAndAssert( - t, net, charlie, dave, chanPointCD, assetID, groupID, + t, net, charlie, dave, chanPointCD, [][]byte{assetID}, groupID, universeTap, assertDefaultCoOpCloseBalance(false, false), ) @@ -1155,6 +1139,546 @@ func testCustomChannelsGroupedAsset(ctx context.Context, net *NetworkHarness, assertAssetBalance(t.t, fabiaTap, assetID, fabiaAssetBalance) } +// testCustomChannelsGroupTranchesForceClose tests that we can successfully open +// a custom channel with multiple pieces of a grouped asset. We then test that +// we can successfully co-op and force close such channels and sweep the +// remaining channel balances. +func testCustomChannelsGroupTranchesForceClose(ctx context.Context, + net *NetworkHarness, t *harnessTest) { + + lndArgs := slices.Clone(lndArgsTemplate) + litdArgs := slices.Clone(litdArgsTemplate) + + // We use Charlie as the proof courier. But in order for Charlie to also + // use itself, we need to define its port upfront. + charliePort := port.NextAvailablePort() + litdArgs = append(litdArgs, fmt.Sprintf( + "--taproot-assets.proofcourieraddr=%s://%s", + proof.UniverseRpcCourierType, + fmt.Sprintf(node.ListenerFormat, charliePort), + )) + + // The topology we are going for looks like the following: + // + // Charlie --[assets]--> Dave --[sats]--> Erin --[assets]--> Fabia + // + // With [assets] being a custom channel and [sats] being a normal, BTC + // only channel. + charlie, err := net.NewNodeWithPort( + t.t, "Charlie", lndArgs, false, true, charliePort, litdArgs..., + ) + require.NoError(t.t, err) + + dave, err := net.NewNode(t.t, "Dave", lndArgs, false, true, litdArgs...) + require.NoError(t.t, err) + erin, err := net.NewNode(t.t, "Erin", lndArgs, false, true, litdArgs...) + require.NoError(t.t, err) + fabia, err := net.NewNode( + t.t, "Fabia", lndArgs, false, true, litdArgs..., + ) + require.NoError(t.t, err) + + nodes := []*HarnessNode{charlie, dave, erin, fabia} + connectAllNodes(t.t, net, nodes) + fundAllNodes(t.t, net, nodes) + + // Create the normal channel between Dave and Erin. + t.Logf("Opening normal channel between Dave and Erin...") + channelOp := openChannelAndAssert( + t, net, dave, erin, lntest.OpenChannelParams{ + Amt: 5_000_000, + SatPerVByte: 5, + }, + ) + defer closeChannelAndAssert(t, net, dave, channelOp, false) + + // This is the only public channel, we need everyone to be aware of it. + assertChannelKnown(t.t, charlie, channelOp) + assertChannelKnown(t.t, fabia, channelOp) + + universeTap := newTapClient(t.t, charlie) + charlieTap := newTapClient(t.t, charlie) + daveTap := newTapClient(t.t, dave) + erinTap := newTapClient(t.t, erin) + fabiaTap := newTapClient(t.t, fabia) + + groupAssetReq := itest.CopyRequest(&mintrpc.MintAssetRequest{ + Asset: itestAsset, + }) + groupAssetReq.Asset.NewGroupedAsset = true + + // Mint the asset tranches 1 and 2 on Charlie and sync all nodes to + // Charlie as the universe. + mintedAssetsT1 := itest.MintAssetsConfirmBatch( + t.t, t.lndHarness.Miner.Client, charlieTap, + []*mintrpc.MintAssetRequest{groupAssetReq}, + ) + centsT1 := mintedAssetsT1[0] + assetID1 := centsT1.AssetGenesis.AssetId + groupKey := centsT1.GetAssetGroup().GetTweakedGroupKey() + + groupAssetReq = itest.CopyRequest(&mintrpc.MintAssetRequest{ + Asset: itestAsset, + }) + groupAssetReq.Asset.GroupedAsset = true + groupAssetReq.Asset.GroupKey = groupKey + groupAssetReq.Asset.Name = "itest-asset-cents-tranche-2" + + mintedAssetsT2 := itest.MintAssetsConfirmBatch( + t.t, t.lndHarness.Miner.Client, charlieTap, + []*mintrpc.MintAssetRequest{groupAssetReq}, + ) + centsT2 := mintedAssetsT2[0] + assetID2 := centsT2.AssetGenesis.AssetId + + t.Logf("Minted lightning cents tranche 1 (%x) and 2 (%x) for group "+ + "key %x, syncing universes...", assetID1, assetID2, groupKey) + syncUniverses(t.t, charlieTap, dave, erin, fabia) + t.Logf("Universes synced between all nodes, distributing assets...") + + chanPointCD, chanPointEF := createTestAssetNetworkGroupKey( + ctx, t, net, charlieTap, daveTap, erinTap, fabiaTap, + universeTap, []*taprpc.Asset{centsT1, centsT2}, + fundingAmount, fundingAmount, DefaultPushSat, + ) + + t.Logf("Created channels %v and %v", chanPointCD, chanPointEF) + + // We now send some assets over the channels to test the functionality. + // Print initial channel balances. + groupIDs := [][]byte{assetID1, assetID2} + logBalanceGroup(t.t, nodes, groupIDs, "initial") + + // ------------ + // Test case 1: Send a few direct keysend payments from Charlie to Dave. + // We want to send at least 30k assets, so we use up one channel + // internal tranche of assets and should at least once have an HTLC + // that transports assets from two tranches. + // ------------ + const ( + keySendAmount = 5000 + numSends = 6 + totalFirstSend = keySendAmount * numSends + ) + for i := 0; i < numSends; i++ { + sendAssetKeySendPayment( + t.t, charlie, dave, keySendAmount, nil, + fn.None[int64](), withGroupKey(groupKey), + ) + } + logBalanceGroup(t.t, nodes, groupIDs, "after keysend Charlie->Dave") + + // ------------ + // Test case 2: Send a few direct keysend payments from Erin to Fabia. + // ------------ + for i := 0; i < numSends; i++ { + sendAssetKeySendPayment( + t.t, erin, fabia, keySendAmount, nil, + fn.None[int64](), withGroupKey(groupKey), + ) + } + logBalanceGroup(t.t, nodes, groupIDs, "after keysend Erin->Fabia") + + // ------------ + // Test case 3: Co-op close the channel between Charlie and Dave. + // ------------ + t.Logf("Closing Charlie -> Dave channel") + closeAssetChannelAndAssert( + t, net, charlie, dave, chanPointCD, + [][]byte{assetID1, assetID2}, groupKey, universeTap, + // TODO(guggero): replace this with + // assertDefaultCoOpCloseBalance(true, true) once we have the + // ability to check the custom data in the closed channel list. + noOpCoOpCloseBalanceCheck, + ) + + assertSpendableBalance( + t.t, charlieTap, nil, groupKey, fundingAmount-totalFirstSend+2, + ) + assertSpendableBalance(t.t, daveTap, nil, groupKey, totalFirstSend) + + // ------------ + // Test case 4: Force close the channel between Erin and Fabia. + // ------------ + _, closeTxid, err := net.CloseChannel(erin, chanPointEF, true) + require.NoError(t.t, err) + + t.Logf("Channel force closed! Mining blocks, close_txid=%v", closeTxid) + + // Next, we'll mine a block to confirm the force close. + mineBlocks(t, net, 1, 1) + + // At this point, we should have the force close transaction in the set + // of transfers for both nodes. + forceCloseTransfer := findForceCloseTransfer( + t.t, erinTap, fabiaTap, closeTxid, + ) + t.Logf("Force close transfer: %v", toProtoJSON(t.t, forceCloseTransfer)) + + // Now that we have the transfer on disk, we'll also assert that the + // universe also has proof for both the relevant transfer outputs. + for _, transfer := range forceCloseTransfer.Transfers { + for _, transferOut := range transfer.Outputs { + assertUniverseProofExists( + t.t, universeTap, transferOut.AssetId, groupKey, + transferOut.ScriptKey, + transferOut.Anchor.Outpoint, + ) + } + } + + t.Logf("Universe proofs located!") + + // We should also have a new sweep transaction in the mempool. + fabiaSweepTxid, err := waitForNTxsInMempool( + net.Miner.Client, 1, shortTimeout, + ) + require.NoError(t.t, err) + + t.Logf("Fabia sweep txid: %v", fabiaSweepTxid) + + mineBlocks(t, net, 1, 1) + + // Fabia should have her sweep output confirmed now, and the assets + // should be back in her on-chain wallet and spendable. + assertSpendableBalance(t.t, fabiaTap, nil, groupKey, totalFirstSend) + + // Next, we'll mine three additional blocks to trigger the CSV delay + // for Erin. + mineBlocks(t, net, 4, 0) + + // We expect that Erin's sweep transaction has been broadcast. + erinSweepTxid, err := waitForNTxsInMempool( + net.Miner.Client, 1, shortTimeout, + ) + require.NoError(t.t, err) + + t.Logf("Erin sweep txid: %v", erinSweepTxid) + + // Now we'll mine a block to confirm Erin's sweep transaction. + mineBlocks(t, net, 1, 1) + + // Charlie should now have an asset transfer for his sweep transaction. + erinSweepTransfer := locateAssetTransfers( + t.t, erinTap, *erinSweepTxid[0], + ) + + t.Logf("Erin sweep transfer: %v", toProtoJSON(t.t, erinSweepTransfer)) + + assertSpendableBalance( + t.t, erinTap, nil, groupKey, fundingAmount-totalFirstSend, + ) +} + +// testCustomChannelsGroupTranchesHtlcForceClose tests that we can successfully +// open a custom channel with multiple pieces of a grouped asset, then force +// close it while having pending HTLCs. We then test that we can successfully +// sweep all balances from those HTLCs. +func testCustomChannelsGroupTranchesHtlcForceClose(ctx context.Context, + net *NetworkHarness, t *harnessTest) { + + lndArgs := slices.Clone(lndArgsTemplate) + litdArgs := slices.Clone(litdArgsTemplate) + + // We use Charlie as the proof courier. But in order for Charlie to also + // use itself, we need to define its port upfront. + charliePort := port.NextAvailablePort() + litdArgs = append(litdArgs, fmt.Sprintf( + "--taproot-assets.proofcourieraddr=%s://%s", + proof.UniverseRpcCourierType, + fmt.Sprintf(node.ListenerFormat, charliePort), + )) + + // The topology we are going for looks like the following: + // + // Charlie --[assets]--> Dave --[sats]--> Erin --[assets]--> Fabia + // + // With [assets] being a custom channel and [sats] being a normal, BTC + // only channel. + charlie, err := net.NewNodeWithPort( + t.t, "Charlie", lndArgs, false, true, charliePort, litdArgs..., + ) + require.NoError(t.t, err) + + dave, err := net.NewNode(t.t, "Dave", lndArgs, false, true, litdArgs...) + require.NoError(t.t, err) + erin, err := net.NewNode(t.t, "Erin", lndArgs, false, true, litdArgs...) + require.NoError(t.t, err) + fabia, err := net.NewNode( + t.t, "Fabia", lndArgs, false, true, litdArgs..., + ) + require.NoError(t.t, err) + + nodes := []*HarnessNode{charlie, dave, erin, fabia} + connectAllNodes(t.t, net, nodes) + fundAllNodes(t.t, net, nodes) + + // Create the normal channel between Dave and Erin. + t.Logf("Opening normal channel between Dave and Erin...") + channelOp := openChannelAndAssert( + t, net, dave, erin, lntest.OpenChannelParams{ + Amt: 5_000_000, + SatPerVByte: 5, + }, + ) + defer closeChannelAndAssert(t, net, dave, channelOp, false) + + // This is the only public channel, we need everyone to be aware of it. + assertChannelKnown(t.t, charlie, channelOp) + assertChannelKnown(t.t, fabia, channelOp) + + universeTap := newTapClient(t.t, charlie) + charlieTap := newTapClient(t.t, charlie) + daveTap := newTapClient(t.t, dave) + erinTap := newTapClient(t.t, erin) + fabiaTap := newTapClient(t.t, fabia) + + groupAssetReq := itest.CopyRequest(&mintrpc.MintAssetRequest{ + Asset: itestAsset, + }) + groupAssetReq.Asset.NewGroupedAsset = true + + // Mint the asset tranches 1 and 2 on Charlie and sync all nodes to + // Charlie as the universe. + mintedAssetsT1 := itest.MintAssetsConfirmBatch( + t.t, t.lndHarness.Miner.Client, charlieTap, + []*mintrpc.MintAssetRequest{groupAssetReq}, + ) + centsT1 := mintedAssetsT1[0] + assetID1 := centsT1.AssetGenesis.AssetId + groupKey := centsT1.GetAssetGroup().GetTweakedGroupKey() + + groupAssetReq = itest.CopyRequest(&mintrpc.MintAssetRequest{ + Asset: itestAsset, + }) + groupAssetReq.Asset.GroupedAsset = true + groupAssetReq.Asset.GroupKey = groupKey + groupAssetReq.Asset.Name = "itest-asset-cents-tranche-2" + + mintedAssetsT2 := itest.MintAssetsConfirmBatch( + t.t, t.lndHarness.Miner.Client, charlieTap, + []*mintrpc.MintAssetRequest{groupAssetReq}, + ) + centsT2 := mintedAssetsT2[0] + assetID2 := centsT2.AssetGenesis.AssetId + + t.Logf("Minted lightning cents tranche 1 (%x) and 2 (%x) for group "+ + "key %x, syncing universes...", assetID1, assetID2, groupKey) + syncUniverses(t.t, charlieTap, dave, erin, fabia) + t.Logf("Universes synced between all nodes, distributing assets...") + + chanPointCD, chanPointEF := createTestAssetNetworkGroupKey( + ctx, t, net, charlieTap, daveTap, erinTap, fabiaTap, + universeTap, []*taprpc.Asset{centsT1, centsT2}, + fundingAmount, fundingAmount, DefaultPushSat, + ) + + t.Logf("Created channels %v and %v", chanPointCD, chanPointEF) + + // We now send some assets over the channels to test the functionality. + // Print initial channel balances. + groupIDs := [][]byte{assetID1, assetID2} + logBalanceGroup(t.t, nodes, groupIDs, "initial") + + // First, we'll send over some funds from Charlie to Dave, as we want + // Dave to be able to extend HTLCs in the other direction. + const ( + numPayments = 10 + keySendAmount = 2_500 + ) + for i := 0; i < numPayments; i++ { + sendAssetKeySendPayment( + t.t, charlie, dave, keySendAmount, nil, + fn.None[int64](), withGroupKey(groupKey), + ) + } + + // Now that both parties have some funds, we'll move onto the main test. + // + // We'll make 2 hodl invoice for each peer, so 4 total. From Charlie's + // PoV, he'll have 6 outgoing HTLCs, and two incoming HTLCs. + var ( + daveHodlInvoices []assetHodlInvoice + charlieHodlInvoices []assetHodlInvoice + + // The default oracle rate is 17_180 mSat/asset unit, so 10_000 + // will be equal to 171_800_000 mSat. When we use the mpp bool + // for the smallShards param of payInvoiceWithAssets, that + // means we'll split the payment into shards of 80_000_000 mSat + // max. So we'll get three shards per payment. + assetInvoiceAmt = 10_000 + assetsPerMPPShard = 4656 + ) + for i := 0; i < 2; i++ { + daveHodlInvoices = append( + daveHodlInvoices, createAssetHodlInvoice( + t.t, charlie, dave, uint64(assetInvoiceAmt), + nil, withInvGroupKey(groupKey), + ), + ) + charlieHodlInvoices = append( + charlieHodlInvoices, createAssetHodlInvoice( + t.t, dave, charlie, uint64(assetInvoiceAmt), + nil, withInvGroupKey(groupKey), + ), + ) + } + + // Now we'll have both Dave and Charlie pay each other's invoices. We + // only care that they're in flight at this point, as they won't be + // settled yet. + baseOpts := []payOpt{ + withGroupKey(groupKey), + withFailure( + lnrpc.Payment_IN_FLIGHT, + lnrpc.PaymentFailureReason_FAILURE_REASON_NONE, + ), + } + for _, charlieInvoice := range charlieHodlInvoices { + // For this direction, we also want to enforce MPP. + opts := append(slices.Clone(baseOpts), withSmallShards()) + payInvoiceWithAssets( + t.t, dave, charlie, charlieInvoice.payReq, nil, opts..., + ) + } + for _, daveInvoice := range daveHodlInvoices { + payInvoiceWithAssets( + t.t, charlie, dave, daveInvoice.payReq, nil, + baseOpts..., + ) + } + + // Make sure we can sweep all the HTLCs. + const charlieStartAmount = 2 + charlieExpectedBalance, _ := assertForceCloseSweeps( + ctx, net, t, charlie, dave, chanPointCD, charlieStartAmount, + assetInvoiceAmt, assetsPerMPPShard, nil, groupKey, + charlieHodlInvoices, daveHodlInvoices, true, + ) + + // Finally, we'll assert that Charlie's balance has been incremented by + // the timeout value. + charlieExpectedBalance += uint64(assetInvoiceAmt - 1) + t.Logf("Expecting Charlie's balance to be %d", charlieExpectedBalance) + assertSpendableBalance( + t.t, charlieTap, nil, groupKey, charlieExpectedBalance, + ) + + t.Logf("Sending all settled funds to Fabia") + + // As a final sanity check, both Charlie and Dave should be able to send + // their entire balances to Fabia, our 3rd party. + // + // We'll make two addrs for Fabia, one for Charlie, and one for Dave. + charlieSpendableBalanceAsset1, err := spendableBalance( + charlieTap, assetID1, nil, + ) + require.NoError(t.t, err) + charlieSpendableBalanceAsset2, err := spendableBalance( + charlieTap, assetID2, nil, + ) + require.NoError(t.t, err) + + t.Logf("Charlie's spendable balance asset 1: %d, asset 2: %d", + charlieSpendableBalanceAsset1, charlieSpendableBalanceAsset2) + + fabiaCourierAddr := fmt.Sprintf( + "%s://%s", proof.UniverseRpcCourierType, + fabiaTap.node.Cfg.LitAddr(), + ) + charlieAddr1, err := fabiaTap.NewAddr(ctx, &taprpc.NewAddrRequest{ + Amt: charlieSpendableBalanceAsset1, + AssetId: assetID1, + ProofCourierAddr: fabiaCourierAddr, + }) + require.NoError(t.t, err) + charlieAddr2, err := fabiaTap.NewAddr(ctx, &taprpc.NewAddrRequest{ + Amt: charlieSpendableBalanceAsset2, + AssetId: assetID2, + ProofCourierAddr: fabiaCourierAddr, + }) + require.NoError(t.t, err) + + daveSpendableBalanceAsset1, err := spendableBalance( + daveTap, assetID1, nil, + ) + require.NoError(t.t, err) + daveSpendableBalanceAsset2, err := spendableBalance( + daveTap, assetID2, nil, + ) + require.NoError(t.t, err) + + t.Logf("Daves's spendable balance asset 1: %d, asset 2: %d", + daveSpendableBalanceAsset1, daveSpendableBalanceAsset2) + + daveAddr1, err := fabiaTap.NewAddr(ctx, &taprpc.NewAddrRequest{ + Amt: daveSpendableBalanceAsset1, + AssetId: assetID1, + ProofCourierAddr: fabiaCourierAddr, + }) + require.NoError(t.t, err) + daveAddr2, err := fabiaTap.NewAddr(ctx, &taprpc.NewAddrRequest{ + Amt: daveSpendableBalanceAsset2, + AssetId: assetID2, + ProofCourierAddr: fabiaCourierAddr, + }) + require.NoError(t.t, err) + + _, err = charlieTap.SendAsset(ctx, &taprpc.SendAssetRequest{ + TapAddrs: []string{charlieAddr1.Encoded}, + }) + require.NoError(t.t, err) + mineBlocks(t, net, 1, 1) + + itest.AssertNonInteractiveRecvComplete(t.t, fabiaTap, 1) + + ctxb := context.Background() + charlieAssets, err := charlieTap.ListAssets( + ctxb, &taprpc.ListAssetRequest{ + IncludeSpent: true, + }, + ) + require.NoError(t.t, err) + charlieTransfers, err := charlieTap.ListTransfers( + ctxb, &taprpc.ListTransfersRequest{}, + ) + require.NoError(t.t, err) + + t.Logf("Charlie's assets: %v", toProtoJSON(t.t, charlieAssets)) + t.Logf("Charlie's transfers: %v", toProtoJSON(t.t, charlieTransfers)) + + _, err = charlieTap.SendAsset(ctx, &taprpc.SendAssetRequest{ + TapAddrs: []string{charlieAddr2.Encoded}, + }) + require.NoError(t.t, err) + mineBlocks(t, net, 1, 1) + + itest.AssertNonInteractiveRecvComplete(t.t, fabiaTap, 2) + + _, err = daveTap.SendAsset(ctx, &taprpc.SendAssetRequest{ + TapAddrs: []string{daveAddr1.Encoded}, + }) + require.NoError(t.t, err) + mineBlocks(t, net, 1, 1) + + itest.AssertNonInteractiveRecvComplete(t.t, fabiaTap, 3) + + _, err = daveTap.SendAsset(ctx, &taprpc.SendAssetRequest{ + TapAddrs: []string{daveAddr2.Encoded}, + }) + require.NoError(t.t, err) + mineBlocks(t, net, 1, 1) + + itest.AssertNonInteractiveRecvComplete(t.t, fabiaTap, 4) + + // Fabia's balance should now be the sum of Charlie's and Dave's + // balances. + fabiaExpectedBalance := uint64(50_002) + assertSpendableBalance( + t.t, fabiaTap, nil, groupKey, fabiaExpectedBalance, + ) +} + // testCustomChannelsForceClose tests a force close scenario after both parties // have an active asset balance. func testCustomChannelsForceClose(ctx context.Context, net *NetworkHarness, @@ -1292,7 +1816,9 @@ func testCustomChannelsForceClose(ctx context.Context, net *NetworkHarness, ) // Make sure the channel shows the correct asset information. - assertAssetChan(t.t, charlie, dave, fundingAmount, cents) + assertAssetChan( + t.t, charlie, dave, fundingAmount, []*taprpc.Asset{cents}, + ) // Before we start sending out payments, let's make sure each node can // see the other one in the graph and has all required features. @@ -1347,40 +1873,9 @@ func testCustomChannelsForceClose(ctx context.Context, net *NetworkHarness, // At this point, we should have the force close transaction in the set // of transfers for both nodes. - var forceCloseTransfer *taprpc.ListTransfersResponse - fErr := wait.NoError(func() error { - forceCloseTransfer, err = charlieTap.ListTransfers( - ctx, &taprpc.ListTransfersRequest{ - AnchorTxid: closeTxid.String(), - }, - ) - if err != nil { - return fmt.Errorf("unable to list charlie transfers: "+ - "%w", err) - } - if len(forceCloseTransfer.Transfers) != 1 { - return fmt.Errorf("charlie is missing force close " + - "transfer") - } - - forceCloseTransfer2, err := daveTap.ListTransfers( - ctx, &taprpc.ListTransfersRequest{ - AnchorTxid: closeTxid.String(), - }, - ) - if err != nil { - return fmt.Errorf("unable to list dave transfers: %w", - err) - } - if len(forceCloseTransfer2.Transfers) != 1 { - return fmt.Errorf("dave is missing force close " + - "transfer") - } - - return nil - }, defaultTimeout) - require.NoError(t.t, fErr) - + forceCloseTransfer := findForceCloseTransfer( + t.t, charlieTap, daveTap, closeTxid, + ) t.Logf("Force close transfer: %v", toProtoJSON(t.t, forceCloseTransfer)) // Now that we have the transfer on disk, we'll also assert that the @@ -1513,25 +2008,18 @@ func testCustomChannelsForceClose(ctx context.Context, net *NetworkHarness, // testCustomChannelsBreach tests a force close scenario that breaches an old // state, after both parties have an active asset balance. func testCustomChannelsBreach(ctx context.Context, net *NetworkHarness, - t *harnessTest) { - - lndArgs := slices.Clone(lndArgsTemplate) - litdArgs := slices.Clone(litdArgsTemplate) - - // Explicitly set the proof courier as Zane (now has no other role - // other than proof shuffling), otherwise a hashmail courier will be - // used. For the funding transaction, we're just posting it and don't - // expect a true receiver. - zane, err := net.NewNode( - t.t, "Zane", lndArgs, false, true, litdArgs..., - ) - require.NoError(t.t, err) + t *harnessTest) { - // For our litd args, make sure that they all seen Zane as the main - // Universe server. + lndArgs := slices.Clone(lndArgsTemplate) + litdArgs := slices.Clone(litdArgsTemplate) + + // We use Charlie as the proof courier. But in order for Charlie to also + // use itself, we need to define its port upfront. + charliePort := port.NextAvailablePort() litdArgs = append(litdArgs, fmt.Sprintf( "--taproot-assets.proofcourieraddr=%s://%s", - proof.UniverseRpcCourierType, zane.Cfg.LitAddr(), + proof.UniverseRpcCourierType, + fmt.Sprintf(node.ListenerFormat, charliePort), )) // Charlie will be the breached party. We set --nolisten to ensure Dave @@ -1545,8 +2033,9 @@ func testCustomChannelsBreach(ctx context.Context, net *NetworkHarness, // For this simple test, we'll just have Carol -> Dave as an assets // channel. - charlie, err := net.NewNode( - t.t, "Charlie", charlieFlags, false, true, litdArgs..., + charlie, err := net.NewNodeWithPort( + t.t, "Charlie", charlieFlags, false, true, charliePort, + litdArgs..., ) require.NoError(t.t, err) @@ -1558,7 +2047,7 @@ func testCustomChannelsBreach(ctx context.Context, net *NetworkHarness, connectAllNodes(t.t, net, nodes) fundAllNodes(t.t, net, nodes) - universeTap := newTapClient(t.t, zane) + universeTap := newTapClient(t.t, charlie) charlieTap := newTapClient(t.t, charlie) daveTap := newTapClient(t.t, dave) @@ -1626,7 +2115,9 @@ func testCustomChannelsBreach(ctx context.Context, net *NetworkHarness, ) // Make sure the channel shows the correct asset information. - assertAssetChan(t.t, charlie, dave, fundingAmount, cents) + assertAssetChan( + t.t, charlie, dave, fundingAmount, []*taprpc.Asset{cents}, + ) // Before we start sending out payments, let's make sure each node can // see the other one in the graph and has all required features. @@ -1740,18 +2231,13 @@ func testCustomChannelsLiquidtyEdgeCasesCore(ctx context.Context, lndArgs := slices.Clone(lndArgsTemplate) litdArgs := slices.Clone(litdArgsTemplate) - // Explicitly set the proof courier as Zane (now has no other role - // other than proof shuffling), otherwise a hashmail courier will be - // used. For the funding transaction, we're just posting it and don't - // expect a true receiver. - zane, err := net.NewNode( - t.t, "Zane", lndArgs, false, true, litdArgs..., - ) - require.NoError(t.t, err) - + // We use Charlie as the proof courier. But in order for Charlie to also + // use itself, we need to define its port upfront. + charliePort := port.NextAvailablePort() litdArgs = append(litdArgs, fmt.Sprintf( "--taproot-assets.proofcourieraddr=%s://%s", - proof.UniverseRpcCourierType, zane.Cfg.LitAddr(), + proof.UniverseRpcCourierType, + fmt.Sprintf(node.ListenerFormat, charliePort), )) // The topology we are going for looks like the following: @@ -1770,8 +2256,8 @@ func testCustomChannelsLiquidtyEdgeCasesCore(ctx context.Context, // with tapd included. We also need specific flags to be enabled, so we // create 5 completely new nodes, ignoring the two default nodes that // are created by the harness. - charlie, err := net.NewNode( - t.t, "Charlie", lndArgs, false, true, litdArgs..., + charlie, err := net.NewNodeWithPort( + t.t, "Charlie", lndArgs, false, true, charliePort, litdArgs..., ) require.NoError(t.t, err) @@ -1808,7 +2294,7 @@ func testCustomChannelsLiquidtyEdgeCasesCore(ctx context.Context, assertChannelKnown(t.t, charlie, channelOp) assertChannelKnown(t.t, fabia, channelOp) - universeTap := newTapClient(t.t, zane) + universeTap := newTapClient(t.t, charlie) charlieTap := newTapClient(t.t, charlie) daveTap := newTapClient(t.t, dave) erinTap := newTapClient(t.t, erin) @@ -2268,18 +2754,13 @@ func testCustomChannelsStrictForwarding(ctx context.Context, lndArgs := slices.Clone(lndArgsTemplate) litdArgs := slices.Clone(litdArgsTemplate) - // Explicitly set the proof courier as Zane (now has no other role - // other than proof shuffling), otherwise a hashmail courier will be - // used. For the funding transaction, we're just posting it and don't - // expect a true receiver. - zane, err := net.NewNode( - t.t, "Zane", lndArgs, false, true, litdArgs..., - ) - require.NoError(t.t, err) - + // We use Charlie as the proof courier. But in order for Charlie to also + // use itself, we need to define its port upfront. + charliePort := port.NextAvailablePort() litdArgs = append(litdArgs, fmt.Sprintf( "--taproot-assets.proofcourieraddr=%s://%s", - proof.UniverseRpcCourierType, zane.Cfg.LitAddr(), + proof.UniverseRpcCourierType, + fmt.Sprintf(node.ListenerFormat, charliePort), )) // The topology we are going for looks like the following: @@ -2298,8 +2779,8 @@ func testCustomChannelsStrictForwarding(ctx context.Context, // with tapd included. We also need specific flags to be enabled, so we // create 5 completely new nodes, ignoring the two default nodes that // are created by the harness. - charlie, err := net.NewNode( - t.t, "Charlie", lndArgs, false, true, litdArgs..., + charlie, err := net.NewNodeWithPort( + t.t, "Charlie", lndArgs, false, true, charliePort, litdArgs..., ) require.NoError(t.t, err) @@ -2334,7 +2815,7 @@ func testCustomChannelsStrictForwarding(ctx context.Context, assertChannelKnown(t.t, charlie, channelOp) assertChannelKnown(t.t, fabia, channelOp) - universeTap := newTapClient(t.t, zane) + universeTap := newTapClient(t.t, charlie) charlieTap := newTapClient(t.t, charlie) daveTap := newTapClient(t.t, dave) erinTap := newTapClient(t.t, erin) @@ -2480,22 +2961,17 @@ func testCustomChannelsBalanceConsistency(ctx context.Context, lndArgs := slices.Clone(lndArgsTemplate) litdArgs := slices.Clone(litdArgsTemplate) - // Explicitly set the proof courier as Zane (now has no other role - // other than proof shuffling), otherwise a hashmail courier will be - // used. For the funding transaction, we're just posting it and don't - // expect a true receiver. - zane, err := net.NewNode( - t.t, "Zane", lndArgs, false, true, litdArgs..., - ) - require.NoError(t.t, err) - + // We use Charlie as the proof courier. But in order for Charlie to also + // use itself, we need to define its port upfront. + charliePort := port.NextAvailablePort() litdArgs = append(litdArgs, fmt.Sprintf( "--taproot-assets.proofcourieraddr=%s://%s", - proof.UniverseRpcCourierType, zane.Cfg.LitAddr(), + proof.UniverseRpcCourierType, + fmt.Sprintf(node.ListenerFormat, charliePort), )) - charlie, err := net.NewNode( - t.t, "Charlie", lndArgs, false, true, litdArgs..., + charlie, err := net.NewNodeWithPort( + t.t, "Charlie", lndArgs, false, true, charliePort, litdArgs..., ) require.NoError(t.t, err) dave, err := net.NewNode(t.t, "Dave", lndArgs, false, true, litdArgs...) @@ -2507,7 +2983,7 @@ func testCustomChannelsBalanceConsistency(ctx context.Context, charlieTap := newTapClient(t.t, charlie) daveTap := newTapClient(t.t, dave) - universeTap := newTapClient(t.t, zane) + universeTap := newTapClient(t.t, charlie) // Mint an asset on Charlie and sync Dave to Charlie as the universe. mintedAssets := itest.MintAssetsConfirmBatch( @@ -2603,7 +3079,8 @@ func testCustomChannelsBalanceConsistency(ctx context.Context, // Make sure the channel shows the correct asset information. assertAssetChan( - t.t, charlieTap.node, daveTap.node, charlieBalance, cents, + t.t, charlieTap.node, daveTap.node, charlieBalance, + []*taprpc.Asset{cents}, ) logBalance(t.t, nodes, assetID, "initial") @@ -2679,18 +3156,17 @@ func testCustomChannelsSingleAssetMultiInput(ctx context.Context, lndArgs := slices.Clone(lndArgsTemplate) litdArgs := slices.Clone(litdArgsTemplate) - zane, err := net.NewNode( - t.t, "Zane", lndArgs, false, true, litdArgs..., - ) - require.NoError(t.t, err) - + // We use Charlie as the proof courier. But in order for Charlie to also + // use itself, we need to define its port upfront. + charliePort := port.NextAvailablePort() litdArgs = append(litdArgs, fmt.Sprintf( "--taproot-assets.proofcourieraddr=%s://%s", - proof.UniverseRpcCourierType, zane.Cfg.LitAddr(), + proof.UniverseRpcCourierType, + fmt.Sprintf(node.ListenerFormat, charliePort), )) - charlie, err := net.NewNode( - t.t, "Charlie", lndArgs, false, true, litdArgs..., + charlie, err := net.NewNodeWithPort( + t.t, "Charlie", lndArgs, false, true, charliePort, litdArgs..., ) require.NoError(t.t, err) dave, err := net.NewNode(t.t, "Dave", lndArgs, false, true, litdArgs...) @@ -2786,7 +3262,8 @@ func testCustomChannelsSingleAssetMultiInput(ctx context.Context, // Make sure the channel shows the correct asset information. assertAssetChan( - t.t, charlieTap.node, daveTap.node, 2*halfCentsAmount, cents, + t.t, charlieTap.node, daveTap.node, 2*halfCentsAmount, + []*taprpc.Asset{cents}, ) } @@ -2825,18 +3302,13 @@ func testCustomChannelsOraclePricing(ctx context.Context, net *NetworkHarness, "rfqrpc://%s", oracleAddr, )) - // Explicitly set the proof courier as Zane (now has no other role - // other than proof shuffling), otherwise a hashmail courier will be - // used. For the funding transaction, we're just posting it and don't - // expect a true receiver. - zane, err := net.NewNode( - t.t, "Zane", lndArgs, false, true, litdArgs..., - ) - require.NoError(t.t, err) - + // We use Charlie as the proof courier. But in order for Charlie to also + // use itself, we need to define its port upfront. + charliePort := port.NextAvailablePort() litdArgs = append(litdArgs, fmt.Sprintf( "--taproot-assets.proofcourieraddr=%s://%s", - proof.UniverseRpcCourierType, zane.Cfg.LitAddr(), + proof.UniverseRpcCourierType, + fmt.Sprintf(node.ListenerFormat, charliePort), )) // The topology we are going for looks like the following: @@ -2855,8 +3327,8 @@ func testCustomChannelsOraclePricing(ctx context.Context, net *NetworkHarness, // with tapd included. We also need specific flags to be enabled, so we // create 5 completely new nodes, ignoring the two default nodes that // are created by the harness. - charlie, err := net.NewNode( - t.t, "Charlie", lndArgs, false, true, litdArgs..., + charlie, err := net.NewNodeWithPort( + t.t, "Charlie", lndArgs, false, true, charliePort, litdArgs..., ) require.NoError(t.t, err) @@ -2892,7 +3364,7 @@ func testCustomChannelsOraclePricing(ctx context.Context, net *NetworkHarness, assertChannelKnown(t.t, charlie, chanPointDE) assertChannelKnown(t.t, fabia, chanPointDE) - universeTap := newTapClient(t.t, zane) + universeTap := newTapClient(t.t, charlie) charlieTap := newTapClient(t.t, charlie) daveTap := newTapClient(t.t, dave) erinTap := newTapClient(t.t, erin) @@ -3086,20 +3558,20 @@ func testCustomChannelsOraclePricing(ctx context.Context, net *NetworkHarness, t.Logf("Closing Charlie -> Dave channel") closeAssetChannelAndAssert( - t, net, charlie, dave, chanPointCD, assetID, nil, universeTap, - noOpCoOpCloseBalanceCheck, + t, net, charlie, dave, chanPointCD, [][]byte{assetID}, nil, + universeTap, noOpCoOpCloseBalanceCheck, ) t.Logf("Closing Dave -> Yara channel, close initiated by Yara") closeAssetChannelAndAssert( - t, net, yara, dave, chanPointDY, assetID, nil, universeTap, - noOpCoOpCloseBalanceCheck, + t, net, yara, dave, chanPointDY, [][]byte{assetID}, nil, + universeTap, noOpCoOpCloseBalanceCheck, ) t.Logf("Closing Erin -> Fabia channel") closeAssetChannelAndAssert( - t, net, erin, fabia, chanPointEF, assetID, nil, universeTap, - noOpCoOpCloseBalanceCheck, + t, net, erin, fabia, chanPointEF, [][]byte{assetID}, nil, + universeTap, noOpCoOpCloseBalanceCheck, ) } @@ -3111,18 +3583,17 @@ func testCustomChannelsFee(ctx context.Context, net *NetworkHarness, lndArgs := slices.Clone(lndArgsTemplate) litdArgs := slices.Clone(litdArgsTemplate) - zane, err := net.NewNode( - t.t, "Zane", lndArgs, false, true, litdArgs..., - ) - require.NoError(t.t, err) - + // We use Charlie as the proof courier. But in order for Charlie to also + // use itself, we need to define its port upfront. + charliePort := port.NextAvailablePort() litdArgs = append(litdArgs, fmt.Sprintf( "--taproot-assets.proofcourieraddr=%s://%s", - proof.UniverseRpcCourierType, zane.Cfg.LitAddr(), + proof.UniverseRpcCourierType, + fmt.Sprintf(node.ListenerFormat, charliePort), )) - charlie, err := net.NewNode( - t.t, "Charlie", lndArgs, false, true, litdArgs..., + charlie, err := net.NewNodeWithPort( + t.t, "Charlie", lndArgs, false, true, charliePort, litdArgs..., ) require.NoError(t.t, err) dave, err := net.NewNode(t.t, "Dave", lndArgs, false, true, litdArgs...) @@ -3273,6 +3744,14 @@ func runCustomChannelsHtlcForceClose(ctx context.Context, t *harnessTest, }, ) require.NoError(t.t, err) + + aliceChanPoint := &lnrpc.ChannelPoint{ + OutputIndex: uint32(assetFundResp.OutputIndex), + FundingTxid: &lnrpc.ChannelPoint_FundingTxidStr{ + FundingTxidStr: assetFundResp.Txid, + }, + } + t.Logf("Funded channel between Alice and Bob: %v", assetFundResp) // With the channel open, mine a block to confirm it. @@ -3355,404 +3834,20 @@ func runCustomChannelsHtlcForceClose(ctx context.Context, t *harnessTest, ) } - // At this point, both sides should have 4 (or +4 with MPP) HTLCs - // active. - numHtlcs := 4 - numAdditionalShards := assetInvoiceAmt / assetsPerMPPShard - if mpp { - numHtlcs += numAdditionalShards * 2 - } - t.Logf("Asserting both Alice and Bob have %d HTLCs...", numHtlcs) - assertNumHtlcs(t.t, alice, numHtlcs) - assertNumHtlcs(t.t, bob, numHtlcs) - - // Before we force close, we'll grab the current height, the CSV delay - // needed, and also the absolute timeout of the set of active HTLCs. - closeExpiryInfo := newCloseExpiryInfo(t.t, alice) - - // With all of the HTLCs established, we'll now force close the channel - // with Alice. - t.Logf("Force close by Alice w/ HTLCs...") - aliceChanPoint := &lnrpc.ChannelPoint{ - OutputIndex: uint32(assetFundResp.OutputIndex), - FundingTxid: &lnrpc.ChannelPoint_FundingTxidStr{ - FundingTxidStr: assetFundResp.Txid, - }, - } - _, closeTxid, err := net.CloseChannel(alice, aliceChanPoint, true) - require.NoError(t.t, err) - - t.Logf("Channel closed! Mining blocks, close_txid=%v", closeTxid) - - // The channel should first be in "waiting close" until it confirms. - assertWaitingCloseChannelAssetData(t.t, alice, aliceChanPoint) - - // Next, we'll mine a block which should start the clock ticking on the - // relative timeout for the Alice, and Bob. - // - // After this next block, both of them can start to sweep. - // - // For Alice, she'll go to the second level, revealing her preimage in - // the process. She'll then need to wait for the relative timeout to - // expire before she can sweep her output. - // - // For Bob, since the remote party (Alice) closed, he can try to sweep - // right away after initial confirmation. - mineBlocks(t, net, 1, 1) - - // After force closing, Bob should now have a transfer that tracks the - // force closed commitment transaction. - locateAssetTransfers(t.t, bobTap, *closeTxid) - - t.Logf("Settling Bob's hodl invoice") - - // It should then go to "pending force closed". - assertPendingForceCloseChannelAssetData(t.t, alice, aliceChanPoint) - - // At this point, the commitment transaction has been mined, and we have - // 4 total HTLCs on Alice's commitment transaction: - // - // * 2x outgoing HTLCs from Alice to Bob - // * 2x incoming HTLCs from Bob to Alice (+2 with MPP) - // - // We'll leave half the HTLCs timeout, while pulling the other half. - // To start, we'll signal Bob to settle one of his incoming HTLCs on - // Alice's commitment transaction. For him, this is a remote success - // spend, so there's no CSV delay other than the 1 CSV (carve out), and - // he can spend directly from the commitment transaction. - _, err = bob.InvoicesClient.SettleInvoice( - ctx, &invoicesrpc.SettleInvoiceMsg{ - Preimage: bobHodlInvoices[0].preimage[:], - }, - ) - require.NoError(t.t, err) - - // We'll pause here for Bob to extend the sweep request to the sweeper. - assertSweepExists( - t.t, bob, - walletrpc.WitnessType_TAPROOT_HTLC_ACCEPTED_REMOTE_SUCCESS, - ) - - bobSweepTx1, err := waitForNTxsInMempool( - net.Miner.Client, 1, shortTimeout, - ) - require.NoError(t.t, err) - - // Next, we'll mine an additional block, this should allow Bob to sweep - // both his commitment output, and the incoming HTLC that we just - // settled above. - mineBlocks(t, net, 1, 1) - - // At this point, we should have the next sweep transaction in the - // mempool: Bob's incoming HTLC sweep directly off the commitment - // transaction. - bobSweepTx2, err := waitForNTxsInMempool( - net.Miner.Client, 1, shortTimeout, - ) - require.NoError(t.t, err) - - // We'll now mine the next block, which should confirm Bob's HTLC sweep - // transaction. - mineBlocks(t, net, 1, 1) - - bobSweepTransfer1 := locateAssetTransfers(t.t, bobTap, *bobSweepTx1[0]) - bobSweepTransfer2 := locateAssetTransfers(t.t, bobTap, *bobSweepTx2[0]) - t.Logf("Bob's sweep transfer 1: %v", - toProtoJSON(t.t, bobSweepTransfer1)) - t.Logf("Bob's sweep transfer 2: %v", - toProtoJSON(t.t, bobSweepTransfer2)) - - t.Logf("Confirming Bob's remote HTLC success sweep") - - // Bob's balance should now reflect that he's gained the value of the - // HTLC, in addition to his settled balance. We need to subtract 1 from - // the final balance due to the rounding down of the asset amount during - // RFQ conversion. - bobExpectedBalance := closeExpiryInfo.remoteAssetBalance + - uint64(assetInvoiceAmt-1) - t.Logf("Expecting Bob's balance to be %d", bobExpectedBalance) - assertSpendableBalance(t.t, bobTap, assetID, bobExpectedBalance) - - // With Bob's HTLC settled, we'll now have Alice do the same. For her, - // it'll be a 2nd level sweep, which requires an extra transaction. - // - // Before, we do that though, enough blocks have passed so Alice can now - // sweep her to-local output. So we'll mine an extra block, then assert - // that she's swept everything properly. With the way the sweeper works, - // we need to mine one extra block before the sweeper picks things up. - mineBlocks(t, net, 1, 0) - - aliceSweepTx1, err := waitForNTxsInMempool( - net.Miner.Client, 1, shortTimeout, - ) - require.NoError(t.t, err) - - mineBlocks(t, net, 1, 1) - - aliceSweepTransfer1 := locateAssetTransfers( - t.t, aliceTap, *aliceSweepTx1[0], - ) - t.Logf("Alice's sweep transfer 1: %v", - toProtoJSON(t.t, aliceSweepTransfer1)) - - t.Logf("Confirming Alice's to-local sweep") - - // With this extra block mined, Alice's settled balance should be the - // starting balance, minus the 2 HTLCs, plus her settled balance. - aliceExpectedBalance := itestAsset.Amount - fundingAmount - aliceExpectedBalance += closeExpiryInfo.localAssetBalance - assertSpendableBalance( - t.t, aliceTap, assetID, aliceExpectedBalance, - ) - - t.Logf("Settling Alice's hodl invoice") - - // With her commitment output swept above, we'll now settle one of - // Alice's incoming HTLCs. - _, err = alice.InvoicesClient.SettleInvoice( - ctx, &invoicesrpc.SettleInvoiceMsg{ - Preimage: aliceHodlInvoices[0].preimage[:], - }, - ) - require.NoError(t.t, err) - - // We'll pause here for Alice to extend the sweep request to the - // sweeper. - assertSweepExists( - t.t, alice, - walletrpc.WitnessType_TAPROOT_HTLC_ACCEPTED_LOCAL_SUCCESS, - ) - - // We'll now mine a block, which should trigger Alice's broadcast of the - // second level sweep transaction. - sweepBlocks := mineBlocks(t, net, 1, 0) - - // If the block mined above didn't also mine our sweep, then we'll mine - // one final block which will confirm Alice's sweep transaction. - if len(sweepBlocks[0].Transactions) == 1 { - sweepTx, err := waitForNTxsInMempool( - net.Miner.Client, 1, shortTimeout, - ) - require.NoError(t.t, err) - - // With the sweep transaction in the mempool, we'll mine a block - // to confirm the sweep. - mineBlocks(t, net, 1, 1) - - aliceSweepTransfer := locateAssetTransfers( - t.t, aliceTap, *sweepTx[0], - ) - t.Logf("Alice's first-level sweep transfer: %v", - toProtoJSON(t.t, aliceSweepTransfer)) - } else { - sweepTx := sweepBlocks[0].Transactions[1] - aliceSweepTransfer := locateAssetTransfers( - t.t, aliceTap, sweepTx.TxHash(), - ) - t.Logf("Alice's first-level sweep transfer: %v", - toProtoJSON(t.t, aliceSweepTransfer)) - } - - t.Logf("Confirming Alice's second level remote HTLC success sweep") - - // Next, we'll mine enough blocks to trigger the CSV expiry so Alice can - // sweep the HTLC into her wallet. - mineBlocks(t, net, closeExpiryInfo.csvDelay, 0) - - // We'll pause here and wait until the sweeper recognizes that we've - // offered the second level sweep transaction. - assertSweepExists( - t.t, alice, - //nolint: lll - walletrpc.WitnessType_TAPROOT_HTLC_ACCEPTED_SUCCESS_SECOND_LEVEL, - ) - - t.Logf("Confirming Alice's local HTLC success sweep") - - // Now that we know the sweep was offered, we'll mine an extra block to - // actually trigger a sweeper broadcast. Due to an internal block race - // condition, the sweep transaction may have already been - // published+mined. If so, we don't need to mine the extra block. - sweepBlocks = mineBlocks(t, net, 1, 0) - - // If the block mined above didn't also mine our sweep, then we'll mine - // one final block which will confirm Alice's sweep transaction. - if len(sweepBlocks[0].Transactions) == 1 { - sweepTx, err := waitForNTxsInMempool( - net.Miner.Client, 1, shortTimeout, - ) - require.NoError(t.t, err) - - mineBlocks(t, net, 1, 1) - - aliceSweepTransfer := locateAssetTransfers( - t.t, aliceTap, *sweepTx[0], - ) - t.Logf("Alice's second-level sweep transfer: %v", - toProtoJSON(t.t, aliceSweepTransfer)) - } else { - sweepTx := sweepBlocks[0].Transactions[1] - aliceSweepTransfer := locateAssetTransfers( - t.t, aliceTap, sweepTx.TxHash(), - ) - t.Logf("Alice's second-level sweep transfer: %v", - toProtoJSON(t.t, aliceSweepTransfer)) - } - - // With the sweep transaction confirmed, Alice's balance should have - // incremented by the amt of the HTLC. - aliceExpectedBalance += uint64(assetInvoiceAmt - 1) - assertSpendableBalance( - t.t, aliceTap, assetID, aliceExpectedBalance, - ) - - t.Logf("Mining enough blocks to time out the remaining HTLCs") - - // At this point, we've swept two HTLCs: one from the remote commit, and - // one via the second layer. We'll now mine the remaining amount of - // blocks to time out the HTLCs. - blockToMine := closeExpiryInfo.blockTillExpiry( - aliceHodlInvoices[1].preimage.Hash(), - ) - mineBlocks(t, net, blockToMine, 0) - - // We'll wait for both Alice and Bob to present their respective sweeps - // to the sweeper. - numTimeoutHTLCs := 1 - if mpp { - numTimeoutHTLCs += numAdditionalShards - } - assertSweepExists( - t.t, alice, - walletrpc.WitnessType_TAPROOT_HTLC_LOCAL_OFFERED_TIMEOUT, - ) - assertSweepExists( - t.t, bob, - walletrpc.WitnessType_TAPROOT_HTLC_OFFERED_REMOTE_TIMEOUT, - ) - - t.Logf("Confirming initial HTLC timeout txns") - - timeoutSweeps, err := waitForNTxsInMempool( - net.Miner.Client, 2, shortTimeout, - ) - require.NoError(t.t, err) - - t.Logf("Asserting balance on sweeps: %v", timeoutSweeps) - - // Finally, we'll mine a single block to confirm them. - mineBlocks(t, net, 1, 2) - - // Make sure Bob swept all his HTLCs. - bobSweeps, err := bob.WalletKitClient.ListSweeps( - ctx, &walletrpc.ListSweepsRequest{ - Verbose: true, - }, - ) - require.NoError(t.t, err) - - var bobSweepTx *wire.MsgTx - for _, sweep := range bobSweeps.GetTransactionDetails().Transactions { - for _, tx := range timeoutSweeps { - if sweep.TxHash == tx.String() { - txBytes, err := hex.DecodeString(sweep.RawTxHex) - require.NoError(t.t, err) - - bobSweepTx = &wire.MsgTx{} - err = bobSweepTx.Deserialize( - bytes.NewReader(txBytes), - ) - require.NoError(t.t, err) - } - } - } - require.NotNil(t.t, bobSweepTx, "Bob's sweep transaction not found") - - // There's always an extra input that pays for the fees. So we can only - // count the remainder as HTLC inputs. - numSweptHTLCs := len(bobSweepTx.TxIn) - 1 - - // If we didn't yet sweep all HTLCs, then we need to wait for another - // sweep. - if numSweptHTLCs < numTimeoutHTLCs { - assertSweepExists( - t.t, bob, - // nolint: lll - walletrpc.WitnessType_TAPROOT_HTLC_OFFERED_REMOTE_TIMEOUT, - ) - - t.Logf("Confirming additional HTLC timeout sweep txns") - - additionalTimeoutSweeps, err := waitForNTxsInMempool( - net.Miner.Client, 1, shortTimeout, - ) - require.NoError(t.t, err) - - t.Logf("Asserting balance on additional timeout sweeps: %v", - additionalTimeoutSweeps) - - // Finally, we'll mine a single block to confirm them. - mineBlocks(t, net, 1, 1) - } - - // At this point, Bob's balance should be incremented by an additional - // HTLC value. - bobExpectedBalance += uint64(assetInvoiceAmt - 1) - assertSpendableBalance( - t.t, bobTap, assetID, bobExpectedBalance, - ) - - t.Logf("Mining extra blocks for Alice's CSV to expire on 2nd level txn") - - // Next, we'll mine 4 additional blocks to Alice's CSV delay expires for - // the second level timeout output. - mineBlocks(t, net, closeExpiryInfo.csvDelay, 0) - - // Wait for Alice to extend the second level output to the sweeper - // before we mine the next block to the sweeper. - assertSweepExists( - t.t, alice, - walletrpc.WitnessType_TAPROOT_HTLC_OFFERED_TIMEOUT_SECOND_LEVEL, + // Make sure we can sweep all the HTLCs. + aliceExpectedBalance, bobExpectedBalance := assertForceCloseSweeps( + ctx, net, t, alice, bob, aliceChanPoint, + itestAsset.Amount-fundingAmount, assetInvoiceAmt, + assetsPerMPPShard, assetID, nil, aliceHodlInvoices, + bobHodlInvoices, mpp, ) - t.Logf("Confirming Alice's final timeout sweep") - - // With the way the sweeper works, we'll now need to mine an extra block - // to trigger the sweep. - sweepBlocks = mineBlocks(t, net, 1, 0) - - // If the block mined above didn't also mine our sweep, then we'll mine - // one final block which will confirm Alice's sweep transaction. - if len(sweepBlocks[0].Transactions) == 1 { - sweepTx, err := waitForNTxsInMempool( - net.Miner.Client, 1, shortTimeout, - ) - require.NoError(t.t, err) - - // We'll mine one final block which will confirm Alice's sweep - // transaction. - mineBlocks(t, net, 1, 1) - - aliceSweepTransfer := locateAssetTransfers( - t.t, aliceTap, *sweepTx[0], - ) - t.Logf("Alice's final timeout sweep transfer: %v", - toProtoJSON(t.t, aliceSweepTransfer)) - } else { - sweepTx := sweepBlocks[0].Transactions[1] - aliceSweepTransfer := locateAssetTransfers( - t.t, aliceTap, sweepTx.TxHash(), - ) - t.Logf("Alice's final timeout sweep transfer: %v", - toProtoJSON(t.t, aliceSweepTransfer)) - } - // Finally, we'll assert that Alice's balance has been incremented by // the timeout value. aliceExpectedBalance += uint64(assetInvoiceAmt - 1) t.Logf("Expecting Alice's balance to be %d", aliceExpectedBalance) assertSpendableBalance( - t.t, aliceTap, assetID, aliceExpectedBalance, + t.t, aliceTap, assetID, nil, aliceExpectedBalance, ) t.Logf("Sending all settled funds to Zane") @@ -3800,7 +3895,7 @@ func runCustomChannelsHtlcForceClose(ctx context.Context, t *harnessTest, // Zane's balance should now be the sum of Alice's and Bob's balances. zaneExpectedBalance := aliceExpectedBalance + bobExpectedBalance assertSpendableBalance( - t.t, zaneTap, assetID, zaneExpectedBalance, + t.t, zaneTap, assetID, nil, zaneExpectedBalance, ) } @@ -3813,18 +3908,13 @@ func testCustomChannelsForwardBandwidth(ctx context.Context, lndArgs := slices.Clone(lndArgsTemplate) litdArgs := slices.Clone(litdArgsTemplate) - // Explicitly set the proof courier as Zane (now has no other role - // other than proof shuffling), otherwise a hashmail courier will be - // used. For the funding transaction, we're just posting it and don't - // expect a true receiver. - zane, err := net.NewNode( - t.t, "Zane", lndArgs, false, true, litdArgs..., - ) - require.NoError(t.t, err) - + // We use Charlie as the proof courier. But in order for Charlie to also + // use itself, we need to define its port upfront. + charliePort := port.NextAvailablePort() litdArgs = append(litdArgs, fmt.Sprintf( "--taproot-assets.proofcourieraddr=%s://%s", - proof.UniverseRpcCourierType, zane.Cfg.LitAddr(), + proof.UniverseRpcCourierType, + fmt.Sprintf(node.ListenerFormat, charliePort), )) // The topology we are going for looks like the following: @@ -3843,8 +3933,8 @@ func testCustomChannelsForwardBandwidth(ctx context.Context, // with tapd included. We also need specific flags to be enabled, so we // create 5 completely new nodes, ignoring the two default nodes that // are created by the harness. - charlie, err := net.NewNode( - t.t, "Charlie", lndArgs, false, true, litdArgs..., + charlie, err := net.NewNodeWithPort( + t.t, "Charlie", lndArgs, false, true, charliePort, litdArgs..., ) require.NoError(t.t, err) @@ -3879,7 +3969,7 @@ func testCustomChannelsForwardBandwidth(ctx context.Context, assertChannelKnown(t.t, charlie, channelOp) assertChannelKnown(t.t, fabia, channelOp) - universeTap := newTapClient(t.t, zane) + universeTap := newTapClient(t.t, charlie) charlieTap := newTapClient(t.t, charlie) daveTap := newTapClient(t.t, dave) erinTap := newTapClient(t.t, erin) @@ -4019,7 +4109,7 @@ func testCustomChannelsForwardBandwidth(ctx context.Context, // Finally, we close the channel between Erin and Fabia to make sure // everything is settled correctly. closeAssetChannelAndAssert( - t, net, erin, fabia, chanPointEF, assetID, nil, + t, net, erin, fabia, chanPointEF, [][]byte{assetID}, nil, universeTap, noOpCoOpCloseBalanceCheck, ) } @@ -4043,18 +4133,6 @@ func testCustomChannelsDecodeAssetInvoice(ctx context.Context, "rfqrpc://%s", oracleAddr, )) - // For this test, Zane will be our dedicated Universe server for all - // parties. - zane, err := net.NewNode( - t.t, "Zane", lndArgs, false, true, litdArgs..., - ) - require.NoError(t.t, err) - - litdArgs = append(litdArgs, fmt.Sprintf( - "--taproot-assets.proofcourieraddr=%s://%s", - proof.UniverseRpcCourierType, zane.Cfg.LitAddr(), - )) - // We'll just make a single node here, as this doesn't actually rely on // a set of active channels. alice, err := net.NewNode( diff --git a/itest/litd_node.go b/itest/litd_node.go index 48cd6353a..bbd822f85 100644 --- a/itest/litd_node.go +++ b/itest/litd_node.go @@ -70,6 +70,9 @@ var ( ) ) +// Option is a function for updating a node's configuration. +type Option func(config *LitNodeConfig) + type LitNodeConfig struct { *node.BaseNodeConfig diff --git a/itest/litd_test.go b/itest/litd_test.go index 30a69cd95..91a1b25ca 100644 --- a/itest/litd_test.go +++ b/itest/litd_test.go @@ -1,7 +1,6 @@ package itest import ( - "fmt" "os" "strings" "testing" @@ -42,8 +41,6 @@ func TestLightningTerminal(t *testing.T) { // Run the subset of the test cases selected in this tranche. for _, testCase := range allTestCases { - testCase := testCase - success := t.Run(testCase.name, func(t1 *testing.T) { cleanTestCaseName := strings.ReplaceAll( testCase.name, " ", "_", @@ -79,24 +76,9 @@ func TestLightningTerminal(t *testing.T) { err = litdHarness.SetUp( t1, cleanTestCaseName, aliceBobArgs, + testCase.noAliceBob, ) require.NoError(t1, err, "harness setup failed") - t1.Cleanup(func() { - require.NoError(t1, litdHarness.TearDown()) - litdHarness.Stop() - }) - - litdHarness.EnsureConnected( - t1, litdHarness.Alice, litdHarness.Bob, - ) - - logLine := fmt.Sprintf( - "STARTING ============ %v ============\n", - testCase.name, - ) - - litdHarness.Alice.AddToLog(logLine) - litdHarness.Bob.AddToLog(logLine) // Create a separate harness test for the testcase to // avoid overwriting the external harness test that is diff --git a/itest/litd_test_list_on_test.go b/itest/litd_test_list_on_test.go index 04c3f020c..41ccc8937 100644 --- a/itest/litd_test_list_on_test.go +++ b/itest/litd_test_list_on_test.go @@ -5,11 +5,11 @@ package itest var allTestCases = []*testCase{ { - name: "test mode integrated", + name: "integrated mode", test: testModeIntegrated, }, { - name: "test mode remote", + name: "remote mode", test: testModeRemote, }, { @@ -17,75 +17,101 @@ var allTestCases = []*testCase{ test: testStatelessInitMode, }, { - name: "test firewall rules", + name: "firewall rules", test: testFirewallRules, }, { - name: "test large http header", + name: "large http header", test: testLargeHttpHeader, }, { - name: "test custom channels", - test: testCustomChannels, + name: "custom channels", + test: testCustomChannels, + noAliceBob: true, }, { - name: "test custom channels large", - test: testCustomChannelsLarge, + name: "custom channels large", + test: testCustomChannelsLarge, + noAliceBob: true, }, { - name: "test custom channels grouped asset", - test: testCustomChannelsGroupedAsset, + name: "custom channels grouped asset", + test: testCustomChannelsGroupedAsset, + noAliceBob: true, }, { - name: "test custom channels force close", - test: testCustomChannelsForceClose, + name: "custom channels group tranches force close", + test: testCustomChannelsGroupTranchesForceClose, + noAliceBob: true, }, { - name: "test custom channels breach", - test: testCustomChannelsBreach, + name: "custom channels group tranches htlc force close", + test: testCustomChannelsGroupTranchesHtlcForceClose, + noAliceBob: true, }, { - name: "test custom channels liquidity", - test: testCustomChannelsLiquidityEdgeCases, + name: "custom channels force close", + test: testCustomChannelsForceClose, + noAliceBob: true, }, { - name: "test custom channels liquidity group", - test: testCustomChannelsLiquidityEdgeCasesGroup, + name: "custom channels breach", + test: testCustomChannelsBreach, + noAliceBob: true, }, { - name: "test custom channels htlc force close", - test: testCustomChannelsHtlcForceClose, + name: "custom channels liquidity", + test: testCustomChannelsLiquidityEdgeCases, + noAliceBob: true, }, { - name: "test custom channels htlc force close MPP", - test: testCustomChannelsHtlcForceCloseMpp, + name: "custom channels liquidity group", + test: testCustomChannelsLiquidityEdgeCasesGroup, + noAliceBob: true, }, { - name: "test custom channels balance consistency", - test: testCustomChannelsBalanceConsistency, + name: "custom channels htlc force close", + test: testCustomChannelsHtlcForceClose, + noAliceBob: true, }, { - name: "test custom channels single asset multi input", - test: testCustomChannelsSingleAssetMultiInput, + name: "custom channels htlc force close MPP", + test: testCustomChannelsHtlcForceCloseMpp, + noAliceBob: true, }, { - name: "test custom channels oracle pricing", - test: testCustomChannelsOraclePricing, + name: "custom channels balance consistency", + test: testCustomChannelsBalanceConsistency, + noAliceBob: true, }, { - name: "test custom channels fee", - test: testCustomChannelsFee, + name: "custom channels single asset multi input", + test: testCustomChannelsSingleAssetMultiInput, + noAliceBob: true, }, { - name: "test custom channels forward bandwidth", - test: testCustomChannelsForwardBandwidth, + name: "custom channels oracle pricing", + test: testCustomChannelsOraclePricing, + noAliceBob: true, }, { - name: "test custom channels strict forwarding", - test: testCustomChannelsStrictForwarding, + name: "custom channels fee", + test: testCustomChannelsFee, + noAliceBob: true, }, { - name: "test custom channels decode payreq", - test: testCustomChannelsDecodeAssetInvoice, + name: "custom channels forward bandwidth", + test: testCustomChannelsForwardBandwidth, + noAliceBob: true, + }, + { + name: "custom channels strict forwarding", + test: testCustomChannelsStrictForwarding, + noAliceBob: true, + }, + { + name: "custom channels decode payreq", + test: testCustomChannelsDecodeAssetInvoice, + noAliceBob: true, }, } diff --git a/itest/network_harness.go b/itest/network_harness.go index 86ab786aa..52c94d073 100644 --- a/itest/network_harness.go +++ b/itest/network_harness.go @@ -122,8 +122,8 @@ func (n *NetworkHarness) ProcessErrors() <-chan error { // rpc clients capable of communicating with the initial seeder nodes are // created. Nodes are initialized with the given extra command line flags, which // should be formatted properly - "--arg=value". -func (n *NetworkHarness) SetUp(t *testing.T, - testCase string, lndArgs []string) error { +func (n *NetworkHarness) SetUp(t *testing.T, testCase string, lndArgs []string, + noAliceBob bool) error { // Swap out grpc's default logger with our fake logger which drops the // statements on the floor. @@ -143,6 +143,11 @@ func (n *NetworkHarness) SetUp(t *testing.T, n.autopilotServer = mock.NewServer() require.NoError(t, n.autopilotServer.Start()) + // Skip early if we don't need the default Alice and Bob nodes. + if noAliceBob { + return nil + } + // Start the initial seeder nodes within the test network, then connect // their respective RPC clients. eg := errgroup.Group{} @@ -252,6 +257,20 @@ out: } } + t.Cleanup(func() { + require.NoError(t, n.TearDown()) + n.Stop() + }) + + n.EnsureConnected(t, n.Alice, n.Bob) + + logLine := fmt.Sprintf( + "STARTING ============ %v ============\n", testCase, + ) + + n.Alice.AddToLog(logLine) + n.Bob.AddToLog(logLine) + return nil } @@ -300,13 +319,28 @@ func (n *NetworkHarness) NewNode(t *testing.T, name string, extraArgs []string, ) } +// NewNodeWithPort initializes a new HarnessNode with a custom litd port. +func (n *NetworkHarness) NewNodeWithPort(t *testing.T, name string, + extraArgs []string, remoteMode bool, wait bool, litPort int, + additionalLitArgs ...string) (*HarnessNode, error) { + + allLitArgs := append(n.litArgs(), additionalLitArgs...) + + return n.newNode( + t, name, extraArgs, allLitArgs, false, remoteMode, nil, wait, + false, func(config *LitNodeConfig) { + config.LitPort = litPort + }, + ) +} + // newNode initializes a new HarnessNode, supporting the ability to initialize a // wallet with or without a seed. If hasSeed is false, the returned harness node // can be used immediately. Otherwise, the node will require an additional // initialization phase where the wallet is either created or restored. func (n *NetworkHarness) newNode(t *testing.T, name string, extraArgs, litArgs []string, hasSeed, remoteMode bool, password []byte, wait, - skipUnlock bool, opts ...node.Option) (*HarnessNode, error) { + skipUnlock bool, opts ...Option) (*HarnessNode, error) { baseCfg := &node.BaseNodeConfig{ Name: name, @@ -318,15 +352,15 @@ func (n *NetworkHarness) newNode(t *testing.T, name string, extraArgs, SkipUnlock: skipUnlock, FeeURL: n.feeService.URL(), } - for _, opt := range opts { - opt(baseCfg) - } cfg := &LitNodeConfig{ BaseNodeConfig: baseCfg, HasSeed: hasSeed, LitArgs: litArgs, RemoteMode: remoteMode, } + for _, opt := range opts { + opt(cfg) + } node, err := NewNode(t, cfg, n.LNDHarness) if err != nil { diff --git a/itest/test_harness.go b/itest/test_harness.go index b3af045dc..a2a6bc36d 100644 --- a/itest/test_harness.go +++ b/itest/test_harness.go @@ -126,7 +126,9 @@ func getLitdBinary() string { type testCase struct { name string - test func(ctx context.Context, net *NetworkHarness, t *harnessTest) + test func(ctx context.Context, net *NetworkHarness, + t *harnessTest) + noAliceBob bool } // waitForNTxsInMempool polls until finding the desired number of transactions diff --git a/proto/lnd.proto b/proto/lnd.proto index aef90a6f7..2254a5a3f 100644 --- a/proto/lnd.proto +++ b/proto/lnd.proto @@ -1758,6 +1758,10 @@ message ChannelCloseSummary { // The confirmed SCID for a zero-conf channel. uint64 zero_conf_confirmed_scid = 15 [jstype = JS_STRING]; + + // The TLV encoded custom channel data records for this output, which might + // be set for custom channels. + bytes custom_channel_data = 16; } enum ResolutionType { @@ -5124,6 +5128,22 @@ message RPCMiddlewareRequest { intercept message. */ uint64 msg_id = 7 [jstype = JS_STRING]; + + /* + The metadata pairs that were sent along with the original gRPC request via + the golang context.Context using explicit [gRPC + metadata](https://grpc.io/docs/guides/metadata/). Context values are not + propagated via gRPC and so we send any pairs along explicitly here so that + the interceptor can access them. + */ + map metadata_pairs = 9; +} + +message MetadataValues { + /* + The set of metadata values that correspond to the metadata key. + */ + repeated string values = 1; } message StreamAuth { diff --git a/proto/loop.proto b/proto/loop.proto index c1c7cdd9c..0748755e1 100644 --- a/proto/loop.proto +++ b/proto/loop.proto @@ -336,6 +336,19 @@ message LoopOutRequest { as the timeout for the payment. */ uint32 payment_timeout = 19; + + /* + The optional asset information to use for the swap. If set, the swap will + be paid in the specified asset using the provided edge node. An Asset client + must be connected to the loop client to use this feature. + */ + AssetLoopOutRequest asset_info = 20; + + /* + The optional RFQ information to use for the swap. If set, the swap will + use the provided RFQs to pay for the swap invoice. + */ + AssetRfqInfo asset_rfq_info = 21; } /* @@ -539,6 +552,9 @@ message SwapStatus { // An optional label given to the swap on creation. string label = 15; + + // If the swap was an asset swap, the asset information will be returned. + AssetLoopOutInfo asset_info = 19; } enum SwapType { @@ -659,6 +675,9 @@ enum FailureReason { message ListSwapsRequest { // Optional filter to only return swaps that match the filter. ListSwapsFilter list_swap_filter = 1; + + // Set a maximum number of swaps to return in the response. + uint64 max_swaps = 2 [jstype = JS_STRING]; } message ListSwapsFilter { @@ -685,6 +704,12 @@ message ListSwapsFilter { // If specified on creation, the last hop of the swap. bytes loop_in_last_hop = 5; + + // If specified, only returns asset swaps. + bool asset_swap_only = 6; + + // If specified, returns swaps initiated after this Unix (ns) timestamp. + int64 start_timestamp_ns = 7 [jstype = JS_STRING]; } message ListSwapsResponse { @@ -692,6 +717,9 @@ message ListSwapsResponse { The list of all currently known swaps and their status. */ repeated SwapStatus swaps = 1; + + // Timestamp to use for paging start_timestamp_ns. + int64 next_start_time = 2 [jstype = JS_STRING]; } message SwapInfoRequest { @@ -793,6 +821,12 @@ message QuoteRequest { the same time. */ repeated string deposit_outpoints = 8; + + /* + The optional asset information to use for the swap. If set, the quote will + be returned in the specified asset. + */ + AssetLoopOutRequest asset_info = 9; } message InQuoteResponse { @@ -856,6 +890,12 @@ message OutQuoteResponse { The confirmation target to be used for the sweep of the on-chain HTLC. */ int32 conf_target = 6; + + /* + If the request was for an asset swap, the quote will return the rfq ids + that will be used to pay for the swap and prepay invoices. + */ + AssetRfqInfo asset_rfq_info = 7; } message ProbeRequest { @@ -1014,6 +1054,11 @@ message GetInfoResponse { Statistics about loop ins. */ LoopStats loop_in_stats = 8; + + /* + The git commit hash of the loopd binary. + */ + string commit_hash = 9; } message GetLiquidityParamsRequest { @@ -1176,6 +1221,29 @@ message LiquidityParameters { The address type of the account specified in the account field. */ AddressType account_addr_type = 24; + + /* + A map of asset parameters to use for swaps. The key is the asset id and the + value is the parameters to use for swaps in that asset. + */ + map easy_asset_params = 25; +} + +message EasyAssetAutoloopParams { + /* + Set to true to enable easy autoloop for this asset. If set the client will + automatically dispatch swaps in order to meet the configured local balance + target size. Currently only loop out is supported, meaning that easy + autoloop can only reduce the funds that are held as balance in channels. + */ + bool enabled = 1; + + /* + The local balance target size, expressed in the asset's base units. This is + used by easy autoloop to determine how much liquidity should be maintained + in channels. + */ + uint64 local_target_asset_amt = 2 [jstype = JS_STRING]; } enum LiquidityRuleType { @@ -1592,6 +1660,15 @@ message WithdrawDepositsRequest { The fee rate in sat/vbyte to use for the withdrawal transaction. */ int64 sat_per_vbyte = 4 [jstype = JS_STRING]; + + /* + The amount in satoshis that should be withdrawn from the selected deposits. + If there is change, it will be sent back to the static address. The fees for + the transaction are taken from the change output. If the change is below + the dust limit, there won't be a change output and the dust goes towards + fees. + */ + int64 amount = 5 [jstype = JS_STRING]; } message WithdrawDepositsResponse { @@ -1601,9 +1678,9 @@ message WithdrawDepositsResponse { string withdrawal_tx_hash = 1; /* - The pkscript of the withdrawal transaction. + The destination address of the withdrawal transaction. */ - string pk_script = 2; + string address = 2; } message OutPoint { @@ -2000,3 +2077,117 @@ message StaticAddressLoopInResponse { */ uint32 payment_timeout_seconds = 11; } + +message AssetLoopOutRequest { + /* + The asset id to use to pay for the swap invoice. If set an + asset client is needed to set to be able to pay the invoice. + */ + bytes asset_id = 1; + + /* + The node identity public key of the peer to ask for a quote for sending out + the assets and converting them to satoshis. This must be specified if + an asset id is set. + */ + bytes asset_edge_node = 2; + + /* + An optional maximum multiplier for the rfq rate. If not set, the default + will be 1.1. This means if we request a loop out quote for 1 BTC, the off + chain cost will be at most 1.1 BTC. + */ + double max_limit_multiplier = 3; + + /* + An optional expiry unix timestamp for when the rfq quote should expire. + */ + int64 expiry = 4 [jstype = JS_STRING]; +} + +message AssetRfqInfo { + /* + The Prepay RFQ ID to use to pay for the prepay invoice. + */ + bytes prepay_rfq_id = 1; + + /* + The maximum asset amt we'll pay for the prepay payment. This includes the + max limit multiplier that was set in the request. + */ + uint64 max_prepay_asset_amt = 2 [jstype = JS_STRING]; + + /* + The asset to BTC conversion rate for the prepay invoice. + */ + FixedPoint prepay_asset_rate = 6; + + /* + The Swap RFQ ID to use to pay for the swap invoice. + */ + bytes swap_rfq_id = 3; + + /* + The maximum asset amt we'll pay for the swap payment. This includes the + max limit multiplier that was set in the request. + */ + uint64 max_swap_asset_amt = 4 [jstype = JS_STRING]; + + /* + The asset to BTC conversion rate for the swap invoice. + */ + FixedPoint swap_asset_rate = 7; + + /* + The name of the asset to swap. + */ + string asset_name = 5; +} + +// FixedPoint is a scaled integer representation of a fractional number. +// +// This type consists of two integer fields: a coefficient and a scale. +// Using this format enables precise and consistent representation of fractional +// numbers while avoiding floating-point data types, which are prone to +// precision errors. +// +// The relationship between the fractional representation and its fixed-point +// representation is expressed as: +// ``` +// V = F_c / (10^F_s) +// ``` +// where: +// +// * `V` is the fractional value. +// +// * `F_c` is the coefficient component of the fixed-point representation. It is +// the scaled-up fractional value represented as an integer. +// +// * `F_s` is the scale component. It is an integer specifying how +// many decimal places `F_c` should be divided by to obtain the fractional +// representation. +message FixedPoint { + // The coefficient is the fractional value scaled-up as an integer. This + // integer is represented as a string as it may be too large to fit in a + // uint64. + string coefficient = 1; + + // The scale is the component that determines how many decimal places + // the coefficient should be divided by to obtain the fractional value. + uint32 scale = 2; +} + +message AssetLoopOutInfo { + /* + The asset id that was used to pay for the swap invoice. + */ + string asset_id = 1; + /* + The human readable name of the asset. + */ + string asset_name = 2; + /* + The total asset offchain cost of the swap. + */ + uint64 asset_cost_offchain = 3 [jstype = JS_STRING]; +} diff --git a/rules/channel_restrictions_test.go b/rules/channel_restrictions_test.go index b2d6200c3..6102851c4 100644 --- a/rules/channel_restrictions_test.go +++ b/rules/channel_restrictions_test.go @@ -157,8 +157,8 @@ func (m *mockLndClient) GetLndClient() lndclient.LightningClient { return m } -func (m *mockLndClient) ListChannels(_ context.Context, _, _ bool) ( - []lndclient.ChannelInfo, error) { +func (m *mockLndClient) ListChannels(_ context.Context, _, _ bool, + _ ...lndclient.ListChannelsOption) ([]lndclient.ChannelInfo, error) { return m.channels, nil }