市场上dApp和数字货币的数量正在迅速增长,每年新增的去中心化应用程序超过1000,新数字货币超过500个,以及围绕这他们构建的各种在线服务。区块链技术给我们的生活带来了许多令人瞩目的新特点和好处。然而想法总是相同的,一个交易应该被发送到一个区块链中,并被挖掘,目的是加密的转账或执行任何其他功能的智能合约。
对于某些应用程序和在线服务,了解用户钱包的当前状态或由用户的行为引起的任何交易都是至关重要的。有很多Web服务允许开发人员通过JSON API
获取有关钱包和交易的详细信息(如BlockCypher)。然而,很少有,如果有的话,可以在一个地方看到所需要的所有交易和代币。
在这篇文章中,我将阐明我们如何处理这个问题。
每个区块链项目使用不一致的协议,但是在钱包和交易监测方面,它们都有很多共同点。确定资金转移的时间,并验证交易获得了安全确认的所需数量是加密项目的典型任务。
因此,数字资产追踪器的任务可以分为两部分。首先,查看钱包中传入的交易,并符合我们的过滤标准。第二,使用转账交易的hash确认并监视它。
让我们从以太坊的货币——以太币开始。由于以太坊开发团队和开源社区的努力(我认为自己也是社区的一部分),我们有非常可观的Web3实现:
然而,最原始和最流行的是JavaScript实现,它被称为web3.js。因此,让我们使用这个强大的工具直接与以太坊区块链节点一起工作,看看它是如何工作的:
npm install web3
web3 API不允许你直接订阅钱包的交易,所以为了解决我们的特殊问题,我们必须使用不同的策略。首先,我们订阅所有未决的交易,然后通过发送者的钱包地址和某些其他标准对它们进行过滤。
web3.js允许我们通过多个协议(包括HTTP和WebSockets)直接与以太坊节点进行对话。例如,我使用Rinkeby
的测试网络和由Infura
提供的节点。但是,你可以自由使用任何其他提供者,包括本地节点。
在下面所示的函数中,创建了一个带有WebSockets
提供的新Web3实例,并用于在区块链中建立对新创建的交易的订阅。此实例称为pending
。
订阅对象可以使用两种方法subscribe()
和unsubscribe()
来创建。它们都接受回调函数来处理错误和订阅的任何结果。对于待定交易的订阅,我们可以处理两个事件:data
和error
。当然,data
是我们寻找交易所必需的事件。
data
事件处理程序只有一个输入参数,它表示交易哈希,并且在需要比哈希更详细的情况下检查每个交易是否符合我们的搜索标准。这是一个不同的web3.js方法,getTransaction()
,可以用来读取交易细节。由于这是异步调用,所以我简单地将其封装到try-catch语句中并等待响应。你可以在这里的Web3官方文档中找到响应对象格式。
一旦收到响应,交易与我们的过滤条件匹配,我们需要启动交易确认过程,并通过调用它的unsubscribe()
方法取消订阅。如果我们没有一个满足我们的过滤器的交易,我们只需从函数返回到订阅。该函数如下所示:
function watchEtherTransfers() {
// Instantiate web3 with WebSocket provider
const web3 = new Web3(new Web3.providers.WebsocketProvider('wss://rinkeby.infura.io/ws'))
// Instantiate subscription object
const subscription = web3.eth.subscribe('pendingTransactions')
// Subscribe to pending transactions
subscription.subscribe((error, result) => {
if (error) console.log(error)
})
.on('data', async (txHash) => {
try {
// Instantiate web3 with HttpProvider
const web3Http = new Web3('https://rinkeby.infura.io/')
// Get transaction details
const trx = await web3Http.eth.getTransaction(txHash)
const valid = validateTransaction(trx)
// If transaction is not valid, simply return
if (!valid) return
console.log('Found incoming Ether transaction from ' + process.env.WALLET_FROM + ' to ' + process.env.WALLET_TO);
console.log('Transaction value is: ' + process.env.AMOUNT)
console.log('Transaction hash is: ' + txHash + '\n')
// Initiate transaction confirmation
confirmEtherTransaction(txHash)
// Unsubscribe from pending transactions.
subscription.unsubscribe()
}
catch (error) {
console.log(error)
}
})
}
请注意,上面的示例使用HttpProvider
来获取交易细节,因为与WebSockets
有连接错误的风险要高得多。在我三十分钟观察中,WebSocketProvider
至少有两个错误,而HttpProvider
没有。
一旦确定了需要监测的交易,我们就可以开始监视确认,直到它们达到所需的数量。
有一种非常简单的方式来确认,是基于在一个交易最初被开采的时候区块号码的方法,即通过当前块号和交易块号之间的差值来作为确认计算值。为了得到它,我建议使用下面概述的辅助函数。
async function getConfirmations(txHash) {
try {
// Instantiate web3 with HttpProvider
const web3 = new Web3('https://rinkeby.infura.io/')
// Get transaction details
const trx = await web3.eth.getTransaction(txHash)
// Get current block number
const currentBlock = await web3.eth.getBlockNumber()
// When transaction is unconfirmed, its block number is null.
// In this case we return 0 as number of confirmations
return trx.blockNumber === null ? 0 : currentBlock - trx.blockNumber
}
catch (error) {
console.log(error)
}
}
作为调用此函数的结果,我们得到一个表示确认计算值的整数值。有些项目需要100次确认,有些不到10次,这就是为什么我们必须递归使用这个函数。
在下面的示例中,我通过setTimeout()
函数调用getConfirmations()
实现,但是你也可以用其他方式实现它。
我选择了10作为缺省的确认数量,设置了30秒的间隔,这比以太坊的块挖掘时间(10到19秒)略微多一点。
function confirmEtherTransaction(txHash, confirmations = 10) {
setTimeout(async () => {
// Get current number of confirmations and compare it with sought-for value
const trxConfirmations = await getConfirmations(txHash)
console.log('Transaction with hash ' + txHash + ' has ' + trxConfirmations + ' confirmation(s)')
if (trxConfirmations >= confirmations) {
// Handle confirmation event according to your business logic
console.log('Transaction with hash ' + txHash + ' has been successfully confirmed')
return
}
// Recursive call
return confirmEtherTransaction(txHash, confirmations)
}, 30 * 1000)
}
我们都知道ERC20代币是建立在以太坊上的智能合约,乍一看,似乎很容易监测Ether。查找具有一定数量钱包中的加密交易与Ether不同,因为交易的接收方地址将始终是智能合约的地址。但是,对于每一个代币的转账,都调用一个特殊代币的合约函数。这个函数调用区块链上的转账事件,当它成功时,所有事件都由区块链记录,在任何时候都可以访问。
我们的目标是捕获一个满足要求的交易,直到它被发布到区块链,所以我们将使用相同的WebSocketProvider
。但是,代替订阅对象,我们将实例化代币合约对象,并监听转账事件。
需要一个代币合约来订阅和解析交易数据,因为行数据是十六进制格式的,因此对我们来说是不可读的。对于合约对象的实例化,我们需要代币的JSON-ABI(参见示例)和部署在以太坊上的合约地址。
web3.js API允许我们通过设置过滤事件的参数来过滤事件。在转账事件的情况下,这样的参数是_from
,_to
和_value
。在为订阅事件设置选项对象时,还可以设置开始查找事件区块号。
当我们过滤交易事件时,一旦出现在区块链上,我们将得到所查询的交易,然后我们可以进入确认阶段。
function watchTokenTransfers() {
// Instantiate web3 with WebSocketProvider
const web3 = new Web3(new Web3.providers.WebsocketProvider('wss://rinkeby.infura.io/ws'))
// Instantiate token contract object with JSON ABI and address
const tokenContract = new web3.eth.Contract(
TOKEN_ABI, process.env.TOKEN_CONTRACT_ADDRESS,
(error, result) => { if (error) console.log(error) }
)
// Generate filter options
const options = {
filter: {
_from: process.env.WALLET_FROM,
_to: process.env.WALLET_TO,
_value: process.env.AMOUNT
},
fromBlock: 'latest'
}
// Subscribe to Transfer events matching filter criteria
tokenContract.events.Transfer(options, async (error, event) => {
if (error) {
console.log(error)
return
}
console.log('Found incoming Pluton transaction from ' + process.env.WALLET_FROM + ' to ' + process.env.WALLET_TO + '\n');
console.log('Transaction value is: ' + process.env.AMOUNT)
console.log('Transaction hash is: ' + txHash + '\n')
// Initiate transaction confirmation
confirmEtherTransaction(event.transactionHash)
return
})
}
以太币交易对象遵循与转账交易相同的规则,这意味着我们可以在上述示例中使用与以太交易处理完全相同的confirmEtherTransaction()
函数。
这些示例显示了如何具体追踪ERC20代币转账,但同样的技术可以应用于任何其他智能合约的功能,取决于你的业务需求。我在上面的例子中总结了一个简单的node.js 服务,它可以作为区块链探索的起点。
我们创建了一个特殊的存储库,它具有完整的工作示例,用于描述本文中的所有状态。可以在你的下一个项目的demo中使用它:
区块链追踪器实例源代码
- 以太坊教程,主要介绍web3.js与智能合约dapp应用开发,适合入门。
- 以太坊开发,主要是介绍使用node.js、mongodb、区块链、ipfs实现去中心化电商DApp实战,适合进阶。
- web3j教程,主要是针对java和android程序员进行区块链以太坊开发的web3j详解。
- python以太坊,主要是针对python工程师使用web3.py进行区块链以太坊开发的详解。
- php以太坊,主要是介绍使用php进行智能合约开发交互,进行账号创建、交易、转账、代币开发以及过滤器和事件等内容。
- C#以太坊,主要讲解如何使用C#开发基于.Net的以太坊应用,包括账户管理、状态与交易、智能合约开发与交互、过滤器和事件等。
汇智网原创翻译,转载请标明出处。这里是原文