Skip to content

Commit

Permalink
fix: sip10 token send form fees bug
Browse files Browse the repository at this point in the history
  • Loading branch information
alter-eggo committed May 22, 2024
1 parent 0c6c4d1 commit 40371b5
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 65 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
8 changes: 4 additions & 4 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -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';

Expand All @@ -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 to={RouteUrls.SendCryptoAsset} />;
navigate(RouteUrls.SendCryptoAsset);
return;
}

return children({
Expand Down
1 change: 1 addition & 0 deletions src/app/query/stacks/fees/fees.query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ function fetchTransactionFeeEstimation(currentNetwork: any, limiter: PQueue) {
}
),
{
priority: 2,
throwOnTimeout: true,
}
);
Expand Down
3 changes: 2 additions & 1 deletion src/app/query/stacks/sip10/sip10-tokens.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
123 changes: 66 additions & 57 deletions src/app/store/transactions/token-transfer.hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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';

Expand Down Expand Up @@ -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,
]
);
}

Expand Down

0 comments on commit 40371b5

Please sign in to comment.