-
Notifications
You must be signed in to change notification settings - Fork 34
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Spend to Taproot #91
Spend to Taproot #91
Changes from all commits
8b72e86
6b8f3bc
dcfc0ec
4ed5e74
a826fff
801bc78
dacc5eb
ca8a8b3
bce2d08
fda1072
36b2530
09e5a67
698091f
0df5bc6
6b987c3
32fbd9b
01ff296
77e177e
575aeeb
404e160
82f0ea3
9d5f8da
8235f8d
14c6b76
fd6e7c8
2b8c899
eed8801
1dc8d13
223efc9
85528b7
7550bd1
9e4a19e
f2e06a7
b426ae1
8226c95
15bb709
4088c6e
0c969cc
29ac63b
e098a8b
8cab8d3
3280982
83a81c4
185c261
3b8b75f
80fbd51
43f4f99
9183567
f2768ca
4f17031
e6a6b45
37d46d6
4b8c95e
f0486bf
81c17fa
24c5c5b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@caravan/psbt": minor | ||
--- | ||
|
||
export of new utils for psbt v0 handling. Primarily adds support for taproot outputs by upgrading to bitcoinjs-lib v6 depedency. Upgrades to a new API from legacy utils from caravan/bitcoin and includes some utilities and types for handling conversions. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@caravan/bitcoin": minor | ||
--- | ||
|
||
export signature utilities from caravan/bitcoin to support new psbt tooling |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@caravan/wallets": minor | ||
--- | ||
|
||
upgrading psbt generation to support taproot outputs and new caravan/psbt utils |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@caravan/multisig": major | ||
--- | ||
|
||
New package for multisig wallet utilities and types to share across other packages |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@caravan/bitcoin": minor | ||
--- | ||
|
||
transaction parser was stripping out network information from global xpubs being added to psbt. global xpubs will now respect the network and include appropriate prefix |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"caravan-coordinator": minor | ||
--- | ||
|
||
upgrade tx processing utils to use new psbt utils for taproot output support |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
"@caravan/wallets": patch | ||
"caravan-coordinator": patch | ||
--- | ||
|
||
fixes an issue where esbuild was polyfilling process.env which breaks the ability to override trezor connect settings and pass other env vars at run time in dependent applications |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@caravan/eslint-config": patch | ||
--- | ||
|
||
initiliazing package, upgrading deps. need to improve shared config before major release |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import type { JestConfigWithTsJest } from "ts-jest"; | ||
|
||
const config: JestConfigWithTsJest = { | ||
testEnvironment: "jsdom", | ||
transform: { | ||
"\\.[jt]sx?$": "babel-jest", | ||
}, | ||
transformIgnorePatterns: ["^.+\\.module\\.(css|sass|scss)$"], | ||
moduleNameMapper: { | ||
"^.+\\.module\\.(css|sass|scss)$": "identity-obj-proxy", | ||
}, | ||
moduleFileExtensions: [ | ||
"web.cjs", | ||
"js", | ||
"web.ts", | ||
"ts", | ||
"web.tsx", | ||
"tsx", | ||
"json", | ||
"web.cjsx", | ||
"jsx", | ||
"node", | ||
], | ||
setupFilesAfterEnv: ["<rootDir>/jest.setup.ts"], | ||
}; | ||
|
||
export default config; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
import "@inrupt/jest-jsdom-polyfills"; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,6 @@ import PropTypes from "prop-types"; | |
import { connect } from "react-redux"; | ||
import { | ||
validateHex, | ||
validateMultisigSignature, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is one of three legacy functions that needed to be replaced. |
||
multisigBIP32Path, | ||
multisigBIP32Root, | ||
validateBIP32Path, | ||
|
@@ -38,6 +37,12 @@ import { | |
} from "../../actions/signatureImporterActions"; | ||
import { setSigningKey as setSigningKeyAction } from "../../actions/transactionActions"; | ||
import { downloadFile } from "../../utils"; | ||
import { | ||
convertLegacyInput, | ||
convertLegacyOutput, | ||
getUnsignedMultisigPsbtV0, | ||
validateMultisigPsbtSignature, | ||
} from "@caravan/psbt"; | ||
|
||
const TEXT = "text"; | ||
const UNKNOWN = "unknown"; | ||
|
@@ -389,12 +394,17 @@ class SignatureImporter extends React.Component { | |
|
||
let publicKey; | ||
try { | ||
publicKey = validateMultisigSignature( | ||
const args = { | ||
network, | ||
inputs, | ||
outputs, | ||
inputs: inputs.map(convertLegacyInput), | ||
outputs: outputs.map(convertLegacyOutput), | ||
}; | ||
const psbt = getUnsignedMultisigPsbtV0(args); | ||
publicKey = validateMultisigPsbtSignature( | ||
psbt.toBase64(), | ||
inputIndex, | ||
inputSignature, | ||
inputs[inputIndex].amountSats, | ||
); | ||
} catch (e) { | ||
errback(`Signature for input ${inputNumber} is invalid.`); | ||
|
@@ -482,13 +492,17 @@ class SignatureImporter extends React.Component { | |
return; | ||
} | ||
try { | ||
// This returns false if it completes with no error | ||
publicKey = validateMultisigSignature( | ||
const args = { | ||
network, | ||
inputs, | ||
outputs, | ||
inputs: inputs.map(convertLegacyInput), | ||
outputs: outputs.map(convertLegacyOutput), | ||
}; | ||
const psbt = getUnsignedMultisigPsbtV0(args); | ||
publicKey = validateMultisigPsbtSignature( | ||
psbt.toBase64(), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this was a big change in the API. The main functions now operating past the creator role should take a psbt and can extract inputs/output data from there. |
||
inputIndex, | ||
inputSignature, | ||
inputs[inputIndex].amountSats, | ||
); | ||
} catch (e) { | ||
// eslint-disable-next-line no-console | ||
|
@@ -579,7 +593,8 @@ SignatureImporter.propTypes = { | |
}), | ||
).isRequired, | ||
fee: PropTypes.string.isRequired, | ||
inputs: PropTypes.arrayOf(PropTypes.shape({})).isRequired, | ||
inputs: PropTypes.arrayOf(PropTypes.shape({ amountSats: PropTypes.string })) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it actually has mre than this but this value is directly used and so an error was being thrown for not having it declared. I didn't spend too much time building out the proptypes as typescript will obsolete this. |
||
.isRequired, | ||
inputsTotalSats: PropTypes.shape({}).isRequired, | ||
isWallet: PropTypes.bool.isRequired, | ||
network: PropTypes.string.isRequired, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,8 +2,8 @@ import React from "react"; | |
import PropTypes from "prop-types"; | ||
import { connect } from "react-redux"; | ||
import { | ||
signedMultisigTransaction, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a second function that's replaced (it uses |
||
blockExplorerTransactionURL, | ||
addSignaturesToPSBT, | ||
} from "@caravan/bitcoin"; | ||
|
||
import { | ||
|
@@ -21,6 +21,13 @@ import { updateBlockchainClient } from "../../actions/clientActions"; | |
import Copyable from "../Copyable"; | ||
import { externalLink } from "utils/ExternalLink"; | ||
import { setTXID } from "../../actions/transactionActions"; | ||
import { | ||
convertLegacyInput, | ||
convertLegacyOutput, | ||
getUnsignedMultisigPsbtV0, | ||
} from "@caravan/psbt"; | ||
import { Psbt } from "bitcoinjs-lib"; | ||
import { Buffer } from "buffer"; | ||
|
||
class Transaction extends React.Component { | ||
constructor(props) { | ||
|
@@ -34,14 +41,30 @@ class Transaction extends React.Component { | |
|
||
buildSignedTransaction = () => { | ||
const { network, inputs, outputs, signatureImporters } = this.props; | ||
return signedMultisigTransaction( | ||
const args = { | ||
network, | ||
inputs, | ||
outputs, | ||
Object.values(signatureImporters).map( | ||
(signatureImporter) => signatureImporter.signature, | ||
), | ||
); | ||
inputs: inputs.map(convertLegacyInput), | ||
outputs: outputs.map(convertLegacyOutput), | ||
}; | ||
const psbt = getUnsignedMultisigPsbtV0(args); | ||
let partiallySignedTransaction = psbt.toBase64(); | ||
for (const signatureImporter of Object.values(signatureImporters)) { | ||
partiallySignedTransaction = addSignaturesToPSBT( | ||
network, | ||
partiallySignedTransaction, | ||
signatureImporter.publicKeys.map((pubkey) => | ||
Buffer.from(pubkey, "hex"), | ||
), | ||
signatureImporter.signature.map((signature) => | ||
Buffer.from(signature, "hex"), | ||
), | ||
); | ||
} | ||
|
||
return Psbt.fromBase64(partiallySignedTransaction) | ||
.finalizeAllInputs() | ||
.extractTransaction() | ||
.toHex(); | ||
}; | ||
|
||
handleBroadcast = async () => { | ||
|
@@ -52,7 +75,7 @@ class Transaction extends React.Component { | |
let txid = ""; | ||
this.setState({ broadcasting: true }); | ||
try { | ||
txid = await client.broadcastTransaction(signedTransaction.toHex()); | ||
txid = await client.broadcastTransaction(signedTransaction); | ||
} catch (e) { | ||
// eslint-disable-next-line no-console | ||
console.error(e); | ||
|
@@ -71,14 +94,13 @@ class Transaction extends React.Component { | |
|
||
render() { | ||
const { error, broadcasting, txid } = this.state; | ||
const signedTransaction = this.buildSignedTransaction(); | ||
const signedTransactionHex = signedTransaction.toHex(); | ||
const signedTransactionHex = this.buildSignedTransaction(); | ||
return ( | ||
<Card> | ||
<CardHeader title="Broadcast" /> | ||
<CardContent> | ||
<form> | ||
{signedTransaction && ( | ||
{signedTransactionHex && ( | ||
<Box mt={4}> | ||
<Typography variant="h6">Signed Transaction</Typography> | ||
<Copyable text={signedTransactionHex} code showIcon /> | ||
|
@@ -89,7 +111,7 @@ class Transaction extends React.Component { | |
<Button | ||
variant="contained" | ||
color="primary" | ||
disabled={!signedTransaction || broadcasting} | ||
disabled={!signedTransactionHex || broadcasting} | ||
onClick={this.handleBroadcast} | ||
> | ||
Broadcast Transaction | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -278,11 +278,7 @@ class CreateWallet extends React.Component { | |
setTotalSigners(walletConfiguration.quorum.totalSigners); | ||
setRequiredSigners(walletConfiguration.quorum.requiredSigners); | ||
setAddressType(walletConfiguration.addressType); | ||
if (walletConfiguration.network === "regtest") { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we can actually support regtest now. |
||
setNetwork("testnet"); | ||
} else { | ||
setNetwork(walletConfiguration.network); | ||
} | ||
setNetwork(walletConfiguration.network); | ||
updateWalletNameAction(0, walletConfiguration.name); | ||
updateWalletUuid(walletConfiguration.uuid); | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,13 +8,16 @@ import { | |
satoshisToBitcoins, | ||
bitcoinsToSatoshis, | ||
validateAddress, | ||
unsignedMultisigTransaction, | ||
unsignedMultisigPSBT, | ||
unsignedTransactionObjectFromPSBT, | ||
checkFeeRateError, | ||
getFeeErrorMessage, | ||
FeeValidationError, | ||
unsignedMultisigTransaction, | ||
} from "@caravan/bitcoin"; | ||
import { | ||
convertLegacyInput, | ||
convertLegacyOutput, | ||
getUnsignedMultisigPsbtV0, | ||
} from "@caravan/psbt"; | ||
import updateState from "./utils"; | ||
import { SET_NETWORK, SET_ADDRESS_TYPE } from "../actions/settingsActions"; | ||
import { | ||
|
@@ -45,6 +48,7 @@ import { | |
SPEND_STEP_CREATE, | ||
} from "../actions/transactionActions"; | ||
import { RESET_NODES_SPEND } from "../actions/walletActions"; | ||
import { Transaction } from "bitcoinjs-lib"; | ||
|
||
function sortInputs(a, b) { | ||
const x = a.txid.toLowerCase(); | ||
|
@@ -280,16 +284,18 @@ function finalizeOutputs(state, action) { | |
// First try to build the transaction via PSBT, if that fails (e.g. an input doesn't know about its braid), | ||
// then try to build it using the old TransactionBuilder plumbing. | ||
try { | ||
const unsignedTransactionPSBT = unsignedMultisigPSBT( | ||
state.network, | ||
state.inputs, | ||
state.outputs, | ||
); | ||
unsignedTransaction = unsignedTransactionObjectFromPSBT( | ||
unsignedTransactionPSBT, | ||
const args = { | ||
network: state.network, | ||
inputs: state.inputs.map(convertLegacyInput), | ||
outputs: state.outputs.map(convertLegacyOutput), | ||
}; | ||
const psbt = getUnsignedMultisigPsbtV0(args); | ||
unsignedTransaction = Transaction.fromHex( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another example of not needing a specialized function. If we have a psbt, it has the unsignedTx on its globalMap (if v0) so just use that. |
||
psbt.data.globalMap.unsignedTx.toBuffer().toString("hex"), | ||
); | ||
} catch (e) { | ||
// probably has an input that isn't braid aware. | ||
// NOTE: This won't work for txs with taproot outputs | ||
unsignedTransaction = unsignedMultisigTransaction( | ||
state.network, | ||
state.inputs, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
import "@testing-library/jest-dom"; | ||
import BigNumber from "bignumber.js"; | ||
import { | ||
P2WSH, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,12 @@ | ||
import React from "react"; | ||
|
||
import { blockExplorerAddressURL, TEST_FIXTURES } from "@caravan/bitcoin"; | ||
import { | ||
ConfirmMultisigAddress, | ||
LEDGER, | ||
braidDetailsToWalletConfig, | ||
} from "@caravan/wallets"; | ||
import { ConfirmMultisigAddress, LEDGER } from "@caravan/wallets"; | ||
import { Box, Table, TableBody, TableRow, TableCell } from "@mui/material"; | ||
import { externalLink } from "utils/ExternalLink"; | ||
|
||
import Test from "./Test"; | ||
import { braidDetailsToWalletConfig } from "@caravan/multisig"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A few exports were moved to this new internal package (internal because it's not published and only marked as |
||
|
||
class ConfirmMultisigAddressTest extends Test { | ||
name() { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
update to support regtest xpubs