-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: migrate bitcoin generate txs, closes LEA-1735
- Loading branch information
Showing
41 changed files
with
771 additions
and
190 deletions.
There are no files selected for viewing
75 changes: 75 additions & 0 deletions
75
apps/mobile/src/common/transactions/bitcoin-transactions.hooks.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import { useCallback } from 'react'; | ||
|
||
import { useNetworkPreferenceBitcoinScureLibNetworkConfig } from '@/store/settings/settings.read'; | ||
import { t } from '@lingui/macro'; | ||
|
||
import { | ||
CoinSelectionRecipient, | ||
CoinSelectionUtxo, | ||
determineUtxosForSpend, | ||
determineUtxosForSpendAll, | ||
generateUnsignedTransactionNativeSegwit, | ||
} from '@leather.io/bitcoin'; | ||
import type { Money } from '@leather.io/models'; | ||
|
||
export interface BitcoinTransactionValues { | ||
amount: Money; | ||
recipients: CoinSelectionRecipient[]; | ||
} | ||
|
||
export function useBtcPayerDetails(address: string, publicKey: string) { | ||
const network = useNetworkPreferenceBitcoinScureLibNetworkConfig(); | ||
|
||
return { | ||
network, | ||
payerAddress: address, | ||
payerPublicKey: publicKey, | ||
}; | ||
} | ||
|
||
export interface GenerateBtcUnsignedTransactionCallbackArgs { | ||
feeRate: number; | ||
isSendingMax?: boolean; | ||
utxos: CoinSelectionUtxo[]; | ||
values: BitcoinTransactionValues; | ||
} | ||
|
||
export function useGenerateBtcUnsignedTransactionNativeSegwit( | ||
btcPayerDetails: ReturnType<typeof useBtcPayerDetails> | ||
) { | ||
return useCallback( | ||
async ({ | ||
feeRate, | ||
isSendingMax, | ||
utxos, | ||
values, | ||
}: GenerateBtcUnsignedTransactionCallbackArgs) => { | ||
try { | ||
const determineUtxosArgs = { | ||
feeRate, | ||
recipients: values.recipients, | ||
utxos, | ||
}; | ||
|
||
const { inputs, outputs, fee } = isSendingMax | ||
? determineUtxosForSpendAll(determineUtxosArgs) | ||
: determineUtxosForSpend(determineUtxosArgs); | ||
|
||
if (!inputs.length) throw new Error('No inputs to sign'); | ||
if (!outputs.length) throw new Error('No outputs to sign'); | ||
|
||
return generateUnsignedTransactionNativeSegwit({ | ||
...btcPayerDetails, | ||
inputs, | ||
outputs, | ||
fee, | ||
}); | ||
} catch (e) { | ||
// eslint-disable-next-line no-console | ||
console.log(t`Error signing bitcoin transaction`, e); | ||
return null; | ||
} | ||
}, | ||
[btcPayerDetails] | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
77 changes: 74 additions & 3 deletions
77
apps/mobile/src/features/send/send-form/hooks/use-send-form-btc.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,24 +1,95 @@ | ||
import { useCallback } from 'react'; | ||
|
||
import { | ||
useBtcPayerDetails, | ||
useGenerateBtcUnsignedTransactionNativeSegwit, | ||
} from '@/common/transactions/bitcoin-transactions.hooks'; | ||
import BigNumber from 'bignumber.js'; | ||
|
||
import { CoinSelectionRecipient, CoinSelectionUtxo, getBitcoinFees } from '@leather.io/bitcoin'; | ||
import { AverageBitcoinFeeRates } from '@leather.io/models'; | ||
import { Utxo } from '@leather.io/query'; | ||
import { createMoneyFromDecimal } from '@leather.io/utils'; | ||
|
||
import { | ||
CreateCurrentSendRoute, | ||
useSendSheetNavigation, | ||
useSendSheetRoute, | ||
} from '../../send-form.utils'; | ||
import { SendFormStxSchema } from '../schemas/send-form-stx.schema'; | ||
import { SendFormBtcContext } from '../providers/send-form-btc-provider'; | ||
import { SendFormBtcSchema } from '../schemas/send-form-btc.schema'; | ||
|
||
type CurrentRoute = CreateCurrentSendRoute<'send-form-btc'>; | ||
|
||
function parseSendFormValues(values: SendFormBtcSchema) { | ||
return { | ||
amount: createMoneyFromDecimal(new BigNumber(values.amount), 'BTC'), | ||
recipients: [ | ||
{ | ||
address: values.recipient, | ||
amount: createMoneyFromDecimal(new BigNumber(values.amount), 'BTC'), | ||
}, | ||
], | ||
}; | ||
} | ||
|
||
function createCoinSelectionUtxos(utxos: Utxo[]): CoinSelectionUtxo[] { | ||
return utxos.map(utxo => ({ | ||
address: utxo.address, | ||
txid: utxo.txid, | ||
value: Number(utxo.value), | ||
vout: utxo.vout, | ||
})); | ||
} | ||
|
||
export function useSendFormBtc() { | ||
const route = useSendSheetRoute<CurrentRoute>(); | ||
const navigation = useSendSheetNavigation<CurrentRoute>(); | ||
const btcPayerDetails = useBtcPayerDetails(route.params.address, route.params.publicKey); | ||
|
||
const getTransactionFees = useCallback( | ||
( | ||
feeRates: AverageBitcoinFeeRates, | ||
recipients: CoinSelectionRecipient[], | ||
utxos: CoinSelectionUtxo[] | ||
) => getBitcoinFees({ feeRates, isSendingMax: false, recipients, utxos }), | ||
[] | ||
); | ||
|
||
const generateTx = useGenerateBtcUnsignedTransactionNativeSegwit(btcPayerDetails); | ||
|
||
return { | ||
onGoBack() { | ||
navigation.navigate('send-select-asset', { account: route.params.account }); | ||
}, | ||
// Temporary logs until we can hook up to approver flow | ||
async onInitSendTransfer(values: SendFormStxSchema) { | ||
async onInitSendTransfer(data: SendFormBtcContext, values: SendFormBtcSchema) { | ||
// eslint-disable-next-line no-console, lingui/no-unlocalized-strings | ||
console.log('Send form data:', parseSendFormValues(values)); | ||
|
||
const parsedSendFormValues = parseSendFormValues(values); | ||
const coinSelectionUtxos = createCoinSelectionUtxos(data.utxos); | ||
|
||
const tx = await generateTx({ | ||
feeRate: Number(values.feeRate), | ||
values: parsedSendFormValues, | ||
utxos: coinSelectionUtxos, | ||
}); | ||
|
||
const fees = getTransactionFees( | ||
data.feeRates, | ||
parsedSendFormValues.recipients, | ||
coinSelectionUtxos | ||
); | ||
|
||
// Show an error toast here? | ||
if (!tx) throw new Error('Attempted to generate raw tx, but no tx exists'); | ||
// eslint-disable-next-line no-console, lingui/no-unlocalized-strings | ||
console.log('tx hex:', tx.hex); | ||
// eslint-disable-next-line no-console, lingui/no-unlocalized-strings | ||
console.log('psbt:', tx.psbt); | ||
// eslint-disable-next-line no-console, lingui/no-unlocalized-strings | ||
console.log('Send form data:', values); | ||
console.log('fees:', fees); | ||
}, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
28 changes: 15 additions & 13 deletions
28
apps/mobile/src/features/send/send-form/loaders/send-form-btc-loader.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,29 +1,31 @@ | ||
import { AccountId } from '@/models/domain.model'; | ||
import { useBitcoinAccountTotalBitcoinBalance } from '@/queries/balance/bitcoin-balance.query'; | ||
import BigNumber from 'bignumber.js'; | ||
import { | ||
useBitcoinAccountTotalBitcoinBalance, | ||
useBitcoinAccountUtxos, | ||
} from '@/queries/balance/bitcoin-balance.query'; | ||
|
||
import { Money } from '@leather.io/models'; | ||
import { useAverageBitcoinFeeRates } from '@leather.io/query'; | ||
import { AverageBitcoinFeeRates, Money } from '@leather.io/models'; | ||
import { Utxo, useAverageBitcoinFeeRates } from '@leather.io/query'; | ||
|
||
interface SendFormBtcData { | ||
availableBalance: Money; | ||
fiatBalance: Money; | ||
feeRates: Record<string, BigNumber>; | ||
feeRates: AverageBitcoinFeeRates; | ||
utxos: Utxo[]; | ||
} | ||
|
||
interface SendFormBtcLoaderProps { | ||
account: AccountId; | ||
children({ availableBalance, fiatBalance, feeRates }: SendFormBtcData): React.ReactNode; | ||
children({ availableBalance, fiatBalance, feeRates, utxos }: SendFormBtcData): React.ReactNode; | ||
} | ||
export function SendFormBtcLoader({ account, children }: SendFormBtcLoaderProps) { | ||
// Not sure if we need to load feeRates here? | ||
const accountId = { fingerprint: account.fingerprint, accountIndex: account.accountIndex }; | ||
const { data: feeRates } = useAverageBitcoinFeeRates(); | ||
const { availableBalance, fiatBalance } = useBitcoinAccountTotalBitcoinBalance({ | ||
accountIndex: account.accountIndex, | ||
fingerprint: account.fingerprint, | ||
}); | ||
const { data: utxos = [] } = useBitcoinAccountUtxos(accountId); | ||
const { availableBalance, fiatBalance } = useBitcoinAccountTotalBitcoinBalance(accountId); | ||
|
||
if (!feeRates) return null; | ||
// Handle loading and error states | ||
if (!utxos.length || !feeRates) return null; | ||
|
||
return children({ availableBalance, fiatBalance, feeRates }); | ||
return children({ availableBalance, fiatBalance, feeRates, utxos }); | ||
} |
Oops, something went wrong.