Skip to content

Commit

Permalink
提交
Browse files Browse the repository at this point in the history
  • Loading branch information
webkubor authored and webkubor committed Jan 8, 2025
1 parent b631017 commit 9a49002
Show file tree
Hide file tree
Showing 11 changed files with 273 additions and 292 deletions.
3 changes: 2 additions & 1 deletion .env
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
VITE_BASE_WEB_VERSION = v0.1.0
VITE_BASE_WEB_VERSION = v0.1.0
VITE_INFURA_KEY = YOUR_INFURA_PROJECT_ID
3 changes: 0 additions & 3 deletions src/main.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import { startMonitoring } from './services/monitorService'

const app = createApp(App);
app.use(router).mount('#app')

// 启动 USDT 交易监控
startMonitoring()
9 changes: 7 additions & 2 deletions src/router/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ let children = [
{
path: "/home",
name: "Home",
component: () => import("@/views/home/index.vue"),
component: () => import("@/views/home/index.vue"),
},
{
path: "/metamask",
Expand All @@ -16,7 +16,12 @@ let children = [
{
path: "/wallectconnect",
name: "Wallectconnect",
component: ()=> import("@/views/wallectconnect/index.vue"),
component: () => import("@/views/wallectconnect/index.vue"),
},
{
path: "/monitor",
name: "Monitor",
component: () => import("@/views/monitor/index.vue"),
},
];

Expand Down
121 changes: 56 additions & 65 deletions src/services/monitorService.ts
Original file line number Diff line number Diff line change
@@ -1,76 +1,67 @@
import { ref } from 'vue'
import { ethers } from 'ethers'
import ERC20 from '@/abis/ERC20.json'
import { USDT_CONTRACTS } from '@/utils/networks'
import { getTransactions as getEthTransactions } from '@/contract/eth'
import { getTransactions as getBscTransactions } from '@/contract/bsc'

// 监控地址列表
const monitoredAddresses = ref<string[]>([])

// 交易记录
const transactionRecords = ref<any[]>([])

// USDT 合约地址
const USDT_CONTRACT_ADDRESS = '0xdAC17F958D2ee523a2206206994597C13D831ec7'
interface Transaction {
hash: string
timestamp: number
amount: string
status: string
from: string
to: string
}

// 初始化 provider
const provider = new ethers.providers.InfuraProvider('mainnet', process.env.VITE_INFURA_PROJECT_ID)
/**
* 获取监控服务实例
*/
export const useMonitorService = () => {
const loading = ref(false)
const error = ref(null)

// 初始化 USDT 合约
const usdtContract = new ethers.Contract(
USDT_CONTRACT_ADDRESS,
ERC20.abi,
provider
)
/**
* 获取指定地址的 USDT 交易记录
* @param {string} address - 监控地址
* @param {string} chain - 链类型 (ETH/BSC)
* @returns {Promise<Transaction[]>} 交易记录数组
*/
const getTransactions = async (address: string, chain: string): Promise<Transaction[]> => {
try {
loading.value = true
error.value = null

// 添加监控地址
export function addMonitoredAddress(address: string) {
if (!monitoredAddresses.value.includes(address)) {
monitoredAddresses.value.push(address)
startWatchingAddress(address)
}
}
const contractAddress = USDT_CONTRACTS[chain]
if (!contractAddress) {
throw new Error('不支持的链类型')
}

// 获取监控地址列表
export function getMonitoredAddresses() {
return monitoredAddresses.value
}
let transactions: Transaction[] = []
switch (chain) {
case 'ETH':
transactions = await getEthTransactions(address, contractAddress)
break
case 'BSC':
transactions = await getBscTransactions(address, contractAddress)
break
default:
throw new Error('不支持的链类型')
}

// 获取交易记录
export function getTransactionRecords() {
return transactionRecords.value
}

// 启动地址监控
function startWatchingAddress(address: string) {
// 监听 Transfer 事件
const filter = usdtContract.filters.Transfer(null, address)

usdtContract.on(filter, (from, to, value, event) => {
const record = {
txHash: event.transactionHash,
from: from,
to: to,
value: ethers.utils.formatUnits(value, 6), // USDT 6 decimals
timestamp: Math.floor(Date.now() / 1000)
return transactions.map(tx => ({
...tx,
status: tx.status ? '成功' : '失败'
}))
} catch (err) {
error.value = err.message
throw err
} finally {
loading.value = false
}

transactionRecords.value.unshift(record)
})
}

// 启动监控服务
export function startMonitoring() {
// 加载已配置的地址
const storedAddresses = localStorage.getItem('monitoredAddresses')
if (storedAddresses) {
monitoredAddresses.value = JSON.parse(storedAddresses)
monitoredAddresses.value.forEach(startWatchingAddress)
}

// 定期保存地址列表
setInterval(() => {
localStorage.setItem(
'monitoredAddresses',
JSON.stringify(monitoredAddresses.value)
)
}, 10000)
return {
loading,
error,
getTransactions
}
}
112 changes: 23 additions & 89 deletions src/utils/format.js
Original file line number Diff line number Diff line change
@@ -1,96 +1,30 @@
import _ from 'lodash'

/**
* @description: 纯数量格式化
* @param {number} num 数字
* @param {number} decimal 小数
* @param {boolean} unit 是否带单位
* @return {number}
*/
export function formatNum (num, decimal = 2, unit = false) {
if (!num) return num
const units = ['', 'K', 'M', 'B', 'T']
let unitIndex
let result = num
if (num < 1000 * 10) {
// nothing
unitIndex = 0
} else if (num < Math.pow(1000, 2) * 10) {
// K
unitIndex = 1
} else if (num < Math.pow(1000, 3) * 10) {
// M
unitIndex = 2
} else if (num < Math.pow(1000, 4) * 10) {
// B
unitIndex = 3
} else {
// T
unitIndex = 4
}
if (unit) {
result = _.divide(result, Math.pow(1000, unitIndex))
result = retain(result, decimal)
result = toCurrency(result)
result = result + units[unitIndex]
} else {
result = retain(result, decimal)
result = toCurrency(result)
}
return result

function toCurrency (num) {
const parts = num.toString().split('.')
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',')
return parts.join('.')
}
function retain (num, decimal) {
const magnification = Math.pow(10, decimal)
return Math.floor(num * magnification) / magnification
}
}

/**
* @description: 按照精度截取数据(小数,科学记数法,非四舍五入)
* @param {*}
* @return {*} string
*/
export function dealDecimals (value, decimals) {
let amount = String(value)
let isDealPosint = amount.split('.')
if (!isDealPosint && value * 1 < 0 && isDealPosint.length < 2) {
amount = _toNonExponential(value * 1)
isDealPosint = amount.split('.')
}
if (isDealPosint && isDealPosint.length === 2) {
const integer = isDealPosint[0]
const point = isDealPosint[1]
const maxLength = decimals * 1 + integer.length + 1
if (point && point.length) return amount.substring(0, maxLength)
}
return amount
}

/**
* @description: 将科学记数法转化正常计数
* @param {*} num
* @return {*}
* 格式化时间戳为本地时间字符串
* @param {number|string} timestamp - 时间戳
* @returns {string} 格式化后的时间字符串
*/
function _toNonExponential (num) {
const m = num.toExponential().match(/\d(?:\.(\d*))?e([+-]\d+)/)
return num.toFixed(Math.max(0, (m[1] || '').length - m[2]))
export const formatDate = (timestamp) => {
const date = new Date(Number(timestamp) * 1000)
return date.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false
})
}

/**
* @description: 长文本省略中间部分
* @param {string} str 文本内容
* @param {number} start 保留文本头部长度
* @param {number} end 保留文本尾部长度
* @return {string}
* 缩短哈希字符串显示
* @param {string} hash - 原始哈希字符串
* @param {number} [startLen=6] - 开头保留长度
* @param {number} [endLen=4] - 结尾保留长度
* @returns {string} 缩短后的哈希字符串
*/
export function ellipsisStr (str, start = 6, end = 4) {
if (typeof str === 'string') {
return str.slice(0, start) + '...' + str.slice(-end)
}
return str
export const shortenHash = (hash, startLen = 6, endLen = 4) => {
if (!hash || typeof hash !== 'string') return ''
if (hash.length <= startLen + endLen) return hash
return `${hash.slice(0, startLen)}...${hash.slice(-endLen)}`
}
Loading

0 comments on commit 9a49002

Please sign in to comment.