From 40371b5f9bf654f87893ef00511a7fe27f90cd8c Mon Sep 17 00:00:00 2001 From: alter-eggo Date: Wed, 22 May 2024 14:39:35 +0400 Subject: [PATCH] fix: sip10 token send form fees bug --- package.json | 2 +- pnpm-lock.yaml | 8 +- .../form/sip10/sip10-token-send-form.tsx | 6 +- src/app/query/stacks/fees/fees.query.ts | 1 + .../query/stacks/sip10/sip10-tokens.utils.ts | 3 +- .../transactions/token-transfer.hooks.ts | 123 ++++++++++-------- 6 files changed, 78 insertions(+), 65 deletions(-) diff --git a/package.json b/package.json index dfb58cb1641..8bb3bb02aab 100644 --- a/package.json +++ b/package.json @@ -135,7 +135,7 @@ "@dlc-link/dlc-tools": "1.1.1", "@fungible-systems/zone-file": "2.0.0", "@hirosystems/token-metadata-api-client": "1.2.0", - "@leather-wallet/models": "0.6.1", + "@leather-wallet/models": "0.6.2", "@leather-wallet/tokens": "0.0.15", "@ledgerhq/hw-transport-webusb": "6.27.19", "@noble/hashes": "1.3.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 96bc1bd5907..bb36a62ce10 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -30,8 +30,8 @@ dependencies: specifier: 1.2.0 version: 1.2.0 '@leather-wallet/models': - specifier: 0.6.1 - version: 0.6.1 + specifier: 0.6.2 + version: 0.6.2 '@leather-wallet/tokens': specifier: 0.0.15 version: 0.0.15 @@ -3702,8 +3702,8 @@ packages: bignumber.js: 9.1.2 dev: true - /@leather-wallet/models@0.6.1: - resolution: {integrity: sha512-PVbsCypJaVY7W6pOqDfFlZuvx8pZhpBo+8mMo2wddDNSnSGoIhxQtZVTzZPHTb4d++UWPuxrDx0WVcu7G2Y9gA==} + /@leather-wallet/models@0.6.2: + resolution: {integrity: sha512-YBXKYVH6HvYjmcX9uzXcEiSVSqeU0delR4F+J+z0aiW+LSSqWgk8Dozms+o69vhtKUxjInuaohPZ2HUfMeKZnw==} dependencies: bignumber.js: 9.1.2 dev: false diff --git a/src/app/pages/send/send-crypto-asset-form/form/sip10/sip10-token-send-form.tsx b/src/app/pages/send/send-crypto-asset-form/form/sip10/sip10-token-send-form.tsx index 34fdd76a48b..4cf413e2691 100644 --- a/src/app/pages/send/send-crypto-asset-form/form/sip10/sip10-token-send-form.tsx +++ b/src/app/pages/send/send-crypto-asset-form/form/sip10/sip10-token-send-form.tsx @@ -1,4 +1,4 @@ -import { Navigate, useParams } from 'react-router-dom'; +import { useNavigate, useParams } from 'react-router-dom'; import type { CryptoAssetBalance, MarketData, Sip10CryptoAssetInfo } from '@leather-wallet/models'; @@ -22,12 +22,14 @@ function Sip10TokenSendFormLoader({ children }: Sip10TokenSendFormLoaderProps) { const token = useSip10Token(contractId ?? ''); const priceAsMarketData = useAlexCurrencyPriceAsMarketData(); const toast = useToast(); + const navigate = useNavigate(); if (!contractId) return; if (!token) { toast.error('Token not found'); - return ; + navigate(RouteUrls.SendCryptoAsset); + return; } return children({ diff --git a/src/app/query/stacks/fees/fees.query.ts b/src/app/query/stacks/fees/fees.query.ts index 6ede33dfddc..1db27ff4a52 100644 --- a/src/app/query/stacks/fees/fees.query.ts +++ b/src/app/query/stacks/fees/fees.query.ts @@ -23,6 +23,7 @@ function fetchTransactionFeeEstimation(currentNetwork: any, limiter: PQueue) { } ), { + priority: 2, throwOnTimeout: true, } ); diff --git a/src/app/query/stacks/sip10/sip10-tokens.utils.ts b/src/app/query/stacks/sip10/sip10-tokens.utils.ts index 96058a1fb18..d45647ac5d4 100644 --- a/src/app/query/stacks/sip10/sip10-tokens.utils.ts +++ b/src/app/query/stacks/sip10/sip10-tokens.utils.ts @@ -16,11 +16,12 @@ export function createSip10CryptoAssetInfo( key: string, ftAsset: FtMetadataResponse ): Sip10CryptoAssetInfo { - const { assetName, contractName } = getAssetStringParts(key); + const { assetName, contractName, address } = getAssetStringParts(key); const name = ftAsset.name ? ftAsset.name : assetName; return { canTransfer: isTransferableSip10Token(ftAsset), + contractAddress: address, contractId, contractName, decimals: ftAsset.decimals ?? 0, diff --git a/src/app/store/transactions/token-transfer.hooks.ts b/src/app/store/transactions/token-transfer.hooks.ts index 9eff1ed34c6..efb804ee224 100644 --- a/src/app/store/transactions/token-transfer.hooks.ts +++ b/src/app/store/transactions/token-transfer.hooks.ts @@ -17,6 +17,7 @@ import { uintCV, } from '@stacks/transactions'; +import { logger } from '@shared/logger'; import type { StacksSendFormValues, StacksTransactionFormValues } from '@shared/models/form.model'; import { stxToMicroStx } from '@app/common/money/unit-conversion'; @@ -28,7 +29,6 @@ import { import { useNextNonce } from '@app/query/stacks/nonce/account-nonces.hooks'; import { useCurrentStacksNetworkState } from '@app/store/networks/networks.hooks'; import { makePostCondition } from '@app/store/transactions/transaction.hooks'; -import { getAssetStringParts } from '@app/ui/utils/get-asset-string-parts'; import { useCurrentStacksAccount } from '../accounts/blockchain/stacks/stacks-account.hooks'; @@ -83,70 +83,79 @@ export function useGenerateFtTokenTransferUnsignedTx(info: Sip10CryptoAssetInfo) const { data: nextNonce } = useNextNonce(); const account = useCurrentStacksAccount(); const network = useCurrentStacksNetworkState(); + const { contractName, name: contractAssetName, contractAddress } = info; return useCallback( async (values?: StacksSendFormValues | StacksTransactionFormValues) => { - if (!account) return; - - const functionName = 'transfer'; - const recipient = - values && 'recipient' in values - ? createAddress(values.recipient || '') - : createEmptyAddress(); - const amount = values && 'amount' in values ? values.amount : 0; - const memo = - values && 'memo' in values && values.memo !== '' - ? someCV(bufferCVFromString(values.memo || '')) - : noneCV(); - - const amountAsFractionalUnit = ftUnshiftDecimals(amount, info.decimals || 0); - const { - address: contractAddress, - contractName, - assetName, - } = getAssetStringParts(info.contractId); - - const postConditionOptions = { - amount: amountAsFractionalUnit, - contractAddress, - contractAssetName: assetName, - contractName, - stxAddress: account.address, - }; - - const postConditions = [makePostCondition(postConditionOptions)]; - - // (transfer (uint principal principal) (response bool uint)) - const functionArgs: ClarityValue[] = [ - uintCV(amountAsFractionalUnit), - standardPrincipalCVFromAddress(createAddress(account.address)), - standardPrincipalCVFromAddress(recipient), - ]; - - if (info.hasMemo) { - functionArgs.push(memo); - } - - const options = { - txData: { - txType: TransactionTypes.ContractCall, + try { + if (!account) return; + + const functionName = 'transfer'; + const recipient = + values && 'recipient' in values + ? createAddress(values.recipient || '') + : createEmptyAddress(); + const amount = values && 'amount' in values ? values.amount : 0; + const memo = + values && 'memo' in values && values.memo !== '' + ? someCV(bufferCVFromString(values.memo || '')) + : noneCV(); + + const amountAsFractionalUnit = ftUnshiftDecimals(amount, info.decimals || 0); + const postConditionOptions = { + amount: amountAsFractionalUnit, contractAddress, + contractAssetName, contractName, - functionName, - functionArgs: functionArgs.map(serializeCV).map(arg => bytesToHex(arg)), - postConditions, - postConditionMode: PostConditionMode.Deny, - network, + stxAddress: account.address, + }; + + const postConditions = [makePostCondition(postConditionOptions)]; + + // (transfer (uint principal principal) (response bool uint)) + const functionArgs: ClarityValue[] = [ + uintCV(amountAsFractionalUnit), + standardPrincipalCVFromAddress(createAddress(account.address)), + standardPrincipalCVFromAddress(recipient), + ]; + + if (info.hasMemo) { + functionArgs.push(memo); + } + + const options = { + txData: { + txType: TransactionTypes.ContractCall, + contractAddress, + contractName, + functionName, + functionArgs: functionArgs.map(serializeCV).map(arg => bytesToHex(arg)), + postConditions, + postConditionMode: PostConditionMode.Deny, + network, + publicKey: account.stxPublicKey, + }, + fee: stxToMicroStx(values?.fee || 0).toNumber(), publicKey: account.stxPublicKey, - }, - fee: stxToMicroStx(values?.fee || 0).toNumber(), - publicKey: account.stxPublicKey, - nonce: Number(values?.nonce) ?? nextNonce?.nonce, - } as const; + nonce: Number(values?.nonce) ?? nextNonce?.nonce, + } as const; - return generateUnsignedTransaction(options); + return generateUnsignedTransaction(options); + } catch (error) { + logger.error('Failed to generate unsigned transaction', error); + return; + } }, - [account, info.contractId, info.decimals, info.hasMemo, network, nextNonce?.nonce] + [ + account, + info.decimals, + info.hasMemo, + network, + nextNonce?.nonce, + contractName, + contractAssetName, + contractAddress, + ] ); }