Skip to content

Commit

Permalink
feat: cooperative Submarine claim transactions
Browse files Browse the repository at this point in the history
  • Loading branch information
michael1011 committed Feb 4, 2024
1 parent 9cc7009 commit 141542e
Show file tree
Hide file tree
Showing 9 changed files with 804 additions and 74 deletions.
3 changes: 2 additions & 1 deletion lib/Core.ts
Expand Up @@ -167,6 +167,7 @@ export const constructClaimDetails = (
swap: Swap,
transaction: Transaction | LiquidTransaction,
preimage: Buffer,
cooperative: boolean = false,
): ClaimDetails | LiquidClaimDetails => {
// Compatibility mode with database schema version 0 in which this column didn't exist
if (swap.lockupTransactionVout === undefined) {
Expand All @@ -188,7 +189,7 @@ export const constructClaimDetails = (
switch (swap.version) {
case SwapVersion.Taproot: {
claimDetails.type = OutputType.Taproot;
claimDetails.cooperative = false;
claimDetails.cooperative = cooperative;
claimDetails.swapTree = SwapTreeSerializer.deserializeSwapTree(
swap.redeemScript!,
);
Expand Down
153 changes: 152 additions & 1 deletion lib/api/v2/routers/SwapRouter.ts
Expand Up @@ -2,8 +2,10 @@ import { Request, Response, Router } from 'express';
import Logger from '../../../Logger';
import { getHexString, stringify } from '../../../Utils';
import { SwapVersion } from '../../../consts/Enums';
import SwapRepository from '../../../db/repositories/SwapRepository';
import RateProviderTaproot from '../../../rates/providers/RateProviderTaproot';
import CountryCodes from '../../../service/CountryCodes';
import Errors from '../../../service/Errors';
import Service from '../../../service/Service';
import Controller from '../../Controller';
import {
Expand Down Expand Up @@ -299,7 +301,7 @@ class SwapRouter extends RouterBase {
* properties:
* pubNonce:
* type: string
* description: Public nonce of Boltz encoded as HEX
* description: Public nonce encoded as HEX
* partialSignature:
* type: string
* description: Partial signature encoded as HEX
Expand Down Expand Up @@ -333,6 +335,106 @@ class SwapRouter extends RouterBase {
*/
router.post('/submarine/refund', this.handleError(this.refundSubmarine));

/**
* @openapi
* components:
* schemas:
* SubmarineClaimDetails:
* type: object
* properties:
* preimage:
* type: string
* description: Preimage of the invoice for the Submarine Swap encoded as HEX
* pubNonce:
* type: string
* description: Public nonce of Boltz encoded as HEX
* publicKey:
* type: string
* description: Public key of Boltz encoded as HEX
* transactionHash:
* type: string
* description: Hash of the transaction that should be signed
*/

/**
* @openapi
* /swap/submarine/{id}/claim:
* get:
* tags: [Submarine]
* description: Get the needed information to post a partial signature for a cooperative Submarine Swap claim transaction
* parameters:
* - in: path
* name: id
* required: true
* schema:
* type: string
* description: ID of the Swap
* responses:
* '200':
* description: The latest status of the Swap
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/SubmarineClaimDetails'
* '400':
* description: Error that caused signature request to fail
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/ErrorResponse'
* '404':
* description: When no Swap with the ID could be found
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/ErrorResponse'
*/
router.get(
'/submarine/:id/claim',
this.handleError(this.getSubmarineClaimDetails),
);

/**
* @openapi
* /swap/submarine/{id}/claim:
* post:
* tags: [Submarine]
* description: Send Boltz the clients partial signature for a cooperative Submarine Swap claim transaction
* parameters:
* - in: path
* name: id
* required: true
* schema:
* type: string
* description: ID of the Swap
* requestBody:
* required: true
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/PartialSignature'
* responses:
* '200':
* description: The latest status of the Swap
* content:
* application/json:
* schema:
* type: object
* '400':
* description: Error that caused signature request to fail
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/ErrorResponse'
* '404':
* description: When no Swap with the ID could be found
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/ErrorResponse'
*/
router.post('/submarine/:id/claim', this.handleError(this.claimSubmarine));

/**
* @openapi
* tags:
Expand Down Expand Up @@ -711,6 +813,55 @@ class SwapRouter extends RouterBase {
});
};

private getSubmarineClaimDetails = async (req: Request, res: Response) => {
const { id } = validateRequest(req.params, [
{ name: 'id', type: 'string' },
]);
const swap = await SwapRepository.getSwap({
id,
});
if (swap === null || swap === undefined) {
errorResponse(this.logger, req, res, Errors.SWAP_NOT_FOUND(id), 404);
return;
}

const details =
await this.service.swapManager.deferredClaimer.getCooperativeDetails(
swap,
);
successResponse(res, {
preimage: getHexString(details.preimage),
pubNonce: getHexString(details.pubNonce),
publicKey: getHexString(details.publicKey),
transactionHash: getHexString(details.transactionHash),
});
};

private claimSubmarine = async (req: Request, res: Response) => {
const { id } = validateRequest(req.params, [
{ name: 'id', type: 'string' },
]);
const { pubNonce, partialSignature } = validateRequest(req.body, [
{ name: 'pubNonce', type: 'string', hex: true },
{ name: 'partialSignature', type: 'string', hex: true },
]);

const swap = await SwapRepository.getSwap({
id,
});
if (swap === null || swap === undefined) {
errorResponse(this.logger, req, res, Errors.SWAP_NOT_FOUND(id), 404);
return;
}

await this.service.swapManager.deferredClaimer.broadcastCooperative(
swap,
pubNonce,
partialSignature,
);
successResponse(res, {});
};

private getReverse = (_req: Request, res: Response) =>
successResponse(
res,
Expand Down
8 changes: 8 additions & 0 deletions lib/service/Errors.ts
Expand Up @@ -145,4 +145,12 @@ export default {
message: 'input index is out of range',
code: concatErrorCode(ErrorCodePrefix.Service, 37),
}),
NOT_ELIGIBLE_FOR_COOPERATIVE_CLAIM: (): Error => ({
message: 'swap not eligible for a cooperative claim',
code: concatErrorCode(ErrorCodePrefix.Service, 38),
}),
NOT_ELIGIBLE_FOR_COOPERATIVE_CLAIM_BROADCAST: (): Error => ({
message: 'swap not eligible for a cooperative claim broadcast',
code: concatErrorCode(ErrorCodePrefix.Service, 39),
}),
};

0 comments on commit 141542e

Please sign in to comment.