Skip to content
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

Feat/LIVE-1414 RBF new implementation for Bitcoin #502

Merged
merged 4 commits into from
Jun 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/fresh-timers-dress.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"ledger-live-desktop": major
"@ledgerhq/live-common": major
---

Bitcoin Rbf new implementation. Jira ticket: LIVE-1414, LIVE-1415, LIVE-1416
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,6 @@ const swapEvents = [
rbf: false,
utxoStrategy: {
strategy: 0,
pickUnconfirmedRBF: false,
excludeUTXOs: [],
},
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export const CoinControlRow = ({
input => input.previousOutputIndex === utxo.outputIndex && input.previousTxHash === utxo.hash,
);

const unconfirmed = utxoStatus === "pickUnconfirmedRBF" || utxoStatus === "pickPendingNonRBF";
const unconfirmed = utxoStatus === "pickPendingUtxo";
const last = !s.excluded && totalExcludedUTXOS + 1 === account.bitcoinResources?.utxos.length; // make sure that at least one utxo is selected
const disabled = unconfirmed || last;

Expand All @@ -87,7 +87,7 @@ export const CoinControlRow = ({
return (
<Container disabled={unconfirmed} flow={2} horizontal alignItems="center" onClick={onClick}>
{unconfirmed ? (
<Tooltip content={<Trans i18nKey={"bitcoin.cannotSelect.unconfirmed"} />}>
<Tooltip content={<Trans i18nKey={"bitcoin.cannotSelect.pending"} />}>
<InfoCircle size={16} />
</Tooltip>
) : last ? (
Expand Down Expand Up @@ -118,10 +118,6 @@ export const CoinControlRow = ({
<Text ff="Inter|Medium" fontSize={3} color={"palette.text.shade50"}>
{account.blockHeight - utxo.blockHeight + " confirmations"}
</Text>
) : utxo.rbf ? (
<Text ff="Inter|Medium" fontSize={3} color={"alertRed"}>
<Trans i18nKey="bitcoin.replaceable" />
</Text>
) : (
<Text ff="Inter|Medium" fontSize={3} color={"alertRed"}>
<Trans i18nKey="bitcoin.pending" />
Expand Down

This file was deleted.

32 changes: 0 additions & 32 deletions apps/ledger-live-desktop/src/renderer/families/bitcoin/RBF.js

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ import Tooltip from "~/renderer/components/Tooltip";
import SelectFeeStrategy from "~/renderer/components/SelectFeeStrategy";
import CoinControlModal from "./CoinControlModal";
import { FeesField } from "./FeesField";
import { PickUnconfirmedRBF } from "./PickUnconfirmedRBF";
import { RBF } from "./RBF";
import useBitcoinPickingStrategy from "./useBitcoinPickingStrategy";
import { useFeesStrategy } from "@ledgerhq/live-common/lib/families/bitcoin/react";
import SendFeeMode from "~/renderer/components/SendFeeMode";
Expand All @@ -43,13 +41,6 @@ const Separator = styled.div`
margin: 20px 0;
`;

const InputBox = styled(Box)`
margin-top: 0;
& > * > * {
margin-bottom: 12px;
}
`;

const Fields = ({
transaction,
account,
Expand Down Expand Up @@ -128,20 +119,6 @@ const Fields = ({
</Box>
</Box>
<Separator />
<InputBox>
<RBF
transaction={transaction}
account={account}
onChange={onChange}
status={status}
/>
<PickUnconfirmedRBF
transaction={transaction}
account={account}
onChange={onChange}
status={status}
/>
</InputBox>
<CoinControlModal
transaction={transaction}
account={account}
Expand Down
2 changes: 1 addition & 1 deletion apps/ledger-live-desktop/static/i18n/en/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -2086,10 +2086,10 @@
"replaceable": "replaceable",
"cannotSelect": {
"unconfirmed": "You cannot select coins from unconfirmed, replaceable transactions.",
"pending": "You cannot select coins from pending transactions. (except your change output)",
"last": "You need at least one selected"
},
"pending": "pending",
"pickUnconfirmedRBF": "Include coins from unconfirmed, replaceable transactions.",
"pickingStrategy": "UTXO picking strategy",
"pickingStrategyLabels": {
"DEEP_OUTPUTS_FIRST": "Oldest coins first (FIFO)",
Expand Down
2 changes: 1 addition & 1 deletion apps/ledger-live-desktop/tests/models/DeviceAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ export class DeviceAction {
amount: { s: 1, e: 0, c: [1] },
recipient: "1Cz2ZXb6Y6AacXJTpo4RBjQMLEmscuxD8e",
rbf: false,
utxoStrategy: { strategy: 0, pickUnconfirmedRBF: false, excludeUTXOs: [] },
utxoStrategy: { strategy: 0, excludeUTXOs: [] },
family: "bitcoin",
feePerByte: { s: 1, e: 0, c: [1] },
networkInfo: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,7 @@ describe("testing estimateMaxSpendable", () => {

it("should estimate max spendable correctly", async () => {
await wallet.syncAccount(account);
let maxSpendable = await wallet.estimateAccountMaxSpendable(
account,
0,
[],
true
);
let maxSpendable = await wallet.estimateAccountMaxSpendable(account, 0, []);
const balance = 109088;
expect(maxSpendable.toNumber()).toEqual(balance);
const maxSpendableExcludeUtxo = await wallet.estimateAccountMaxSpendable(
Expand All @@ -43,16 +38,14 @@ describe("testing estimateMaxSpendable", () => {
hash: "f80246be50064bb254d2cad82fb0d4ce7768582b99c113694e72411f8032fd7a",
outputIndex: 0,
},
],
true
]
);
expect(maxSpendableExcludeUtxo.toNumber()).toEqual(balance - 1000);
let feesPerByte = 100;
maxSpendable = await wallet.estimateAccountMaxSpendable(
account,
feesPerByte,
[],
true
[]
);
expect(maxSpendable.toNumber()).toEqual(
balance -
Expand All @@ -69,8 +62,7 @@ describe("testing estimateMaxSpendable", () => {
maxSpendable = await wallet.estimateAccountMaxSpendable(
account,
feesPerByte,
[],
true
[]
);
expect(maxSpendable.toNumber()).toEqual(0);
}, 60000);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ const transaction: Transaction = {
family: "bitcoin",
utxoStrategy: {
strategy: 0,
pickUnconfirmedRBF: false,
excludeUTXOs: [],
},
rbf: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ const createTransaction = (): Transaction => ({
rbf: false,
utxoStrategy: {
strategy: 0,
pickUnconfirmedRBF: false,
excludeUTXOs: [],
},
});
Expand Down
6 changes: 3 additions & 3 deletions libs/ledger-live-common/src/families/bitcoin/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ const getCacheKeyForCalculateFees = ({
}) =>
`${a.id}_${a.blockHeight || 0}_${t.amount.toString()}_${String(
t.useAllAmount
)}_${t.recipient}_${t.feePerByte ? t.feePerByte.toString() : ""}_${
t.utxoStrategy.pickUnconfirmedRBF ? 1 : 0
}_${t.utxoStrategy.strategy}_${String(t.rbf)}_${t.utxoStrategy.excludeUTXOs
)}_${t.recipient}_${t.feePerByte ? t.feePerByte.toString() : ""}_${0}_${
t.utxoStrategy.strategy
}_${String(t.rbf)}_${t.utxoStrategy.excludeUTXOs
.map(({ hash, outputIndex }) => `${hash}@${outputIndex}`)
.join("+")}`;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,6 @@ const options = [
type: String,
desc: "how much fee per byte",
},
{
name: "pickUnconfirmedRBF",
type: Boolean,
desc: "also pick unconfirmed replaceable txs",
},
{
name: "excludeUTXO",
alias: "E",
Expand Down Expand Up @@ -52,7 +47,6 @@ function inferTransactions(
rbf: opts.rbf || false,
utxoStrategy: {
strategy: bitcoinPickingStrategy[opts["bitcoin-pick-strategy"]] || 0,
pickUnconfirmedRBF: opts.pickUnconfirmedRBF || false,
excludeUTXOs: (opts.excludeUTXO || []).map((str) => {
const [hash, index] = str.split("@");
invariant(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ const dataset: CurrenciesData<Transaction> = {
rbf: false,
utxoStrategy: {
strategy: 0,
pickUnconfirmedRBF: false,
excludeUTXOs: [],
},
}),
Expand All @@ -73,7 +72,6 @@ const dataset: CurrenciesData<Transaction> = {
rbf: false,
utxoStrategy: {
strategy: 0,
pickUnconfirmedRBF: false,
excludeUTXOs: [],
},
}),
Expand All @@ -99,7 +97,6 @@ const dataset: CurrenciesData<Transaction> = {
rbf: false,
utxoStrategy: {
strategy: 0,
pickUnconfirmedRBF: false,
excludeUTXOs: [],
},
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ const dataset: CurrenciesData<Transaction> = {
rbf: false,
utxoStrategy: {
strategy: 0,
pickUnconfirmedRBF: false,
excludeUTXOs: [],
},
}),
Expand All @@ -69,7 +68,6 @@ const dataset: CurrenciesData<Transaction> = {
rbf: false,
utxoStrategy: {
strategy: 0,
pickUnconfirmedRBF: false,
excludeUTXOs: [],
},
}),
Expand All @@ -92,7 +90,6 @@ const dataset: CurrenciesData<Transaction> = {
rbf: false,
utxoStrategy: {
strategy: 0,
pickUnconfirmedRBF: false,
excludeUTXOs: [],
},
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ const dataset: CurrenciesData<Transaction> = {
rbf: false,
utxoStrategy: {
strategy: 0,
pickUnconfirmedRBF: false,
excludeUTXOs: [],
},
}),
Expand All @@ -70,7 +69,6 @@ const dataset: CurrenciesData<Transaction> = {
rbf: false,
utxoStrategy: {
strategy: 0,
pickUnconfirmedRBF: false,
excludeUTXOs: [],
},
}),
Expand All @@ -93,7 +91,6 @@ const dataset: CurrenciesData<Transaction> = {
rbf: false,
utxoStrategy: {
strategy: 0,
pickUnconfirmedRBF: false,
excludeUTXOs: [],
},
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ export const buildTransaction = async (
walletAccount,
transaction.feePerByte.toNumber(), //!\ wallet-btc handles fees as JS number
transaction.utxoStrategy.excludeUTXOs,
transaction.utxoStrategy.pickUnconfirmedRBF,
[transaction.recipient]
);
log("btcwallet", "building transaction", transaction);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ const createTransaction = (): Transaction => {
amount: new BigNumber(0),
utxoStrategy: {
strategy: 0,
pickUnconfirmedRBF: false,
excludeUTXOs: [],
},
recipient: "",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ const estimateMaxSpendable = async ({
walletAccount,
feePerByte.toNumber(), //!\ wallet-btc handles fees as JS number
transaction?.utxoStrategy?.excludeUTXOs || [],
transaction?.utxoStrategy?.pickUnconfirmedRBF || false,
transaction ? [transaction.recipient] : []
);
return maxSpendable.lt(0) ? new BigNumber(0) : maxSpendable;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,18 @@ const toWalletNetwork = (currencyId: string): "testnet" | "mainnet" => {
};

// Map wallet-btc's Output to LL's BitcoinOutput
const fromWalletUtxo = (utxo: WalletOutput): BitcoinOutput => {
const fromWalletUtxo = (
utxo: WalletOutput,
changeAddresses: Set<string>
): BitcoinOutput => {
return {
hash: utxo.output_hash,
outputIndex: utxo.output_index,
blockHeight: utxo.block_height,
address: utxo.address,
value: new BigNumber(utxo.value),
rbf: utxo.rbf,
isChange: false, // wallet-btc limitation: doesn't provide it
isChange: changeAddresses.has(utxo.address),
};
};

Expand Down Expand Up @@ -349,7 +352,7 @@ const getAccountShape: GetAccountShape = async (info) => {
const newUniqueOperations = deduplicateOperations(newOperations);
const operations = mergeOps(oldOperations, newUniqueOperations);
const rawUtxos = await wallet.getAccountUnspentUtxos(walletAccount);
const utxos = rawUtxos.map(fromWalletUtxo);
const utxos = rawUtxos.map((utxo) => fromWalletUtxo(utxo, changeAddresses));
return {
id: accountId,
xpub,
Expand Down
Loading