Skip to content

Commit

Permalink
feat: Taproot swaps (apotdevin#611)
Browse files Browse the repository at this point in the history
  • Loading branch information
michael1011 authored and okjodom committed Jul 26, 2024
1 parent aa37e00 commit ecf50b0
Show file tree
Hide file tree
Showing 10 changed files with 260 additions and 88 deletions.
48 changes: 23 additions & 25 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"@nestjs/throttler": "^5.0.1",
"@nestjs/websockets": "^10.2.10",
"@tanstack/react-table": "^8.10.7",
"@vulpemventures/secp256k1-zkp": "^3.2.1",
"apollo-server-express": "^3.13.0",
"balanceofsatoshis": "^17.5.2",
"bcryptjs": "^2.4.3",
Expand All @@ -58,7 +59,7 @@
"bip32": "^4.0.0",
"bip39": "^3.1.0",
"bitcoinjs-lib": "^6.1.5",
"boltz-core": "^1.0.4",
"boltz-core": "^2.1.1",
"cookie": "^0.6.0",
"cross-env": "^7.0.3",
"crypto-js": "^4.1.1",
Expand Down
2 changes: 1 addition & 1 deletion schema.gql
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,7 @@ type MessageType {
type Mutation {
addPeer(isTemporary: Boolean, publicKey: String, socket: String, url: String): Boolean!
bosRebalance(avoid: [String!], in_through: String, max_fee: Float, max_fee_rate: Float, max_rebalance: Float, node: String, out_inbound: Float, out_through: String, timeout_minutes: Float): BosRebalanceResult!
claimBoltzTransaction(destination: String!, fee: Float!, preimage: String!, privateKey: String!, redeem: String!, transaction: String!): String!
claimBoltzTransaction(destination: String!, fee: Float!, id: String!, preimage: String!, privateKey: String!, redeem: String!, transaction: String!): String!
claimGhostAddress(address: String): ClaimGhostAddress!
closeChannel(forceClose: Boolean, id: String!, targetConfirmations: Float, tokensPerVByte: Float): OpenOrCloseChannel!
createAddress(type: String! = "p2tr"): String!
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src/client/src/graphql/mutations/claimBoltzTransaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { gql } from '@apollo/client';

export const CLAIM_BOLTZ_TRANSACTION = gql`
mutation ClaimBoltzTransaction(
$id: String!
$redeem: String!
$transaction: String!
$preimage: String!
Expand All @@ -10,6 +11,7 @@ export const CLAIM_BOLTZ_TRANSACTION = gql`
$fee: Float!
) {
claimBoltzTransaction(
id: $id
redeem: $redeem
transaction: $transaction
preimage: $preimage
Expand Down
1 change: 1 addition & 0 deletions src/client/src/graphql/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,7 @@ export type MutationBosRebalanceArgs = {
export type MutationClaimBoltzTransactionArgs = {
destination: Scalars['String']['input'];
fee: Scalars['Float']['input'];
id: Scalars['String']['input'];
preimage: Scalars['String']['input'];
privateKey: Scalars['String']['input'];
redeem: Scalars['String']['input'];
Expand Down
6 changes: 4 additions & 2 deletions src/client/src/views/swap/SwapClaim.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ export const SwapClaim = () => {
}

const claimingSwap = swaps[claim];
const { redeemScript, preimage, receivingAddress, privateKey } = claimingSwap;
const { redeemScript, preimage, receivingAddress, privateKey, id } =
claimingSwap;

if (!preimage || !transactionHex || !privateKey) {
return <Missing />;
Expand Down Expand Up @@ -129,7 +130,7 @@ export const SwapClaim = () => {
</MultiButton>
</InputWithDeco>
)}
<InputWithDeco title={'Fee Amount'} amount={fee * 223} noInput={true}>
<InputWithDeco title={'Fee Amount'} amount={fee * 111} noInput={true}>
{type !== 'none' && (
<Input
maxWidth={'240px'}
Expand Down Expand Up @@ -176,6 +177,7 @@ export const SwapClaim = () => {
onClick={() =>
claimTransaction({
variables: {
id,
redeem: redeemScript,
transaction: transactionHex,
preimage,
Expand Down
49 changes: 47 additions & 2 deletions src/server/modules/api/boltz/boltz.helpers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
import { address, Network, networks } from 'bitcoinjs-lib';
import { ECPairFactory, ECPairAPI } from 'ecpair';
import { Secp256k1ZKP } from '@vulpemventures/secp256k1-zkp';
import { address, Network, networks, Transaction } from 'bitcoinjs-lib';
import {
detectSwap,
extractRefundPublicKeyFromReverseSwapTree,
Musig,
TaprootUtils,
} from 'boltz-core';
import { SwapTree } from 'boltz-core/dist/lib/consts/Types';
import { randomBytes } from 'crypto';
import { ECPairFactory, ECPairAPI, ECPairInterface } from 'ecpair';
import * as ecc from 'tiny-secp256k1';

const ECPair: ECPairAPI = ECPairFactory(ecc);
Expand Down Expand Up @@ -33,3 +42,39 @@ export const generateKeys = (network: Network = networks.bitcoin) => {
privateKey: getHexString(keys.privateKey),
};
};

export const findTaprootOutput = (
zkp: Secp256k1ZKP,
transaction: Transaction,
tree: SwapTree,
keys: ECPairInterface
) => {
const theirPublicKey = extractRefundPublicKeyFromReverseSwapTree(tree);

// "brute force" the tie breaker because it is not in the onchain script
// https://medium.com/blockstream/reducing-bitcoin-transaction-sizes-with-x-only-pubkeys-f86476af05d7
for (const tieBreaker of ['02', '03']) {
const compressedKey = Buffer.concat([
getHexBuffer(tieBreaker),
theirPublicKey,
]);

const musig = new Musig(zkp, keys, randomBytes(32), [
compressedKey,
keys.publicKey,
]);
const tweakedKey = TaprootUtils.tweakMusig(musig, tree.tree);

const swapOutput = detectSwap(tweakedKey, transaction);
if (swapOutput !== undefined) {
return {
musig,
tweakedKey,
swapOutput,
theirPublicKey: compressedKey,
};
}
}

return undefined;
};
Loading

0 comments on commit ecf50b0

Please sign in to comment.