Skip to content

Commit

Permalink
feat: RSK in API V2
Browse files Browse the repository at this point in the history
  • Loading branch information
michael1011 committed Feb 7, 2024
1 parent 87f952a commit d0dbe53
Show file tree
Hide file tree
Showing 17 changed files with 63 additions and 65 deletions.
6 changes: 3 additions & 3 deletions docker/build.py
Expand Up @@ -43,11 +43,11 @@ class Image:
BITCOIN_VERSION = "26.0"
LITECOIN_VERSION = "0.21.2.2"
ELEMENTS_VERSION = "23.2.1"
GETH_VERSION = "1.13.10"
GETH_VERSION = "1.13.11"

C_LIGHTNING_VERSION = "23.11.2"
ECLAIR_VERSION = "0.9.0"
LND_VERSION = "0.17.3-beta"
LND_VERSION = "0.17.4-beta"

BITCOIN_BUILD_ARG = BuildArgument(
name="BITCOIN_VERSION",
Expand Down Expand Up @@ -101,7 +101,7 @@ class Image:
],
),
"regtest": Image(
tag="4.4.0",
tag="4.4.1",
arguments=[
UBUNTU_VERSION,
BITCOIN_BUILD_ARG,
Expand Down
2 changes: 1 addition & 1 deletion docker/regtest/startRegtest.sh
Expand Up @@ -9,7 +9,7 @@ docker run \
--volume "${PWD}"/docker/regtest/data/cln/mpay:/root/.lightning/regtest/mpay \
--volume "${PWD}"/tools:/tools \
--network host \
boltz/regtest:4.4.0
boltz/regtest:4.4.1

docker exec regtest bash -c "cp /root/.lightning/regtest/*.pem /root/.lightning/regtest/certs"
docker exec regtest chmod -R 777 /root/.lightning/regtest/certs
2 changes: 1 addition & 1 deletion lib/VersionCheck.ts
Expand Up @@ -95,7 +95,7 @@ class VersionCheck {
},
[LndClient.serviceName]: {
minimal: '0.16.0',
maximal: '0.17.3',
maximal: '0.17.4',
},
};

Expand Down
3 changes: 0 additions & 3 deletions lib/api/Controller.ts
Expand Up @@ -474,7 +474,6 @@ class Controller {
invoiceAmount,
onchainAmount,
claimPublicKey,
prepayMinerFee,
} = validateRequest(req.body, [
{ name: 'pairId', type: 'string' },
{ name: 'orderSide', type: 'string' },
Expand All @@ -486,7 +485,6 @@ class Controller {
{ name: 'claimAddress', type: 'string', optional: true },
{ name: 'invoiceAmount', type: 'number', optional: true },
{ name: 'onchainAmount', type: 'number', optional: true },
{ name: 'prepayMinerFee', type: 'boolean', optional: true },
{ name: 'claimPublicKey', type: 'string', hex: true, optional: true },
]);

Expand All @@ -503,7 +501,6 @@ class Controller {
invoiceAmount,
onchainAmount,
claimPublicKey,
prepayMinerFee,
userAddress: address,
version: SwapVersion.Legacy,
});
Expand Down
7 changes: 0 additions & 7 deletions lib/api/v2/WebSocketHandler.ts
Expand Up @@ -3,7 +3,6 @@ import ws from 'ws';
import { formatError } from '../../Utils';
import Service from '../../service/Service';
import Controller from '../Controller';
import { apiPrefix } from './Consts';

enum Operation {
// TODO: unsubscribe
Expand Down Expand Up @@ -54,12 +53,6 @@ class WebSocketHandler {

public register = (server: http.Server) => {
server.on('upgrade', (request, socket, head) => {
if (request.url !== `${apiPrefix}/ws`) {
request.destroy();
socket.destroy();
return;
}

this.ws.handleUpgrade(request, socket, head, (ws) => {
this.ws.emit('connection', ws, request);
});
Expand Down
11 changes: 8 additions & 3 deletions lib/api/v2/routers/SwapRouter.ts
Expand Up @@ -649,8 +649,10 @@ class SwapRouter extends RouterBase {
* description: SHA-256 hash of the preimage of the Reverse Swap encoded as HEX
* claimPublicKey:
* type: string
* required: true
* description: Public key with which the Reverse Swap can be claimed encoded as HEX
* claimAddress:
* type: string
* description: EVM address with which the Reverse Swap can be claimed
* invoiceAmount:
* type: string
* description: Amount for which the invoice should be; conflicts with "onchainAmount"
Expand Down Expand Up @@ -909,8 +911,8 @@ class SwapRouter extends RouterBase {
{ name: 'from', type: 'string' },
{ name: 'invoice', type: 'string', optional: true },
{ name: 'pairHash', type: 'string', optional: true },
{ name: 'refundPublicKey', type: 'string', hex: true },
{ name: 'referralId', type: 'string', optional: true },
{ name: 'refundPublicKey', type: 'string', hex: true, optional: true },
]);

const { pairId, orderSide } = this.service.convertToPairAndSide(from, to);
Expand Down Expand Up @@ -1089,19 +1091,21 @@ class SwapRouter extends RouterBase {
referralId,
routingNode,
preimageHash,
claimAddress,
invoiceAmount,
onchainAmount,
claimPublicKey,
} = validateRequest(req.body, [
{ name: 'to', type: 'string' },
{ name: 'from', type: 'string' },
{ name: 'preimageHash', type: 'string', hex: true },
{ name: 'claimPublicKey', type: 'string', hex: true },
{ name: 'pairHash', type: 'string', optional: true },
{ name: 'referralId', type: 'string', optional: true },
{ name: 'routingNode', type: 'string', optional: true },
{ name: 'claimAddress', type: 'string', optional: true },
{ name: 'invoiceAmount', type: 'number', optional: true },
{ name: 'onchainAmount', type: 'number', optional: true },
{ name: 'claimPublicKey', type: 'string', hex: true, optional: true },
]);

checkPreimageHashLength(preimageHash);
Expand All @@ -1114,6 +1118,7 @@ class SwapRouter extends RouterBase {
referralId,
routingNode,
preimageHash,
claimAddress,
invoiceAmount,
onchainAmount,
claimPublicKey,
Expand Down
2 changes: 1 addition & 1 deletion lib/rates/providers/RateProviderTaproot.ts
Expand Up @@ -299,7 +299,7 @@ class RateProviderTaproot extends RateProviderBase<SwapTypes> {
return false;
}

return cur.chainClient !== undefined;
return cur.chainClient !== undefined || cur.provider !== undefined;
};
}

Expand Down
4 changes: 4 additions & 0 deletions lib/service/Service.ts
Expand Up @@ -872,6 +872,10 @@ class Service {
}
break;

case CurrencyType.Ether:
case CurrencyType.ERC20:
break;

default:
if (args.version !== SwapVersion.Legacy) {
throw Errors.UNSUPPORTED_SWAP_VERSION();
Expand Down
17 changes: 8 additions & 9 deletions lib/service/cooperative/EipSigner.ts
Expand Up @@ -28,6 +28,14 @@ class EipSigner {
}

const { base, quote } = splitPairId(swap.pair);
const chainSymbol = getChainCurrency(base, quote, swap.orderSide, false);
const manager = this.walletManager.ethereumManagers.find((man) =>
man.hasSymbol(chainSymbol),
);

if (manager === undefined) {
throw 'chain currency is not EVM based';
}

if (
!(await MusigSigner.isEligibleForRefund(
Expand All @@ -47,15 +55,6 @@ class EipSigner {
`Creating EIP-712 signature for refund of Swap ${swap.id}`,
);

const chainSymbol = getChainCurrency(base, quote, swap.orderSide, false);
const manager = this.walletManager.ethereumManagers.find((man) =>
man.hasSymbol(chainSymbol),
);

if (manager === undefined) {
throw 'no signer for currency';
}

const { domain, types, value } = await this.getSigningData(
manager,
chainSymbol,
Expand Down
10 changes: 7 additions & 3 deletions lib/service/cooperative/MusigSigner.ts
Expand Up @@ -54,6 +54,13 @@ class MusigSigner {
}

const { base, quote } = splitPairId(swap.pair);
const currency = this.currencies.get(
getChainCurrency(base, quote, swap.orderSide, false),
)!;

if (currency.chainClient === undefined) {
throw 'chain currency is not UTXO based';
}

if (
swap.version !== SwapVersion.Taproot ||
Expand All @@ -74,9 +81,6 @@ class MusigSigner {
`Creating partial signature for refund of Swap ${swap.id}`,
);

const currency = this.currencies.get(
getChainCurrency(base, quote, swap.orderSide, false),
)!;
const swapTree = SwapTreeSerializer.deserializeSwapTree(swap.redeemScript!);

return this.createPartialSignature(
Expand Down
4 changes: 2 additions & 2 deletions lib/swap/SwapManager.ts
Expand Up @@ -365,10 +365,10 @@ class SwapManager {
id,
pair,

lockupAddress: result.address,
version: args.version,
referral: args.referralId,
orderSide: args.orderSide,
version: SwapVersion.Legacy,
lockupAddress: result.address,
status: SwapUpdateEvent.SwapCreated,
preimageHash: getHexString(args.preimageHash),
timeoutBlockHeight: result.timeoutBlockHeight,
Expand Down
5 changes: 4 additions & 1 deletion swagger-spec.json
Expand Up @@ -1719,9 +1719,12 @@
},
"claimPublicKey": {
"type": "string",
"required": true,
"description": "Public key with which the Reverse Swap can be claimed encoded as HEX"
},
"claimAddress": {
"type": "string",
"description": "EVM address with which the Reverse Swap can be claimed"
},
"invoiceAmount": {
"type": "string",
"description": "Amount for which the invoice should be; conflicts with \"onchainAmount\""
Expand Down
2 changes: 1 addition & 1 deletion test/integration/service/cooperative/EipSigner.spec.ts
Expand Up @@ -114,7 +114,7 @@ describe('EipSigner', () => {
status: SwapUpdateEvent.InvoiceFailedToPay,
});
await expect(signer.signSwapRefund('no signer')).rejects.toEqual(
'no signer for currency',
'chain currency is not EVM based',
);
});

Expand Down
17 changes: 16 additions & 1 deletion test/integration/service/cooperative/MusigSigner.spec.ts
Expand Up @@ -69,7 +69,10 @@ describe('MusigSigner', () => {

const signer = new MusigSigner(
Logger.disabledLogger,
new Map<string, Currency>([['BTC', btcCurrency]]),
new Map<string, any>([
['BTC', btcCurrency],
['noChainClient', {}],
]),
walletManager,
nursery,
);
Expand Down Expand Up @@ -179,6 +182,18 @@ describe('MusigSigner', () => {
await bitcoinClient.sendRawTransaction(refundTx.toHex());
});

test('should throw when creating refund signature for onchain currency that is not UTXO based', async () => {
SwapRepository.getSwap = jest.fn().mockResolvedValue({
pair: 'noChainClient/BTC',
side: OrderSide.BUY,
});

const id = 'noChain';
await expect(
signer.signSwapRefund(id, Buffer.alloc(0), Buffer.alloc(0), 0),
).rejects.toEqual('chain currency is not UTXO based');
});

test('should throw when creating refund signature for swap that does not exist', async () => {
SwapRepository.getSwap = jest.fn().mockResolvedValue(undefined);

Expand Down
32 changes: 6 additions & 26 deletions test/unit/api/Controller.spec.ts
Expand Up @@ -985,32 +985,13 @@ describe('Controller', () => {

requestData.pairHash = undefined;

// Should parse and pass the prepay miner fee boolean
requestData.prepayMinerFee = true;

await controller.createSwap(mockRequest(requestData), res);

expect(service.createReverseSwap).toHaveBeenNthCalledWith(5, {
prepayMinerFee: true,
pairId: requestData.pairId,
version: SwapVersion.Legacy,
orderSide: requestData.orderSide,
invoiceAmount: requestData.invoiceAmount,
preimageHash: getHexBuffer(requestData.preimageHash),
claimPublicKey: getHexBuffer(requestData.claimPublicKey),
});

expect(res.status).toHaveBeenNthCalledWith(4, 201);
expect(res.json).toHaveBeenNthCalledWith(4, await mockCreateReverseSwap());

// Should parse and pass onchain amount
requestData.onchainAmount = 123;
requestData.invoiceAmount = undefined;

await controller.createSwap(mockRequest(requestData), res);

expect(service.createReverseSwap).toHaveBeenNthCalledWith(7, {
prepayMinerFee: true,
expect(service.createReverseSwap).toHaveBeenNthCalledWith(5, {
pairId: requestData.pairId,
version: SwapVersion.Legacy,
orderSide: requestData.orderSide,
Expand All @@ -1019,16 +1000,15 @@ describe('Controller', () => {
claimPublicKey: getHexBuffer(requestData.claimPublicKey),
});

expect(res.status).toHaveBeenNthCalledWith(5, 201);
expect(res.json).toHaveBeenNthCalledWith(5, await mockCreateReverseSwap());
expect(res.status).toHaveBeenNthCalledWith(4, 201);
expect(res.json).toHaveBeenNthCalledWith(4, await mockCreateReverseSwap());

// Should parse and pass referral IDs
requestData.referralId = 'someId';

await controller.createSwap(mockRequest(requestData), res);

expect(service.createReverseSwap).toHaveBeenNthCalledWith(9, {
prepayMinerFee: true,
expect(service.createReverseSwap).toHaveBeenNthCalledWith(7, {
pairId: requestData.pairId,
version: SwapVersion.Legacy,
orderSide: requestData.orderSide,
Expand All @@ -1038,8 +1018,8 @@ describe('Controller', () => {
claimPublicKey: getHexBuffer(requestData.claimPublicKey),
});

expect(res.status).toHaveBeenNthCalledWith(6, 201);
expect(res.json).toHaveBeenNthCalledWith(6, await mockCreateReverseSwap());
expect(res.status).toHaveBeenNthCalledWith(5, 201);
expect(res.json).toHaveBeenNthCalledWith(5, await mockCreateReverseSwap());
});

test('should query referrals', async () => {
Expand Down
2 changes: 0 additions & 2 deletions test/unit/api/v2/routers/SwapRouter.spec.ts
Expand Up @@ -248,7 +248,6 @@ describe('SwapRouter', () => {
error | body
${'undefined parameter: to'} | ${{}}
${'undefined parameter: from'} | ${{ to: 'BTC' }}
${'undefined parameter: refundPublicKey'} | ${{ to: 'BTC', from: 'L-BTC', invoice: 'lnbc1' }}
${'could not parse hex string: refundPublicKey'} | ${{ to: 'BTC', from: 'L-BTC', invoice: 'lnbc1', refundPublicKey: 'notHex' }}
`(
'should not create submarine swaps with invalid parameters ($error)',
Expand Down Expand Up @@ -673,7 +672,6 @@ describe('SwapRouter', () => {
${'undefined parameter: from'} | ${{ to: 'L-BTC' }}
${'undefined parameter: preimageHash'} | ${{ to: 'L-BTC', from: 'BTC' }}
${'could not parse hex string: preimageHash'} | ${{ to: 'L-BTC', from: 'BTC', preimageHash: 'notHex' }}
${'undefined parameter: claimPublicKey'} | ${{ to: 'L-BTC', from: 'BTC', preimageHash: '00' }}
${'could not parse hex string: claimPublicKey'} | ${{ to: 'L-BTC', from: 'BTC', preimageHash: '00', claimPublicKey: 'notHex' }}
${'could not parse hex string: claimPublicKey'} | ${{ to: 'L-BTC', from: 'BTC', preimageHash: '00', claimPublicKey: 'notHex' }}
`(
Expand Down
2 changes: 1 addition & 1 deletion test/unit/rates/providers/RateProviderTaproot.spec.ts
Expand Up @@ -395,7 +395,7 @@ describe('RateProviderTaproot', () => {
currency | expected
${'BTC'} | ${true}
${'L-BTC'} | ${true}
${'R-BTC'} | ${false}
${'R-BTC'} | ${true}
${'CASHU'} | ${false}
`(
'should check if $currency can be used onchain',
Expand Down

0 comments on commit d0dbe53

Please sign in to comment.