|
@@ -1,154 +1,235 @@
|
|
|
<template>
|
|
|
- <div class="container">
|
|
|
- <div class="content">
|
|
|
- <div class="card-box">
|
|
|
- <div class="card-title">{{ $t('wallet.Selectthecurrency') }}</div>
|
|
|
- <div class="card-input" @click="selectPop(1)">
|
|
|
- <van-image width="30px" height="30px" round :src="selecctList.logo"/>
|
|
|
- <div class="card-text">{{selecctList.name}}</div>
|
|
|
- <svg-icon style="width: 16px; height: 16px;" name="down" />
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="card-box">
|
|
|
- <div class="card-title">{{ $t('wallet.DeliveryAddress') }}
|
|
|
- <svg-icon style="width: 16px; height: 16px;" name="address" @click="goToAddress"/>
|
|
|
- </div>
|
|
|
- <div class="card-input" style="height:100%">
|
|
|
- <van-field
|
|
|
- type="textarea"
|
|
|
- v-model="walletAddress"
|
|
|
- :placeholder="$t('wallet.PleaseEnterTheDeliveryAddress')"
|
|
|
- rows="1"
|
|
|
- :autosize="true"
|
|
|
- >
|
|
|
- <template #right-icon>
|
|
|
- <svg-icon style="width: 16px; height: 16px;" name="sm" @click="changeSM"/>
|
|
|
- </template>
|
|
|
- </van-field>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="card-box">
|
|
|
- <div class="card-title">
|
|
|
- <div>{{ $t('wallet.TransfeQuantity') }}</div>
|
|
|
- <div>可用:{{selecctList.balance}} {{ selecctList.name }}</div>
|
|
|
- </div>
|
|
|
- <div class="card-input">
|
|
|
- <van-field v-model="unitNum" placeholder="0.00" />
|
|
|
- <div class="card-input-right">
|
|
|
- <div>{{ selecctList.name }}</div>
|
|
|
- <div class="line"></div>
|
|
|
- <div class="all" @click="unitNum = selecctList.balance">{{ $t('wallet.All') }}</div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
+ <div class="container">
|
|
|
+ <div class="content">
|
|
|
+ <div class="card-box">
|
|
|
+ <div class="card-title">{{ $t("wallet.Selectthecurrency") }}</div>
|
|
|
+ <div class="card-input" @click="selectPop(1)">
|
|
|
+ <van-image width="30px" height="30px" round :src="selecctList.logo" />
|
|
|
+ <div class="card-text">{{ selecctList.name }}</div>
|
|
|
+ <svg-icon style="width: 16px; height: 16px" name="down" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="card-box">
|
|
|
+ <div class="card-title">
|
|
|
+ {{ $t("wallet.DeliveryAddress") }}
|
|
|
+ <svg-icon
|
|
|
+ style="width: 16px; height: 16px"
|
|
|
+ name="address"
|
|
|
+ @click="goToAddress"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="card-input" style="height: 100%">
|
|
|
+ <van-field
|
|
|
+ type="textarea"
|
|
|
+ v-model="walletAddress"
|
|
|
+ :placeholder="$t('wallet.PleaseEnterTheDeliveryAddress')"
|
|
|
+ rows="1"
|
|
|
+ :autosize="true"
|
|
|
+ >
|
|
|
+ <template #right-icon>
|
|
|
+ <svg-icon
|
|
|
+ style="width: 16px; height: 16px"
|
|
|
+ name="sm"
|
|
|
+ @click="changeSM"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ </van-field>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="card-box">
|
|
|
+ <div class="card-title">
|
|
|
+ <div>{{ $t("wallet.TransfeQuantity") }}</div>
|
|
|
+ <div>可用:{{ selecctList.balance }} {{ selecctList.name }}</div>
|
|
|
+ </div>
|
|
|
+ <div class="card-input">
|
|
|
+ <van-field v-model="unitNum" placeholder="0.00" />
|
|
|
+ <div class="card-input-right">
|
|
|
+ <div>{{ selecctList.name }}</div>
|
|
|
+ <div class="line"></div>
|
|
|
+ <div class="all" @click="unitNum = selecctList.balance">
|
|
|
+ {{ $t("wallet.All") }}
|
|
|
</div>
|
|
|
- <!-- <div class="card-box">
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- <div class="card-box">
|
|
|
<div class="card-title">网络费用</div>
|
|
|
<div class="card-input" style="flex-direction: column;align-items: self-start;padding: 8px 17px;">
|
|
|
<div>18.34344398867676764566000ACC</div>
|
|
|
<div class="price">STT0.01</div>
|
|
|
</div>
|
|
|
</div> -->
|
|
|
+ </div>
|
|
|
+ <van-button
|
|
|
+ class="footer-btn"
|
|
|
+ type="primary"
|
|
|
+ size="large"
|
|
|
+ @click="selectPop(2)"
|
|
|
+ :disabled="isDisabled"
|
|
|
+ >{{ $t("wallet.Sure") }}</van-button
|
|
|
+ >
|
|
|
+ <van-popup
|
|
|
+ v-model:show="showWallet"
|
|
|
+ position="bottom"
|
|
|
+ round
|
|
|
+ style="height: 400px"
|
|
|
+ >
|
|
|
+ <div class="pop-content" style="height: 400px">
|
|
|
+ <div class="pop-title">
|
|
|
+ <svg-icon
|
|
|
+ style="width: 24px; height: 24px"
|
|
|
+ name="left-arrow"
|
|
|
+ @click="showWallet = false"
|
|
|
+ />
|
|
|
+ <div class="title">
|
|
|
+ {{
|
|
|
+ selectType == 1
|
|
|
+ ? $t("wallet.SelectTheCurrency")
|
|
|
+ : $t("wallet.TransactionDetails")
|
|
|
+ }}
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- <van-button class="footer-btn" type="primary" size="large" @click="selectPop(2)" :disabled="isDisabled">{{ $t('wallet.Sure') }}</van-button>
|
|
|
- <van-popup v-model:show="showWallet" position="bottom" round style="height:400px">
|
|
|
- <div class="pop-content" style="height:400px">
|
|
|
- <div class="pop-title">
|
|
|
- <svg-icon style="width: 24px; height: 24px;" name="left-arrow" @click="showWallet = false"/>
|
|
|
- <div class="title">{{selectType == 1?$t('wallet.SelectTheCurrency'):$t('wallet.TransactionDetails')}}</div>
|
|
|
- </div>
|
|
|
- <div class="list-ul" v-if="selectType == 1">
|
|
|
- <div class="list-li" v-for="item in hotTokensList" @click="changeList(item)" :key="item.name">
|
|
|
- <div class="list-li-lf">
|
|
|
- <van-image width="42px" height="42px" round :src="item.logo"/>
|
|
|
- <div style="margin-left: 12px;">{{item.name}}</div>
|
|
|
- </div>
|
|
|
- <div class="list-li-ri">
|
|
|
- <div>{{item.balance}}</div>
|
|
|
- <div class="list-li-ri-num">${{item.money}}</div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="pop-detail" v-if="selectType == 2">
|
|
|
- <!-- <div class="pop-detail-title">-{{gasFee}} ACC</div> -->
|
|
|
- <div class="pop-detail-cell">
|
|
|
- <div class="cell-label">{{ $t('wallet.PaymentAddress') }}</div>
|
|
|
- <div class="cell-text">{{walletStore.account}}</div>
|
|
|
- </div>
|
|
|
- <div class="pop-detail-cell">
|
|
|
- <div class="cell-label">{{ $t('wallet.ReceivingAddress') }}</div>
|
|
|
- <div class="cell-text">{{walletAddress}}</div>
|
|
|
- </div>
|
|
|
- <div class="pop-detail-cell">
|
|
|
- <div class="cell-label">{{ $t('wallet.MinerIsFee') }}</div>
|
|
|
- <div class="cell-text">{{ gasFee }} ACC</div>
|
|
|
- </div>
|
|
|
- <div class="pop-btn">
|
|
|
- <van-button class="btn" type="primary" size="large" color="#4765DD" @click="confirm" :disabled="!gasFee || gasFee === '0.0000'">确认</van-button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
+ <div class="list-ul" v-if="selectType == 1">
|
|
|
+ <div
|
|
|
+ class="list-li"
|
|
|
+ v-for="item in hotTokensList"
|
|
|
+ @click="changeList(item)"
|
|
|
+ :key="item.name"
|
|
|
+ >
|
|
|
+ <div class="list-li-lf">
|
|
|
+ <van-image width="42px" height="42px" round :src="item.logo" />
|
|
|
+ <div style="margin-left: 12px">{{ item.name }}</div>
|
|
|
</div>
|
|
|
- </van-popup>
|
|
|
- <van-popup v-model:show="showPassWord" :style="{ borderRadius:'25px' }">
|
|
|
- <div class="pop-content-password">
|
|
|
- <div class="pop-title-password">{{ $t('wallet.PleaseEnterThePassword') }}</div>
|
|
|
- <van-field v-model="passWord" class="pop-input" type="password"/>
|
|
|
- <div class="pop-btn-password">
|
|
|
- <van-button type="default" class="btn-password cancel" @click="cancel">{{ $t('wallet.Cancel') }}</van-button>
|
|
|
- <van-button type="default" class="btn-password confirm" @click="popConfirm" :disabled="isDisabledConfirm">{{ $t('wallet.Sure') }}</van-button>
|
|
|
- </div>
|
|
|
+ <div class="list-li-ri">
|
|
|
+ <div>{{ item.balance }}</div>
|
|
|
+ <div class="list-li-ri-num">${{ item.money }}</div>
|
|
|
</div>
|
|
|
- </van-popup>
|
|
|
- </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="pop-detail" v-if="selectType == 2">
|
|
|
+ <!-- <div class="pop-detail-title">-{{gasFee}} ACC</div> -->
|
|
|
+ <div class="pop-detail-cell">
|
|
|
+ <div class="cell-label">{{ $t("wallet.PaymentAddress") }}</div>
|
|
|
+ <div class="cell-text">{{ walletStore.account }}</div>
|
|
|
+ </div>
|
|
|
+ <div class="pop-detail-cell">
|
|
|
+ <div class="cell-label">{{ $t("wallet.ReceivingAddress") }}</div>
|
|
|
+ <div class="cell-text">{{ walletAddress }}</div>
|
|
|
+ </div>
|
|
|
+ <div class="pop-detail-cell">
|
|
|
+ <div class="cell-label">{{ $t("wallet.MinerIsFee") }}</div>
|
|
|
+ <div class="cell-text">{{ gasFee }} ACC</div>
|
|
|
+ </div>
|
|
|
+ <div class="pop-btn">
|
|
|
+ <van-button
|
|
|
+ class="btn"
|
|
|
+ type="primary"
|
|
|
+ size="large"
|
|
|
+ color="#4765DD"
|
|
|
+ @click="confirm"
|
|
|
+ :disabled="!gasFee || gasFee === '0.0000'"
|
|
|
+ >确认</van-button
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </van-popup>
|
|
|
+ <van-popup v-model:show="showPassWord" :style="{ borderRadius: '25px' }">
|
|
|
+ <div class="pop-content-password">
|
|
|
+ <div class="pop-title-password">
|
|
|
+ {{ $t("wallet.PleaseEnterThePassword") }}
|
|
|
+ </div>
|
|
|
+ <van-field v-model="passWord" class="pop-input" type="password" />
|
|
|
+ <div class="pop-btn-password">
|
|
|
+ <van-button
|
|
|
+ type="default"
|
|
|
+ class="btn-password cancel"
|
|
|
+ @click="cancel"
|
|
|
+ >{{ $t("wallet.Cancel") }}</van-button
|
|
|
+ >
|
|
|
+ <van-button
|
|
|
+ type="default"
|
|
|
+ class="btn-password confirm"
|
|
|
+ @click="popConfirm"
|
|
|
+ :disabled="isDisabledConfirm"
|
|
|
+ >{{ $t("wallet.Sure") }}</van-button
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </van-popup>
|
|
|
+ <van-overlay :show="percentageShow">
|
|
|
+ <div class="progress-text">
|
|
|
+ <span>{{ pivotText }}</span>
|
|
|
+ </div>
|
|
|
+ <van-progress
|
|
|
+ class="progress"
|
|
|
+ stroke-width="8"
|
|
|
+ :percentage="percentage"
|
|
|
+ />
|
|
|
+ </van-overlay>
|
|
|
+ </div>
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
-import { verifyFingerprint } from "@/components/Biometrics/biometrics.js"
|
|
|
-import { startScan } from "@/composables/barcodeScanner.js"
|
|
|
-import { useRouter,useRoute } from 'vue-router'
|
|
|
+import { verifyFingerprint } from "@/components/Biometrics/biometrics.js";
|
|
|
+import { startScan } from "@/composables/barcodeScanner.js";
|
|
|
+import { useRouter, useRoute } from "vue-router";
|
|
|
import { useWalletStore } from "@/stores/modules/walletStore";
|
|
|
import Web3 from "web3";
|
|
|
import pubData from "@/utils/pub.json";
|
|
|
-import { cryptoDecode } from "@/utils/crypto.js"
|
|
|
-import { showLoadingToast,showToast } from 'vant';
|
|
|
-import { showNotify } from 'vant';
|
|
|
+import { cryptoDecode } from "@/utils/crypto.js";
|
|
|
+import { showLoadingToast, showToast } from "vant";
|
|
|
+import { showNotify } from "vant";
|
|
|
|
|
|
const router = useRouter();
|
|
|
const route = useRoute();
|
|
|
const walletStore = useWalletStore();
|
|
|
const web3 = new Web3(walletStore.rpcUrl);
|
|
|
|
|
|
-const walletAddress = ref(route.query.address || '');
|
|
|
-const unitNum = ref('')
|
|
|
-const showWallet = ref(false)
|
|
|
-const showPassWord = ref(false)
|
|
|
-const selectType = ref('');
|
|
|
+const walletAddress = ref(route.query.address || "");
|
|
|
+const unitNum = ref("");
|
|
|
+const showWallet = ref(false);
|
|
|
+const showPassWord = ref(false);
|
|
|
+const selectType = ref("");
|
|
|
let hotTokensList = walletStore.tokenList;
|
|
|
let selecctList = walletStore.tokenList[0];
|
|
|
-const passWord = ref('')
|
|
|
-const gasFee = ref('');
|
|
|
-const isDisabledConfirm = ref(false)
|
|
|
+const passWord = ref("");
|
|
|
+const gasFee = ref("");
|
|
|
+const isDisabledConfirm = ref(false);
|
|
|
+const percentage = ref(0);
|
|
|
+const pivotText = ref("Logging in...");
|
|
|
+const percentageShow = ref(false);
|
|
|
+
|
|
|
+// setInterval(()=>{
|
|
|
+// percentage.value += 1
|
|
|
+// }, 200)
|
|
|
|
|
|
const isDisabled = computed(() => {
|
|
|
const num = parseFloat(unitNum.value);
|
|
|
return (
|
|
|
- !walletAddress.value || // 钱包地址为空
|
|
|
- !unitNum.value || // 输入为空
|
|
|
- isNaN(num) || num <= 0 || num >= selecctList.balance // 非法数值
|
|
|
+ !walletAddress.value || // 钱包地址为空
|
|
|
+ !unitNum.value || // 输入为空
|
|
|
+ isNaN(num) ||
|
|
|
+ num <= 0 ||
|
|
|
+ num >= selecctList.balance // 非法数值
|
|
|
);
|
|
|
});
|
|
|
|
|
|
const goToAddress = () => {
|
|
|
- router.push('transferAddressManagement')
|
|
|
-}
|
|
|
+ router.push("transferAddressManagement");
|
|
|
+};
|
|
|
const selectPop = (type) => {
|
|
|
- showWallet.value = true;
|
|
|
- selectType.value = type;
|
|
|
-}
|
|
|
-watch(() => selectType.value, (val) => {
|
|
|
- if (val === 2) {
|
|
|
- estimateGasFee();
|
|
|
+ showWallet.value = true;
|
|
|
+ selectType.value = type;
|
|
|
+};
|
|
|
+watch(
|
|
|
+ () => selectType.value,
|
|
|
+ (val) => {
|
|
|
+ if (val === 2) {
|
|
|
+ estimateGasFee();
|
|
|
+ }
|
|
|
}
|
|
|
-});
|
|
|
+);
|
|
|
|
|
|
const estimateGasFee = async () => {
|
|
|
try {
|
|
@@ -158,7 +239,7 @@ const estimateGasFee = async () => {
|
|
|
|
|
|
if (!from || !to || !amount) return;
|
|
|
|
|
|
- const isACC = selecctList.name === 'ACC';
|
|
|
+ const isACC = selecctList.name === "ACC";
|
|
|
|
|
|
let tx;
|
|
|
if (isACC) {
|
|
@@ -166,12 +247,12 @@ const estimateGasFee = async () => {
|
|
|
tx = {
|
|
|
from,
|
|
|
to,
|
|
|
- value: web3.utils.toWei(amount.toString(), 'ether'),
|
|
|
+ value: web3.utils.toWei(amount.toString(), "ether"),
|
|
|
};
|
|
|
} else {
|
|
|
// ② ERC20 代币转账
|
|
|
const contract = new web3.eth.Contract(pubData, selecctList.address);
|
|
|
- const value = web3.utils.toWei(amount.toString(), 'ether'); // 注意小数位
|
|
|
+ const value = web3.utils.toWei(amount.toString(), "ether"); // 注意小数位
|
|
|
tx = {
|
|
|
from,
|
|
|
to: selecctList.address,
|
|
@@ -179,61 +260,70 @@ const estimateGasFee = async () => {
|
|
|
};
|
|
|
}
|
|
|
|
|
|
- const gasPrice = await web3.eth.getGasPrice(); // 单位 Wei
|
|
|
- const gasLimit = await web3.eth.estimateGas(tx); // 单位 Gas
|
|
|
+ const gasPrice = await web3.eth.getGasPrice(); // 单位 Wei
|
|
|
+ const gasLimit = await web3.eth.estimateGas(tx); // 单位 Gas
|
|
|
|
|
|
const feeWei = BigInt(gasPrice) * BigInt(gasLimit);
|
|
|
- gasFee.value = Number(web3.utils.fromWei(feeWei.toString(), 'ether')).toFixed(8);
|
|
|
+ gasFee.value = Number(
|
|
|
+ web3.utils.fromWei(feeWei.toString(), "ether")
|
|
|
+ ).toFixed(8);
|
|
|
} catch (err) {
|
|
|
- console.error($t('wallet.FailedToEstimateMinerFees'), err);
|
|
|
- gasFee.value = '0.0000';
|
|
|
+ console.error($t("wallet.FailedToEstimateMinerFees"), err);
|
|
|
+ gasFee.value = "0.0000";
|
|
|
}
|
|
|
};
|
|
|
|
|
|
const changeList = (item) => {
|
|
|
- selecctList = item;
|
|
|
- showWallet.value = false;
|
|
|
- unitNum.value = ''
|
|
|
-}
|
|
|
+ selecctList = item;
|
|
|
+ showWallet.value = false;
|
|
|
+ unitNum.value = "";
|
|
|
+};
|
|
|
// 扫码
|
|
|
const changeSM = async () => {
|
|
|
- const result = await startScan();
|
|
|
- walletAddress.value = result.ScanResult;
|
|
|
-}
|
|
|
+ const result = await startScan();
|
|
|
+ walletAddress.value = result.ScanResult;
|
|
|
+};
|
|
|
// 确认
|
|
|
const confirm = async () => {
|
|
|
- showWallet.value = false;
|
|
|
- const verified = await verifyFingerprint();
|
|
|
- console.log(verified)
|
|
|
- if (verified) {
|
|
|
- getData();
|
|
|
- } else {
|
|
|
- showPassWord.value = true;
|
|
|
- }
|
|
|
+ showWallet.value = false;
|
|
|
+ const verified = await verifyFingerprint();
|
|
|
+ console.log(verified);
|
|
|
+ if (verified) {
|
|
|
+ getData();
|
|
|
+ } else {
|
|
|
+ showPassWord.value = true;
|
|
|
+ }
|
|
|
};
|
|
|
// 密码取消
|
|
|
const cancel = () => {
|
|
|
- passWord.value = '';
|
|
|
- showPassWord.value = false;
|
|
|
-}
|
|
|
+ passWord.value = "";
|
|
|
+ showPassWord.value = false;
|
|
|
+};
|
|
|
// 密码确认
|
|
|
const popConfirm = () => {
|
|
|
- if(passWord.value != cryptoDecode(walletStore.accountPassword)){
|
|
|
- showNotify({ type: 'warning', message: $t('wallet.PleaseEnterTheCorrectPassword') });
|
|
|
- }else{
|
|
|
- getData();
|
|
|
- }
|
|
|
-}
|
|
|
+ if (passWord.value != cryptoDecode(walletStore.accountPassword)) {
|
|
|
+ showNotify({
|
|
|
+ type: "warning",
|
|
|
+ message: $t("wallet.PleaseEnterTheCorrectPassword"),
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ getData();
|
|
|
+ }
|
|
|
+};
|
|
|
// 请求链
|
|
|
const getData = async () => {
|
|
|
+ cancel();
|
|
|
isDisabledConfirm.value = true;
|
|
|
- showLoadingToast({
|
|
|
- message: $t('wallet.TransferInProgress'),
|
|
|
- forbidClick: true,
|
|
|
- });
|
|
|
+ // showLoadingToast({
|
|
|
+ // message: $t('wallet.TransferInProgress'),
|
|
|
+ // forbidClick: true,
|
|
|
+ // });
|
|
|
+ percentageShow.value = true;
|
|
|
+ percentage.value = 5;
|
|
|
try {
|
|
|
let receipt;
|
|
|
- if (selecctList.name === 'ACC') {
|
|
|
+ percentage.value = 10;
|
|
|
+ if (selecctList.name === "ACC") {
|
|
|
// ETH 转账
|
|
|
receipt = await sendETH(
|
|
|
walletStore.privateKey,
|
|
@@ -249,42 +339,63 @@ const getData = async () => {
|
|
|
unitNum.value
|
|
|
);
|
|
|
}
|
|
|
- showToast($t('wallet.TheTransferWasSuccessful'));
|
|
|
- router.push('/wallet');
|
|
|
+
|
|
|
+ showToast($t("wallet.TheTransferWasSuccessful"));
|
|
|
+ router.push("/wallet");
|
|
|
} catch (err) {
|
|
|
- showToast($t('wallet.TransferFailed'));
|
|
|
+ showToast($t("wallet.TransferFailed"));
|
|
|
+ percentageShow.value = false;
|
|
|
} finally {
|
|
|
+ percentage.value = 100;
|
|
|
+ percentageShow.value = false;
|
|
|
showWallet.value = false;
|
|
|
isDisabledConfirm.value = false;
|
|
|
}
|
|
|
-}
|
|
|
+};
|
|
|
// ========= ETH 转账 =========
|
|
|
const sendETH = async (privateKey, toAddress, amountInEther) => {
|
|
|
const account = web3.eth.accounts.privateKeyToAccount(privateKey);
|
|
|
const from = account.address;
|
|
|
- const nonce = await web3.eth.getTransactionCount(from, 'latest');
|
|
|
+ pivotText.value = $t("wallet.GetNonce");
|
|
|
+ const nonce = await web3.eth.getTransactionCount(from, "latest");
|
|
|
+ percentage.value = 30;
|
|
|
+ pivotText.value = $t("wallet.GetGasPrice");
|
|
|
const gasPrice = await web3.eth.getGasPrice();
|
|
|
+ pivotText.value = $t("wallet.AcquiringTransactionData");
|
|
|
+ percentage.value = 60;
|
|
|
+ pivotText.value = $t("wallet.SigningTransaction");
|
|
|
const tx = {
|
|
|
from,
|
|
|
to: toAddress,
|
|
|
- value: web3.utils.toWei(amountInEther.toString(), 'ether'),
|
|
|
+ value: web3.utils.toWei(amountInEther.toString(), "ether"),
|
|
|
gas: 21000,
|
|
|
gasPrice,
|
|
|
nonce,
|
|
|
chainId: await web3.eth.getChainId(),
|
|
|
};
|
|
|
+ percentage.value = 80;
|
|
|
+ pivotText.value = $t("wallet.TransactionIsBeingSent");
|
|
|
const signedTx = await web3.eth.accounts.signTransaction(tx, privateKey);
|
|
|
+ percentage.value = 96;
|
|
|
+ pivotText.value = $t("wallet.WaitingForTransactionConfirmation");
|
|
|
return await web3.eth.sendSignedTransaction(signedTx.rawTransaction);
|
|
|
};
|
|
|
// ========= ERC‑20 代币转账 =========
|
|
|
const sendToken = async (privateKey, tokenAddress, toAddress, amount) => {
|
|
|
const account = web3.eth.accounts.privateKeyToAccount(privateKey);
|
|
|
const from = account.address;
|
|
|
+ pivotText.value = $t("wallet.GetNonce");
|
|
|
const contract = new web3.eth.Contract(pubData, tokenAddress);
|
|
|
- const nonce = await web3.eth.getTransactionCount(from, 'latest');
|
|
|
+ const nonce = await web3.eth.getTransactionCount(from, "latest");
|
|
|
+ percentage.value = 40;
|
|
|
+ pivotText.value = $t("wallet.GetGasPrice");
|
|
|
const gasPrice = await web3.eth.getGasPrice();
|
|
|
- const value = web3.utils.toWei(amount.toString(), 'ether');
|
|
|
+ percentage.value = 60;
|
|
|
+ const value = web3.utils.toWei(amount.toString(), "ether");
|
|
|
+ pivotText.value = $t("wallet.AcquiringTransactionData");
|
|
|
const txData = contract.methods.transfer(toAddress, value).encodeABI();
|
|
|
+ percentage.value = 70;
|
|
|
+ pivotText.value = $t("wallet.SigningTransaction");
|
|
|
const tx = {
|
|
|
from,
|
|
|
to: tokenAddress,
|
|
@@ -294,242 +405,287 @@ const sendToken = async (privateKey, tokenAddress, toAddress, amount) => {
|
|
|
nonce,
|
|
|
chainId: await web3.eth.getChainId(),
|
|
|
};
|
|
|
+
|
|
|
+ percentage.value = 80;
|
|
|
+ pivotText.value = $t("wallet.TransactionIsBeingSent");
|
|
|
const signedTx = await web3.eth.accounts.signTransaction(tx, privateKey);
|
|
|
+ percentage.value = 96;
|
|
|
+ pivotText.value = $t("wallet.WaitingForTransactionConfirmation");
|
|
|
return await web3.eth.sendSignedTransaction(signedTx.rawTransaction);
|
|
|
};
|
|
|
</script>
|
|
|
|
|
|
<style lang="less" scoped>
|
|
|
-.container{
|
|
|
+.container {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ height: 86vh;
|
|
|
+ padding: 17px 17px 33px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ .content {
|
|
|
+ flex: 1;
|
|
|
+ .card-box {
|
|
|
+ margin-bottom: 25px;
|
|
|
+ .card-title {
|
|
|
+ font-family:
|
|
|
+ PingFang SC,
|
|
|
+ PingFang SC;
|
|
|
+ font-weight: 400;
|
|
|
+ font-size: 12px;
|
|
|
+ color: #8d8d8d;
|
|
|
+ margin-bottom: 6px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ }
|
|
|
+ .card-input {
|
|
|
+ background: #f2f2f2;
|
|
|
+ border-radius: 8px;
|
|
|
+ border: 1px solid #d8d8d8;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ padding: 18px 17px;
|
|
|
+ height: 56px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ font-family:
|
|
|
+ PingFang SC,
|
|
|
+ PingFang SC;
|
|
|
+ font-weight: 400;
|
|
|
+ font-size: 15px;
|
|
|
+ color: #000000;
|
|
|
+ .card-text {
|
|
|
+ margin: 0 5px 0 8px;
|
|
|
+ }
|
|
|
+ .card-input-right {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ flex-shrink: 0;
|
|
|
+ font-family:
|
|
|
+ PingFang SC,
|
|
|
+ PingFang SC;
|
|
|
+ font-weight: 400;
|
|
|
+ font-size: 15px;
|
|
|
+ color: #000000;
|
|
|
+ margin-left: 17px;
|
|
|
+ .line {
|
|
|
+ height: 25px;
|
|
|
+ border: 1px solid #d8d8d8;
|
|
|
+ width: 0;
|
|
|
+ margin: 0 17px;
|
|
|
+ }
|
|
|
+ .all {
|
|
|
+ font-weight: 500;
|
|
|
+ color: @theme-color1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .price {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #8d8d8d;
|
|
|
+ margin-top: 1px;
|
|
|
+ }
|
|
|
+ :deep(.van-cell) {
|
|
|
+ background: #f2f2f2 !important;
|
|
|
+ padding: 0 !important;
|
|
|
+ }
|
|
|
+ :deep(.van-field__control) {
|
|
|
+ font-family:
|
|
|
+ PingFang SC,
|
|
|
+ PingFang SC;
|
|
|
+ font-weight: 400;
|
|
|
+ font-size: 15px;
|
|
|
+ color: #000000;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .footer-btn {
|
|
|
+ height: 40px !important;
|
|
|
+ line-height: 40px !important;
|
|
|
+ background: linear-gradient(
|
|
|
+ 90deg,
|
|
|
+ @theme-color1 0%,
|
|
|
+ #40a4fb 100%
|
|
|
+ ) !important;
|
|
|
+ border-radius: 28px;
|
|
|
+ font-family:
|
|
|
+ PingFang SC,
|
|
|
+ PingFang SC;
|
|
|
+ font-weight: 500;
|
|
|
+ font-size: 15px;
|
|
|
+ padding: 9px 0;
|
|
|
+ box-sizing: border-box;
|
|
|
+ color: #ffffff;
|
|
|
+ }
|
|
|
+ .pop-content {
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
- height: 86vh;
|
|
|
- padding: 17px 17px 33px;
|
|
|
- box-sizing: border-box;
|
|
|
- .content{
|
|
|
+ .pop-title {
|
|
|
+ padding: 17px;
|
|
|
+ border-bottom: 1px solid #f2f2f2;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ font-family:
|
|
|
+ PingFang SC,
|
|
|
+ PingFang SC;
|
|
|
+ font-weight: 500;
|
|
|
+ font-size: 17px;
|
|
|
+ color: #000000;
|
|
|
+ .title {
|
|
|
flex: 1;
|
|
|
- .card-box{
|
|
|
- margin-bottom: 25px;
|
|
|
- .card-title{
|
|
|
- font-family: PingFang SC, PingFang SC;
|
|
|
- font-weight: 400;
|
|
|
- font-size: 12px;
|
|
|
- color: #8D8D8D;
|
|
|
- margin-bottom: 6px;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: space-between;
|
|
|
- }
|
|
|
- .card-input{
|
|
|
- background: #F2F2F2;
|
|
|
- border-radius: 8px;
|
|
|
- border: 1px solid #D8D8D8;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- padding: 18px 17px;
|
|
|
- height: 56px;
|
|
|
- box-sizing: border-box;
|
|
|
- font-family: PingFang SC, PingFang SC;
|
|
|
- font-weight: 400;
|
|
|
- font-size: 15px;
|
|
|
- color: #000000;
|
|
|
- .card-text{
|
|
|
- margin: 0 5px 0 8px;
|
|
|
- }
|
|
|
- .card-input-right{
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- flex-shrink: 0;
|
|
|
- font-family: PingFang SC, PingFang SC;
|
|
|
- font-weight: 400;
|
|
|
- font-size: 15px;
|
|
|
- color: #000000;
|
|
|
- margin-left: 17px;
|
|
|
- .line{
|
|
|
- height: 25px;
|
|
|
- border: 1px solid #D8D8D8;
|
|
|
- width: 0;
|
|
|
- margin: 0 17px;
|
|
|
- }
|
|
|
- .all{
|
|
|
- font-weight: 500;
|
|
|
- color: @theme-color1;
|
|
|
- }
|
|
|
- }
|
|
|
- .price{
|
|
|
- font-size: 12px;
|
|
|
- color: #8D8D8D;
|
|
|
- margin-top: 1px;
|
|
|
- }
|
|
|
- :deep(.van-cell) {
|
|
|
- background:#F2F2F2 !important;
|
|
|
- padding: 0 !important;
|
|
|
- }
|
|
|
- :deep(.van-field__control) {
|
|
|
- font-family: PingFang SC, PingFang SC;
|
|
|
- font-weight: 400;
|
|
|
- font-size: 15px;
|
|
|
- color: #000000;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- .footer-btn{
|
|
|
- height: 40px !important;
|
|
|
- line-height: 40px !important;
|
|
|
- background: linear-gradient( 90deg, @theme-color1 0%, #40A4FB 100%) !important;
|
|
|
- border-radius:28px;
|
|
|
- font-family: PingFang SC, PingFang SC;
|
|
|
- font-weight: 500;
|
|
|
- font-size: 15px;
|
|
|
- padding: 9px 0;
|
|
|
- box-sizing: border-box;
|
|
|
- color: #FFFFFF;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ }
|
|
|
}
|
|
|
- .pop-content{
|
|
|
+ .list-ul {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ overflow: auto;
|
|
|
+ margin: 16px;
|
|
|
+ .list-li {
|
|
|
display: flex;
|
|
|
- flex-direction: column;
|
|
|
- .pop-title{
|
|
|
- padding: 17px;
|
|
|
- border-bottom: 1px solid #F2F2F2;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- font-family: PingFang SC, PingFang SC;
|
|
|
- font-weight: 500;
|
|
|
- font-size: 17px;
|
|
|
- color: #000000;
|
|
|
- .title{
|
|
|
- flex: 1;
|
|
|
- display: flex;
|
|
|
- justify-content: center;
|
|
|
- }
|
|
|
- }
|
|
|
- .list-ul{
|
|
|
- flex: 1;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- overflow: auto;
|
|
|
- margin: 16px;
|
|
|
- .list-li{
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: space-between;
|
|
|
- font-family: PingFang SC, PingFang SC;
|
|
|
- font-weight: 500;
|
|
|
- margin-bottom: 16px;
|
|
|
- .list-li-lf{
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- font-size: 15px;
|
|
|
- color: #000000;
|
|
|
- }
|
|
|
- .list-li-ri{
|
|
|
- font-size: 15px;
|
|
|
- color: @font-color2;
|
|
|
- text-align: right;
|
|
|
- .list-li-ri-num{
|
|
|
- margin-top: 3px;
|
|
|
- font-weight: 400;
|
|
|
- font-size: 12px;
|
|
|
- color: #8D8D8D;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- .list-li:last-child{
|
|
|
- margin-bottom: 0;
|
|
|
- }
|
|
|
- }
|
|
|
- .list-ul::-webkit-scrollbar{
|
|
|
- width: 0;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ font-family:
|
|
|
+ PingFang SC,
|
|
|
+ PingFang SC;
|
|
|
+ font-weight: 500;
|
|
|
+ margin-bottom: 16px;
|
|
|
+ .list-li-lf {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ font-size: 15px;
|
|
|
+ color: #000000;
|
|
|
}
|
|
|
- .pop-detail{
|
|
|
- padding: 17px 17px 0;
|
|
|
- .pop-detail-title{
|
|
|
- font-family: PingFang SC, PingFang SC;
|
|
|
- font-weight: 500;
|
|
|
- font-size: 17px;
|
|
|
- color: #000000;
|
|
|
- margin-bottom: 20px;
|
|
|
- text-align: center;
|
|
|
- }
|
|
|
- .pop-detail-cell{
|
|
|
- display: flex;
|
|
|
- font-family: PingFang SC, PingFang SC;
|
|
|
- font-weight: 400;
|
|
|
- font-size: 15px;
|
|
|
- color: #4F4F4F;
|
|
|
- padding: 10px 0;
|
|
|
- border-bottom: 1px solid #F2F2F2;
|
|
|
- .cell-label{
|
|
|
- width: 76px;
|
|
|
- flex-shrink: 0;
|
|
|
- }
|
|
|
- .cell-text{
|
|
|
- word-break: break-word;
|
|
|
- }
|
|
|
- }
|
|
|
- .pop-detail-cell:last-child{
|
|
|
- border-bottom: 0;
|
|
|
- }
|
|
|
- .pop-btn{
|
|
|
- margin-top: 53px;
|
|
|
- .btn{
|
|
|
- height: 40px;
|
|
|
- line-height: 40px;
|
|
|
- border-radius: 50px;
|
|
|
- font-family: PingFang SC, PingFang SC;
|
|
|
- font-weight: 500;
|
|
|
- font-size: 15px;
|
|
|
- color: #FFFFFF;
|
|
|
- }
|
|
|
- }
|
|
|
+ .list-li-ri {
|
|
|
+ font-size: 15px;
|
|
|
+ color: @font-color2;
|
|
|
+ text-align: right;
|
|
|
+ .list-li-ri-num {
|
|
|
+ margin-top: 3px;
|
|
|
+ font-weight: 400;
|
|
|
+ font-size: 12px;
|
|
|
+ color: #8d8d8d;
|
|
|
+ }
|
|
|
}
|
|
|
+ }
|
|
|
+ .list-li:last-child {
|
|
|
+ margin-bottom: 0;
|
|
|
+ }
|
|
|
}
|
|
|
-}
|
|
|
-.pop-content-password{
|
|
|
- padding: 27px 35px 25px 34px;
|
|
|
- .pop-title-password{
|
|
|
- font-family: PingFang SC, PingFang SC;
|
|
|
+ .list-ul::-webkit-scrollbar {
|
|
|
+ width: 0;
|
|
|
+ }
|
|
|
+ .pop-detail {
|
|
|
+ padding: 17px 17px 0;
|
|
|
+ .pop-detail-title {
|
|
|
+ font-family:
|
|
|
+ PingFang SC,
|
|
|
+ PingFang SC;
|
|
|
font-weight: 500;
|
|
|
font-size: 17px;
|
|
|
color: #000000;
|
|
|
+ margin-bottom: 20px;
|
|
|
text-align: center;
|
|
|
- }
|
|
|
- .pop-input{
|
|
|
- background: #F2F2F2;
|
|
|
- border-radius: 8px;
|
|
|
- height: 40px;
|
|
|
- margin: 21px 0 31px;
|
|
|
- }
|
|
|
- .pop-btn-password{
|
|
|
+ }
|
|
|
+ .pop-detail-cell {
|
|
|
display: flex;
|
|
|
- justify-content: center;
|
|
|
- .btn-password{
|
|
|
- width: 83px;
|
|
|
- height: 29px;
|
|
|
- line-height: 29px;
|
|
|
- padding: 5px 0 !important;
|
|
|
- border-radius: 6px;
|
|
|
- font-family: PingFang SC, PingFang SC;
|
|
|
- font-weight: 400;
|
|
|
- font-size: 15px;
|
|
|
- box-sizing:border-box;
|
|
|
+ font-family:
|
|
|
+ PingFang SC,
|
|
|
+ PingFang SC;
|
|
|
+ font-weight: 400;
|
|
|
+ font-size: 15px;
|
|
|
+ color: #4f4f4f;
|
|
|
+ padding: 10px 0;
|
|
|
+ border-bottom: 1px solid #f2f2f2;
|
|
|
+ .cell-label {
|
|
|
+ width: 76px;
|
|
|
+ flex-shrink: 0;
|
|
|
}
|
|
|
- .cancel{
|
|
|
- margin-right: 17px !important;
|
|
|
- border: 1px solid #D8D8D8;
|
|
|
- color: #000 !important;
|
|
|
+ .cell-text {
|
|
|
+ word-break: break-word;
|
|
|
}
|
|
|
- .confirm{
|
|
|
- background: @theme-color1;
|
|
|
- color: #FFF;
|
|
|
- font-weight: 500;
|
|
|
- border: none !important;
|
|
|
+ }
|
|
|
+ .pop-detail-cell:last-child {
|
|
|
+ border-bottom: 0;
|
|
|
+ }
|
|
|
+ .pop-btn {
|
|
|
+ margin-top: 53px;
|
|
|
+ .btn {
|
|
|
+ height: 40px;
|
|
|
+ line-height: 40px;
|
|
|
+ border-radius: 50px;
|
|
|
+ font-family:
|
|
|
+ PingFang SC,
|
|
|
+ PingFang SC;
|
|
|
+ font-weight: 500;
|
|
|
+ font-size: 15px;
|
|
|
+ color: #ffffff;
|
|
|
}
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+.pop-content-password {
|
|
|
+ padding: 27px 35px 25px 34px;
|
|
|
+ .pop-title-password {
|
|
|
+ font-family:
|
|
|
+ PingFang SC,
|
|
|
+ PingFang SC;
|
|
|
+ font-weight: 500;
|
|
|
+ font-size: 17px;
|
|
|
+ color: #000000;
|
|
|
+ text-align: center;
|
|
|
+ }
|
|
|
+ .pop-input {
|
|
|
+ background: #f2f2f2;
|
|
|
+ border-radius: 8px;
|
|
|
+ height: 40px;
|
|
|
+ margin: 21px 0 31px;
|
|
|
+ }
|
|
|
+ .pop-btn-password {
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ .btn-password {
|
|
|
+ width: 83px;
|
|
|
+ height: 29px;
|
|
|
+ line-height: 29px;
|
|
|
+ padding: 5px 0 !important;
|
|
|
+ border-radius: 6px;
|
|
|
+ font-family:
|
|
|
+ PingFang SC,
|
|
|
+ PingFang SC;
|
|
|
+ font-weight: 400;
|
|
|
+ font-size: 15px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ }
|
|
|
+ .cancel {
|
|
|
+ margin-right: 17px !important;
|
|
|
+ border: 1px solid #d8d8d8;
|
|
|
+ color: #000 !important;
|
|
|
+ }
|
|
|
+ .confirm {
|
|
|
+ background: @theme-color1;
|
|
|
+ color: #fff;
|
|
|
+ font-weight: 500;
|
|
|
+ border: none !important;
|
|
|
}
|
|
|
+ }
|
|
|
}
|
|
|
:deep(.van-popup--center) {
|
|
|
- margin: 0 40px !important;
|
|
|
- width: auto !important;
|
|
|
+ margin: 0 40px !important;
|
|
|
+ width: auto !important;
|
|
|
+}
|
|
|
+.progress {
|
|
|
+ width: 80vw;
|
|
|
+ margin: 0 auto;
|
|
|
+}
|
|
|
+.progress-text {
|
|
|
+ width: 100vw;
|
|
|
+ margin-top: 45vh;
|
|
|
+ margin-bottom: 30px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ color: #fff;
|
|
|
}
|
|
|
-</style>
|
|
|
+</style>
|