on-chain send max

swap to channel max
This commit is contained in:
Paul Miller
2023-06-15 14:43:51 -05:00
committed by benthecarman
parent d24b276115
commit c9647b568c
3 changed files with 106 additions and 23 deletions

View File

@@ -73,7 +73,21 @@ export function AmountCard(props: {
isAmountEditable?: boolean;
setAmountSats?: (amount: bigint) => void;
skipWarnings?: boolean;
maxAmountSats?: bigint;
}) {
// Normally we want to add the fee to the amount, but for max amount we just show the max
const totalOrTotalLessFee = () => {
console.log(props.amountSats, props.fee, props.maxAmountSats);
if (
props.fee &&
props.maxAmountSats &&
props.amountSats === props.maxAmountSats?.toString()
) {
return props.maxAmountSats.toLocaleString();
} else {
return add(props.amountSats, props.fee).toString();
}
};
return (
<Card>
<VStack>
@@ -98,6 +112,8 @@ export function AmountCard(props: {
: noop
}
skipWarnings={props.skipWarnings}
maxAmountSats={props.maxAmountSats}
fee={props.fee}
/>
</Show>
</KeyValue>
@@ -108,12 +124,7 @@ export function AmountCard(props: {
<hr class="border-white/20" />
<div class="flex flex-col gap-1">
<KeyValue key="Total">
<InlineAmount
amount={add(
props.amountSats,
props.fee
).toString()}
/>
<InlineAmount amount={totalOrTotalLessFee()} />
</KeyValue>
<USDShower
amountSats={props.amountSats}
@@ -166,6 +177,8 @@ export function AmountCard(props: {
: noop
}
skipWarnings={props.skipWarnings}
maxAmountSats={props.maxAmountSats}
fee={props.fee}
/>
</Show>
</KeyValue>

View File

@@ -138,6 +138,8 @@ export const AmountEditable: ParentComponent<{
initialOpen: boolean;
setAmountSats: (s: bigint) => void;
skipWarnings?: boolean;
maxAmountSats?: bigint;
fee?: string;
}> = (props) => {
const [isOpen, setIsOpen] = createSignal(props.initialOpen);
const [state, _actions] = useMegaStore();
@@ -280,6 +282,22 @@ export const AmountEditable: ParentComponent<{
}
}
// If the user is trying to send the max amount we want to show max minus fee
// Otherwise we just the actual amount they've entered
const maxOrLocalSats = () => {
if (
props.maxAmountSats &&
props.fee &&
props.maxAmountSats === BigInt(localSats())
) {
return (
Number(props.maxAmountSats) - Number(props.fee)
).toLocaleString();
} else {
return localSats();
}
};
return (
<Dialog.Root open={isOpen()}>
<button
@@ -292,7 +310,7 @@ export const AmountEditable: ParentComponent<{
<div class="inline-block font-semibold">Set amount</div>
}
>
<InlineAmount amount={localSats()} />
<InlineAmount amount={maxOrLocalSats()} />
</Show>
<img src={pencil} alt="Edit" />
{/* {props.children} */}
@@ -383,6 +401,19 @@ export const AmountEditable: ParentComponent<{
</button>
)}
</For>
<Show when={props.maxAmountSats}>
<button
onClick={() => {
setFixedAmount(
props.maxAmountSats!.toString()
);
focus();
}}
class="py-2 px-4 rounded-lg bg-white/10"
>
MAX
</button>
</Show>
</div>
<div class="grid grid-cols-3 w-full flex-none">
<For each={CHARACTERS}>

View File

@@ -232,17 +232,26 @@ export default function Send() {
setFieldDestination("");
}
const maxOnchain = createMemo(() => {
return (
(state.balance?.confirmed ?? 0n) +
(state.balance?.unconfirmed ?? 0n)
);
});
const isMax = () => {
if (source() === "onchain") {
return amountSats() === maxOnchain();
}
};
const insufficientFunds = () => {
if (source() === "onchain") {
return (
(state.balance?.confirmed ?? 0n) +
(state.balance?.unconfirmed ?? 0n) <
amountSats()
);
return maxOnchain() < amountSats();
}
if (source() === "lightning") {
return (
(state.balance?.lightning ?? 0n) < amountSats() &&
(state.balance?.lightning ?? 0n) <= amountSats() &&
setError(
"We do not have enough balance to pay the given amount."
)
@@ -251,7 +260,10 @@ export default function Send() {
};
const feeEstimate = () => {
if (source() === "lightning") return undefined;
if (source() === "lightning") {
setError(undefined);
return undefined;
}
if (
source() === "onchain" &&
@@ -260,7 +272,15 @@ export default function Send() {
address()
) {
setError(undefined);
try {
// If max we want to use the sweep fee estimator
if (isMax()) {
return state.mutiny_wallet?.estimate_sweep_tx_fee(
address()!
);
}
return state.mutiny_wallet?.estimate_tx_fee(
address()!,
amountSats(),
@@ -465,15 +485,28 @@ export default function Send() {
sentDetails.amount = amountSats();
}
} else if (source() === "onchain" && address()) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const txid = await state.mutiny_wallet?.send_to_address(
address()!,
amountSats(),
tags
);
sentDetails.amount = amountSats();
sentDetails.destination = address();
sentDetails.txid = txid;
if (isMax()) {
// If we're trying to send the max amount, use the sweep method instead of regular send
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const txid = await state.mutiny_wallet?.sweep_wallet(
address()!,
tags
);
sentDetails.amount = amountSats();
sentDetails.destination = address();
sentDetails.txid = txid;
} else {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const txid = await state.mutiny_wallet?.send_to_address(
address()!,
amountSats(),
tags
);
sentDetails.amount = amountSats();
sentDetails.destination = address();
sentDetails.txid = txid;
}
}
setSentDetails(sentDetails as SentDetails);
clearAll();
@@ -500,6 +533,10 @@ export default function Send() {
const network = state.mutiny_wallet?.get_network() as Network;
const maxAmountSats = createMemo(() => {
return source() === "onchain" ? maxOnchain() : undefined;
});
return (
<MutinyWalletGuard>
<SafeArea>
@@ -611,6 +648,8 @@ export default function Send() {
setAmountSats={setAmountSats}
fee={feeEstimate()?.toString()}
isAmountEditable={!invoice()?.amount_sats}
maxAmountSats={maxAmountSats()}
skipWarnings={true}
/>
</Match>
<Match when={true}>