Skip to content

Commit

Permalink
Reverted useTokenTransfer hook (#679)
Browse files Browse the repository at this point in the history
  • Loading branch information
bobo-k2 authored Jan 31, 2023
1 parent c464b17 commit 6d73976
Showing 1 changed file with 253 additions and 33 deletions.
286 changes: 253 additions & 33 deletions src/hooks/transfer/useTokenTransfer.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,31 @@
import { ISubmittableResult } from '@polkadot/types/types';
import { BN } from '@polkadot/util';
import { $api, $web3 } from 'boot/api';
import { ethers } from 'ethers';
import ABI from 'src/config/abi/ERC20.json';
import { getTokenBal, isValidEvmAddress, toSS58Address } from 'src/config/web3';
import { useGasPrice, useNetworkInfo } from 'src/hooks';
import { buildEvmAddress, getTokenBal, isValidEvmAddress, toSS58Address } from 'src/config/web3';
import { useAccount, useBalance, useCustomSignature, useGasPrice, useNetworkInfo } from 'src/hooks';
import { useEthProvider } from 'src/hooks/custom-signature/useEthProvider';
import {
ASTAR_SS58_FORMAT,
isValidAddressPolkadotAddress,
SUBSTRATE_SS58_FORMAT,
} from 'src/hooks/helper/plasmUtils';
import { useAccount } from 'src/hooks/useAccount';
import { signAndSend } from 'src/hooks/helper/wallet';
import { HistoryTxType } from 'src/modules/account';
import { addTxHistories } from 'src/modules/account/utils/index';
import { sampleEvmWalletAddress } from 'src/modules/gas-api';
import { getEvmGasCost } from 'src/modules/gas-api/utils/index';
import { getEvmGas, getEvmGasCost } from 'src/modules/gas-api/utils/index';
import { fetchXcmBalance } from 'src/modules/xcm';
import { Path } from 'src/router';
import { useStore } from 'src/store';
import { container } from 'src/v2/common';
import { SubstrateAccount } from 'src/store/general/state';
import { Asset } from 'src/v2/models';
import { ITokenTransferService } from 'src/v2/services';
import { Symbols } from 'src/v2/symbols';
import { computed, ref, Ref, watch, watchEffect } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute, useRouter } from 'vue-router';
import Web3 from 'web3';
import { TransactionConfig } from 'web3-eth';
import { AbiItem } from 'web3-utils';

export function useTokenTransfer(selectedToken: Ref<Asset>) {
Expand All @@ -32,7 +36,18 @@ export function useTokenTransfer(selectedToken: Ref<Asset>) {
const isChecked = ref<boolean>(false);

const store = useStore();
const { ethProvider } = useEthProvider();
const { t } = useI18n();
const { currentAccount } = useAccount();
const { accountData } = useBalance(currentAccount);

const transferableBalance = computed<number>(() => {
const balance = accountData.value
? ethers.utils.formatEther(accountData.value.getUsableTransactionBalance().toString())
: '0';
return Number(balance);
});
const { handleResult, handleCustomExtrinsic } = useCustomSignature({});
const {
evmGasPrice,
selectedGas,
Expand All @@ -45,10 +60,14 @@ export function useTokenTransfer(selectedToken: Ref<Asset>) {
const route = useRoute();
const router = useRouter();

const { nativeTokenSymbol, evmNetworkIdx } = useNetworkInfo();
const { nativeTokenSymbol, evmNetworkIdx, isSupportXvmTransfer } = useNetworkInfo();
const isH160 = computed<boolean>(() => store.getters['general/isH160Formatted']);
const tokenSymbol = computed<string>(() => route.query.token as string);
const isEthWallet = computed<boolean>(() => store.getters['general/isEthWallet']);
const isLoading = computed<boolean>(() => store.getters['general/isLoading']);
const substrateAccounts = computed<SubstrateAccount[]>(
() => store.getters['general/substrateAccounts']
);

const isTransferNativeToken = computed<boolean>(
() => tokenSymbol.value === nativeTokenSymbol.value.toLowerCase()
Expand All @@ -73,7 +92,8 @@ export function useTokenTransfer(selectedToken: Ref<Asset>) {
});

const isValidDestAddress = computed<boolean>(() => {
const isOnlyAcceptEvmAddress = isH160.value && !isTransferNativeToken.value;
const isOnlyAcceptEvmAddress =
isH160.value && !isTransferNativeToken.value && !isSupportXvmTransfer.value;
return isOnlyAcceptEvmAddress
? isValidEvmAddress(toAddress.value)
: isValidAddressPolkadotAddress(toAddress.value, ASTAR_SS58_FORMAT) ||
Expand All @@ -94,15 +114,16 @@ export function useTokenTransfer(selectedToken: Ref<Asset>) {
toAddressBalance.value = 0;
};

const finalizedCallback = (hash: string): void => {
addTxHistories({
hash: String(hash),
type: HistoryTxType.Transfer,
address: currentAccount.value,
});
const finalizeCallback = (): void => {
router.push(Path.Assets);
};

const toastInvalidAddress = () =>
store.dispatch('general/showAlertMsg', {
msg: 'assets.invalidAddress',
alertType: 'error',
});

const toMaxAmount = async (): Promise<void> => {
transferAmt.value = String(selectedToken.value.userBalance);
};
Expand All @@ -112,9 +133,15 @@ export function useTokenTransfer(selectedToken: Ref<Asset>) {
const transferAmtRef = Number(transferAmt.value);
try {
if (transferAmtRef > fromAddressBalance.value) {
errMsg.value = 'warning.insufficientBalance';
errMsg.value = t('warning.insufficientBalance', {
token: selectedToken.value.metadata.symbol,
});
} else if (toAddress.value && !isValidDestAddress.value) {
errMsg.value = 'warning.inputtedInvalidDestAddress';
} else if (!transferableBalance.value) {
errMsg.value = t('warning.insufficientBalance', {
token: nativeTokenSymbol.value,
});
} else {
errMsg.value = '';
}
Expand All @@ -123,6 +150,145 @@ export function useTokenTransfer(selectedToken: Ref<Asset>) {
}
};

const callH160NativeTransfer = async ({
transferAmt,
fromAddress,
toAddress,
web3,
gasPrice,
symbol,
finalizeCallback,
}: {
transferAmt: number;
fromAddress: string;
toAddress: string;
web3: Web3;
gasPrice: string;
symbol: string;
finalizeCallback: () => void;
}): Promise<void> => {
const destinationAddress = buildEvmAddress(toAddress);
if (!ethers.utils.isAddress(destinationAddress)) {
toastInvalidAddress();
return;
}
const rawTx: TransactionConfig = {
nonce: await web3.eth.getTransactionCount(fromAddress),
gasPrice: web3.utils.toHex(gasPrice),
from: fromAddress,
to: destinationAddress,
value: web3.utils.toWei(String(transferAmt), 'ether'),
};

const estimatedGas = await web3.eth.estimateGas(rawTx);

await web3.eth
.sendTransaction({ ...rawTx, gas: estimatedGas })
.once('transactionHash', (transactionHash) => {
store.commit('general/setLoading', true);
})
.then(({ transactionHash }) => {
store.dispatch('general/showAlertMsg', {
msg: t('toast.completedMessage', {
hash: transactionHash,
symbol,
transferAmt,
toAddress,
}),
alertType: 'success',
txHash: transactionHash,
});
store.commit('general/setLoading', false);
addTxHistories({
hash: transactionHash,
type: HistoryTxType.Transfer,
address: fromAddress,
});
finalizeCallback();
})
.catch((error: any) => {
console.error(error);
store.commit('general/setLoading', false);
store.dispatch('general/showAlertMsg', {
msg: error.message,
alertType: 'error',
});
});
};

const callErc20Transfer = async ({
transferAmt,
fromAddress,
toAddress,
contractAddress,
gasPrice,
web3,
symbol,
finalizeCallback,
}: {
transferAmt: string;
fromAddress: string;
toAddress: string;
contractAddress: string;
gasPrice: string;
web3: Web3;
symbol: string;
finalizeCallback: () => void;
}): Promise<void> => {
if (!isH160.value) return;
const destAddress = isValidAddressPolkadotAddress(toAddress)
? buildEvmAddress(toAddress)
: toAddress;
if (!ethers.utils.isAddress(destAddress)) {
toastInvalidAddress();
return;
}
const contract = new web3.eth.Contract(ABI as AbiItem[], contractAddress);

const rawTx: TransactionConfig = {
nonce: await web3.eth.getTransactionCount(fromAddress),
gasPrice: web3.utils.toHex(gasPrice),
from: fromAddress,
to: contractAddress,
value: '0x0',
data: contract.methods.transfer(destAddress, transferAmt).encodeABI(),
};

const estimatedGas = await web3.eth.estimateGas(rawTx);
await web3.eth
.sendTransaction({ ...rawTx, gas: estimatedGas })
.once('transactionHash', (transactionHash) => {
store.commit('general/setLoading', true);
})
.then(({ transactionHash }) => {
store.dispatch('general/showAlertMsg', {
msg: t('toast.completedMessage', {
hash: transactionHash,
symbol,
transferAmt,
toAddress,
}),
alertType: 'success',
txHash: transactionHash,
});
store.commit('general/setLoading', false);
addTxHistories({
hash: transactionHash,
type: HistoryTxType.Transfer,
address: fromAddress,
});
finalizeCallback();
})
.catch((error: any) => {
console.error(error);
store.commit('general/setLoading', false);
store.dispatch('general/showAlertMsg', {
msg: error.message,
alertType: 'error',
});
});
};

const transferAsset = async ({
transferAmt,
toAddress,
Expand All @@ -137,31 +303,82 @@ export function useTokenTransfer(selectedToken: Ref<Asset>) {
}

const receivingAddress = isValidEvmAddress(toAddress) ? toSS58Address(toAddress) : toAddress;
const txResHandler = async (result: ISubmittableResult): Promise<boolean> => {
const res = await handleResult(result);
finalizeCallback();
return res;
};

const decimals = Number(selectedToken.value.metadata.decimals);
const amount = ethers.utils.parseUnits(String(transferAmt), decimals).toString();

try {
const tokenTransferService = container.get<ITokenTransferService>(
Symbols.TokenTransferService
);
if (isH160.value) {
await tokenTransferService.transferEvmAsset({
senderAddress: currentAccount.value,
toAddress,
amount: String(transferAmt),
const callH160Transfer = async (): Promise<void> => {
const web3 = new Web3(ethProvider.value as any);
const gasPrice = await getEvmGas(web3, selectedGas.value.price);
if (isTransferNativeToken.value) {
await callH160NativeTransfer({
fromAddress: currentAccount.value,
toAddress: toAddress,
transferAmt,
gasPrice,
web3,
symbol,
finalizeCallback,
});
} else {
await callErc20Transfer({
fromAddress: currentAccount.value,
toAddress: toAddress,
transferAmt: amount,
contractAddress: selectedToken.value.mappedERC20Addr,
decimals,
finalizedCallback,
gasPrice,
web3,
symbol,
finalizeCallback,
});
}
};

const callSs58Transfer = async (): Promise<void> => {
if (isTransferNativeToken.value) {
const transaction = $api!.tx.balances.transferKeepAlive(receivingAddress, amount);
await signAndSend({
transaction,
senderAddress: currentAccount.value,
substrateAccounts: substrateAccounts.value,
isCustomSignature: isEthWallet.value,
txResHandler,
handleCustomExtrinsic,
dispatch: store.dispatch,
tip: selectedTip.value.price,
txType: HistoryTxType.Transfer,
});
} else {
await tokenTransferService.transferNativeAsset({
assetId: selectedToken.value.id,
const transaction = $api!.tx.assets.transfer(
new BN(selectedToken.value.id),
receivingAddress,
amount
);
await signAndSend({
transaction,
senderAddress: currentAccount.value,
receivingAddress: receivingAddress,
amount,
finalizedCallback,
substrateAccounts: substrateAccounts.value,
isCustomSignature: false,
txResHandler,
handleCustomExtrinsic,
dispatch: store.dispatch,
tip: selectedTip.value.price,
txType: HistoryTxType.Transfer,
});
}
};

try {
if (isH160.value) {
await callH160Transfer();
} else {
await callSs58Transfer();
}
} catch (e: any) {
console.error(e);
store.dispatch('general/showAlertMsg', {
Expand Down Expand Up @@ -200,9 +417,12 @@ export function useTokenTransfer(selectedToken: Ref<Asset>) {
if (isTransferNativeToken.value) {
toAddressBalance.value = await getNativeTokenBalance(destAddress);
} else if (isH160.value) {
const address = isValidAddressPolkadotAddress(toAddress.value)
? buildEvmAddress(toAddress.value)
: toAddress.value;
const balance = await getTokenBal({
srcChainId,
address: toAddress.value,
address,
tokenAddress: selectedToken.value.mappedERC20Addr,
tokenSymbol: selectedToken.value.metadata.symbol,
});
Expand Down

0 comments on commit 6d73976

Please sign in to comment.