openapi: '3.0.2' info: title: NLoop Server OpenAPI definition version: '1.0' description: > Lightning Channel Manager. It will maintain the channel balance by performing submarine swap against Boltz server. contact: email: joemphilips@gmail.com name: Joe Miyamoto url: https://twitter.com/joemphilips servers: - url: https://api.server.test/v1 paths: /v1/version: get: tags: - general responses: '200': description: OK content: application/json: schema: type: string /v1/info: get: tags: - general responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/GetInfoResponse' /v1/swaps/{id}: get: tags: - swap description: > Get the list of ongoing swaps. parameters: - $ref: '#/components/schemas/swapId' responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/GetSwapResponse' /v1/swaps/history: get: description: > Get the full history of swaps. tags: - swap parameters: - in: query name: since schema: type: string format: date required: false responses: '200': description: OK content: application/json: schema: $ref: "#/components/schemas/GetSwapHistoryResponse" /v1/swaps/ongoing: get: description: > Get the list of ongoing swaps. tags: - swap responses: '200': description: OK content: application/json: schema: $ref: "#/components/schemas/GetOngoingSwapResponse" /v1/loop/out: post: tags: - loop requestBody: content: application/json: schema: $ref: '#/components/schemas/LoopOutRequest' security: - Cookie: [] responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/LoopOutResponse' '400': description: invalid request content: application/json: schema: type: object properties: errors: type: array description: error message minItems: 1 items: type: string /v1/loop/in: post: tags: - loop requestBody: content: application/json: schema: $ref: "#/components/schemas/LoopInRequest" responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/LoopInResponse' '400': description: invalid request content: application/json: schema: type: object properties: errors: type: array description: error message minItems: 1 items: type: string /v1/auto/suggest: get: description: > Get suggestion for the swaps. tags: - loop - autoloop responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/SuggestSwapsResponse' /v1/liquidity/params: get: description: > Get the parameters that the daemon's liquidity manager is currently configured with. This may be nil if nothing is configured. tags: - autoloop responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/LiquidityParameters' post: description: > Overwrites the current set of parameters for the daemon's liquidity manager. requestBody: content: application/json: schema: $ref: '#/components/schemas/SetLiquidityParametersRequest' responses: '200': description: OK '400': description: invalid request content: application/json: schema: type: object properties: errors: type: array description: error message minItems: 1 items: type: string components: securitySchemes: Cookie: type: apiKey name: Cookie in: cookie schemas: cryptoCode: description: Symbol name for the currency. type: string enum: - BTC - LTC pairId: description: Pair of cryptoCode type: string example: - "BTC/LTC" - "BTC/BTC" # ----- Primitive objects PubKey: description: Bitcoin public key in 33 bytes length type: string maxLength: 33 minLength: 33 example: 03afbba930dc74d6412b71c31f72bfb8d4615121174dd4290cbbf83960961ba9ab P2PKH: type: string pattern: ^[1][a-km-zA-HJ-NP-Z1-9]{25,34}$ example: 1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2 BitcoinAddressNonMalleable: oneOf: - $ref: '#/components/schemas/P2WSH' - $ref: '#/components/schemas/P2WPKH' P2SH: type: string pattern: ^[3][a-km-zA-HJ-NP-Z1-9]{25,34}$ example: 3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy P2WPKH: type: string pattern: ^(bc1|[13])[a-zA-HJ-NP-Z0-9]{25}$ example: bc1qcw9l54jre2wc4uju222wz8su6am2fs3vufsc8c P2WSH: type: string pattern: ^(bc1|[13])[a-zA-HJ-NP-Z0-9]{39}$ example: bc1q2y7lfmmm7xhv2dpf0n0mx6w26zspmvszm3hvkc4yn785xp8dvs5shejlc5 ShortChannelId: type: string pattern: (\d{3})x(\d{3})x(\d{2}) description: See bolt 07 example: 140x10x1 swapId: type: string HopHint: type: object properties: node_id: $ref: '#/components/schemas/PubKey' description: The pubkey key of the node at the start of the channel chan_id: $ref: "#/components/schemas/ShortChannelId" fee_base_msat: type: integer format: int64 fee_proportional_millionths: type: integer format: int64 cltv_expiry_delta: type: integer format: int64 RouteHint: type: object properties: hops: type: array maxItems: 6 items: $ref: '#/components/schemas/HopHint' description: < Route hints which will be included in the invoice. See bolt11 for the detail. # ----- # ----- requests LoopOutRequest: type: object properties: channel_id: type: array items: $ref: '#/components/schemas/ShortChannelId' description: < ShortChannelId for the one you want to get inbound liquidity. default is the one it has least. nullable: true pair_id: $ref: '#/components/schemas/pairId' description: < currency pair to perform the swap. Default is BTC/BTC. nullable: true address: $ref: '#/components/schemas/BitcoinAddressNonMalleable' nullable: true amount: type: integer format: int64 description: < amount in satoshi. swap_tx_conf_requirement: type: integer description: < The number of confirmation of the swaptx (htlc tx) before we make an off-chain offer. a.k.a. `htlc_confirmations` on lightning loop. Default number depends on the asset type. nullable: true label: type: string description: < Additional label for this request. nullable: true max_swap_routing_fee: type: integer format: int64 description: < Maximum off-chain fee in sat that may be paied for swap payment to the server. This limit is applied during path finding. nullable: true max_prepay_routing_fee: type: integer format: int64 description: < Maximum off-chain fee in sat that may be paid for the prepay to the server. This limit is applied during path finding. nullable: true max_swap_fee: type: integer format: int64 description: < Maximum we are willing to pay the server for the swap. This value is not disclosed in the swap initiation call, but if the server asks for a higher fee, we abort the swap. nullable: true max_prepay_amount: type: integer format: int64 description: < Maximum amount of the (loop-out) swap fee that may be charged as a prepayment nullable: true max_miner_fee: type: integer format: int64 description: < Maximum on-chain fees that we are willing to spend. If we want to sweep the on-chain htlc and the fee estimate turns out higher than this value, we cancel the swap. If the fee estimate is lower, we publish the sweep tx. If the sweep tx is not confirmed, we are forced to ratchet up fees until it is swept. Possibly even exceeding max_miner_fee if we get close to the HTLC timeout. Because the initial publication revealed the preimage, we have no other choice. The server may already have pulled the off-chain HTLC. Only when the fee becomes higher than the swap amount, we can wait for fees to come down and hope -- if we are past the timeout -- that the server is not publishing the revocation. nullable: true sweep_conf_target: type: integer format: int32 description: < Confimation target for sweeping the HTLC (a.k.a. swaptx, lockuptx) nullable: true required: - amount LoopInRequest: type: object properties: amount: type: integer format: int64 description: < amount in satoshi. channel_id: $ref: '#/components/schemas/ShortChannelId' description: < currency pair to perform the swap. Default is BTC/BTC. nullable: true pair_id: $ref: '#/components/schemas/pairId' description: < counterparty's cryptoCode to swap against. default is the same cryptocurrency with the one you pay. nullable: true label: type: string description: < Additional label for this request. nullable: true max_miner_fee: type: integer format: int64 description: < Maximum on-chain fees that we are willing to spend. If we want to publish the on-chain htlc and the fee estimate turns out higher than this value, we cancel the swap. nullable: true max_swap_fee: type: integer format: int64 description: < Maximum we are willing to pay the server for the swap. This value is not disclosed in the swap initiation call, but if the server asks for a higher fee, we abort the swap. nullable: true htlc_conf_target: type: integer format: int32 description: < Confimation target for sweeping the HTLC (a.k.a. swaptx, lockuptx) nullable: true route_hints: type: array items: $ref: '#/components/schemas/RouteHint' nullable: true description: < route hints included in the invoice. Usually used in case of the private channel. But in NLoop, we also use it as a means of communication against the server, i.e. to tell them which channel do we want inbound liqidity for. required: - amount # ----- # ----- responses GetInfoResponse: type: object properties: version: type: string supported_coins: type: object properties: on_chain: type: array items: $ref: '#/components/schemas/cryptoCode' off_chain: type: array items: $ref: '#/components/schemas/cryptoCode' required: - version - supported_coins GetSwapResponse: type: object ShortSwapSummary: type: object properties: "type": type: string enum: - SuccessfullyFinished - FinishedByError - FinishedByRefund - OnGoing error_msg: type: string nullable: true refund_txid: type: string nullable: true cost: $ref: "#/components/schemas/Cost" required: - "type" GetSwapHistoryResponse: type: object additionalProperties: $ref: "#/components/schemas/ShortSwapSummary" Cost: type: object properties: server_onchain: type: integer format: int64 server_offchain: type: integer format: int64 onchain: type: integer format: int64 offchain: type: integer format: int64 GetOngoingSwapResponse: type: array description: list of swap items: type: object LoopOutResponse: type: object properties: id: description: > Swap identifier to track status. address: description: < An address to which counterparty has paid. Must be the same with the one in the request unless null. $ref: "#/components/schemas/BitcoinAddressNonMalleable" claim_tx_id: description: < An txid by which they have paid to us. It is populated only when its 0-conf. nullable: true LoopInResponse: type: object properties: id: description: > Swap identifier to track status. address: description: > The address of the on-chain HTLC $ref: "#/components/schemas/P2WSH" LiquidityRuleType: enum: - UNKNOWN - THRESHOLD LiquidityRule: type: object properties: incoming_threshold: type: integer format: int64 outgoing_threshold: type: integer format: int64 pubkey: $ref: '#/components/schemas/PubKey' channel_id: $ref: "#/components/schemas/ShortChannelId" type: $ref: "#/components/schemas/LiquidityRuleType" LiquidityParameters: type: object properties: rules: type: array items: $ref: '#/components/schemas/LiquidityRule' fee_ppm: type: integer description: > The parts per million of swap amount that is allowed to be allocated to swap fees. This valie is applied across swap categories and may not be set in conjunction with sweep fee rate, swap fee ppm, routing fee ppm, prepay routing, max prepay and max miner fee. sweep_fee_rate_sat_per_vbyte: type: integer description: > The limit we place on our estimated sweep cost for a swap in sat/vByte. If the estimated fee for our sweep tx within the specified confirmation target is above this value, we will not suggest any swaps. max_swap_fee_ppm: type: integer description: > The maximum fee paid to the server for facilitating the swap, expressed as parts per million of the swap volume. max_routing_fee_ppm: type: integer max_prepay_routing_fee_ppm: type: integer max_prepay_sat: type: integer format: int64 max_miner_fee_sat: type: integer format: int64 sweep_conf_target: type: integer description: The number of blocks from the on-chain HTLC7s confirmation height that it shuold be swept within. failure_backoff_sec: type: integer description: > The amount of time we require to pass since a channel was part of a failed swap due to off chain payment failure until it will be considered for swap suggestions again, expressed in seconds. autoloop: type: boolean description: > Set to true to enable automatic dispatch of swaps. All swaps will be limited to the fee categories set by these parameters, and total expenditure will be limited to the autoloop budget. autoloop_budget_sat: type: integer format: int64 autoloop_budget_start_sec: type: integer description: > The start time for autoloop budget, expressed as a unix timestamp in seconds. If this value is 0, the budget will be applied for all automatically dispatched swaps. Swaps that were completed before this date will not be included in budget calculations. auto_max_in_flight: type: integer description: The maximum number of of automatically dispatched swaps that we allow to be in flight at any point in time. min_swap_amount: type: integer format: int64 description: > The minimum amount, expressed in satoshis, that the autoloop client will dispatch a swap for. max_swap_amount: type: integer format: int64 description: The maximum swap amount, expressed in satoshis. pair_id: $ref: '#/components/schemas/pairId' required: - "pair_id" SetLiquidityParametersRequest: type: object properties: parameters: $ref: "#/components/schemas/LiquidityParameters" Disqualified: type: object properties: channel_id: $ref: '#/components/schemas/ShortChannelId' pubkey: $ref: "#/components/schemas/PubKey" reason: enum: - Unknown - BudgetNotStarted - SweepFeesTooHigh - BudgetElapsed - InFlightLimitReached - SwapFeeTooHigh - MinerFeeTooHigh - PrepayTooHigh - FailureBackoff - LoopOutAlreadyInTheChannel - LoopInAlreadyInTheChannel - LiquidityOk - BudgetInsufficient - FeePPMInsufficient SuggestSwapsResponse: type: object properties: loop_out: type: array items: $ref: "#/components/schemas/LoopOutRequest" loop_in: type: array items: $ref: "#/components/schemas/LoopInRequest" disqualified: type: array items: $ref: "#/components/schemas/Disqualified"