Skip to content

Commit

Permalink
fix(tooling-wallet): Fix staking with ledger (#4296)
Browse files Browse the repository at this point in the history
* feat(wallet): Fix speculos default port

* feat(wallet): Update outdated comment

* feat(wallet): Replace one useDryRunTransaction with new hook to estimate gas budget in StakeForm. Make useDryRunTransaction in StakeForm not trigger a ledger wallet interaction

* feat(wallet): Revert speculos default port change
  • Loading branch information
msarcev authored and Alex6323 committed Dec 4, 2024
1 parent cc81351 commit 42c46d3
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 15 deletions.
1 change: 1 addition & 0 deletions apps/core/src/hooks/stake/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export * from './useTotalDelegatedRewards';
export * from './useTotalDelegatedStake';
export * from './useValidatorInfo';
export * from './useStakeTxnInfo';
export * from './useStakingGasBudgetEstimation';
46 changes: 46 additions & 0 deletions apps/core/src/hooks/stake/useStakingGasBudgetEstimation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import { useMemo } from 'react';
import { useIotaClient } from '@iota/dapp-kit';
import { useQuery } from '@tanstack/react-query';
import { createStakeTransaction } from '../../utils';

interface UseStakingGasBudgetEstimationOptions {
senderAddress: string | null;
validatorAddress: string;
amount: bigint;
}

export function useStakingGasBudgetEstimation({
senderAddress,
validatorAddress,
amount,
}: UseStakingGasBudgetEstimationOptions) {
const client = useIotaClient();

const transaction = useMemo(() => {
return createStakeTransaction(amount, validatorAddress);
}, [amount, validatorAddress]);

return useQuery({
// eslint-disable-next-line @tanstack/query/exhaustive-deps
queryKey: [
'staking-tx-gas-budget-estimate',
senderAddress,
validatorAddress,
transaction.getData(),
],
queryFn: async () => {
if (!senderAddress || !transaction) {
return null;
}

transaction.setSender(senderAddress);

await transaction.build({ client });

return transaction.getData().gasData.budget;
},
});
}
10 changes: 6 additions & 4 deletions apps/wallet/src/ui/app/WalletSigner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@ export abstract class WalletSigner {
if (isTransaction(transaction)) {
// If the sender has not yet been set on the transaction, then set it.
// NOTE: This allows for signing transactions with mismatched senders, which is important for sponsored transactions.
transaction.setSenderIfNotSet(await this.getAddress());
if (!transaction.getData().sender) {
transaction.setSender(await this.getAddress());
}

return await transaction.build({
client: this.client,
});
Expand Down Expand Up @@ -84,13 +87,12 @@ export abstract class WalletSigner {
transactionBlock: Uint8Array | Transaction;
options?: IotaTransactionBlockResponseOptions;
}): Promise<IotaTransactionBlockResponse> {
const bytes = await this.prepareTransaction(input.transactionBlock);
const signed = await this.signTransaction({
transaction: bytes,
transaction: input.transactionBlock,
});

return this.client.executeTransactionBlock({
transactionBlock: bytes,
transactionBlock: signed.bytes,
signature: signed.signature,
options: input.options,
});
Expand Down
25 changes: 14 additions & 11 deletions apps/wallet/src/ui/app/staking/stake/StakeForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
parseAmount,
useCoinMetadata,
useFormatCoin,
useStakingGasBudgetEstimation,
} from '@iota/core';
import { Field, type FieldProps, Form, useFormikContext } from 'formik';
import { memo, useEffect, useMemo } from 'react';
Expand Down Expand Up @@ -36,7 +37,12 @@ function StakeForm({ validatorAddress, coinBalance, coinType, epoch }: StakeFrom
if (!values.amount || !decimals) return null;
if (Number(values.amount) < 0) return null;
const amountWithoutDecimals = parseAmount(values.amount, decimals);
return createStakeTransaction(amountWithoutDecimals, validatorAddress);
const transaction = createStakeTransaction(amountWithoutDecimals, validatorAddress);
if (activeAddress) {
transaction.setSender(activeAddress);
}

return transaction;
}, [values.amount, validatorAddress, decimals]);

const { data: txDryRunResponse } = useTransactionDryRun(
Expand All @@ -46,18 +52,15 @@ function StakeForm({ validatorAddress, coinBalance, coinType, epoch }: StakeFrom

const gasSummary = txDryRunResponse ? getGasSummary(txDryRunResponse) : undefined;

const stakeAllTransaction = useMemo(() => {
return createStakeTransaction(coinBalance, validatorAddress);
}, [coinBalance, validatorAddress]);

const { data: stakeAllTransactionDryRun } = useTransactionDryRun(
activeAddress ?? undefined,
stakeAllTransaction,
);
const { data: stakeAllGasBudget } = useStakingGasBudgetEstimation({
senderAddress: activeAddress,
amount: coinBalance,
validatorAddress,
});

const gasBudget = BigInt(stakeAllTransactionDryRun?.input.gasData.budget ?? 0);
const gasBudget = BigInt(stakeAllGasBudget ?? 0);

// do not remove: gasBudget field is used in the validation schema apps/wallet/src/ui/app/staking/stake/utils/validation.ts
// do not remove: gasBudget field is used in the validation schema apps/core/src/utils/stake/createValidationSchema.ts
useEffect(() => {
setFieldValue('gasBudget', gasBudget);
}, [gasBudget]);
Expand Down

0 comments on commit 42c46d3

Please sign in to comment.