【发布时间】:2018-12-18 11:24:24
【问题描述】:
当用户在我的网络应用上注册时,会生成一个 HD 钱包,并在 blockcypher API 上实例化一个 webhook,以侦听未经确认和单一确认的交易。当检测到未确认的交易时,从 blockcypher 网站向我的 express 应用程序上的路由发出事件,并通知用户他们的交易已收到。当交易有一个确认时,我正试图将钱从他们的钱包转移到一个主要的热钱包。但是,当我尝试广播原始 tx 时出现错误。
这是我的代码。 这个错误是什么意思,我该如何解决。 此外,如果有实现相同结果的替代方法。会很乐意听到/尝试一下。
这是监听和签署交易的代码。
// UNCONFIRMED TRANSACTION
api.post('/callbacks/new-tx', async function(req, res) {
console.log('POST: Callback received from blockcypher');
console.log(req.body);
fs.appendFile('Deposits.txt', 'Unconfirmed Deposit\n' + JSON.stringify(req.body) + '\n');
// FIND OWNER OF ADDRESS
User.findOne({'keyPairs.address': req.body.addresses[0]}, function(err, user) {
// UPDATE BALANCE OF USER
// user.balance += req.body.outputs[0].value;
// CREATE TRANSACTION MODEL OF EVENT (RECORD OF TRANSACTION TO DB)
var transaction = new Transaction({
to: req.body.addresses[0],
from: req.body.addresses[1],
change: req.body.addresses[2],
amount: req.body.outputs[0].value,
time: moment().format('MMMM Do YYYY, h:mm:ss a'),
});
transaction.save((err) => {
// HANDLE ERROR
if (err) {return 'rest in pieces'}
io.emit('notify', {
user_id: user._id,
title: 'Deposit Received',
message: 'We\'ve recieved your deposit of ' + req.body.outputs.value + 'BTC. Your balance will be updated after 1 confirmation.',
color: 'success',
})
})
});
// RESPOND TO API
res.status(200).send('ok');
});
// 1 CONFIRMATION
api.post('/callbacks/confirmed', async function(req, res) {
console.log('confirmed blockcypher api');
console.log(req.body);
fs.appendFile('Deposits.txt', 'Confirmed Deposit\n' + JSON.stringify(req.body) + '\n');
// NEED TO CHECK STRUCTURE OF CALLBACK RESPONSE
let webhook_id;
let address = req.body.addresses[1];
User.findOne({'keyPairs.address' : address}, async function(err, user) {
var keypair = await WalletService.createKeyPair(user.accountIndex);
user.btc_address = keypair.address;
user.btc_s = keypair.secret;
// SEND COINS TO MAIN WALLET
async function send() {
let max;
let main_wallet = config.master_address;
let transaction = new bitcore.Transaction();
WalletService.getAddressUtxo(address).then(utxo => {
for(let i=0; i<utxo.length; i++) {
transaction.from(utxo[i])
}
// set full wallet balance
WalletService.getAddressBalance(address)
.then(balance => {
max = balance.final_balance;
transaction.to(main_wallet, max);
transaction.change(keypair.address);
let priv_key = new Promise((resolve, reject) => {
user.keyPairs.forEach(kp => {
if (kp.address == address) {
resolve(kp);
}
})
})
priv_key.then(kp => {
axios.get('https://bitcoinfees.earn.com/api/v1/fees/recommended')
.then(fee => {
var f = fee.data;
var finalFee = (transaction.toString().length / 2) * f.hourFee;
transaction.to(main_wallet, max-finalFee);
transaction.fee(finalFee);
transaction.sign(kp.secret);
// EMIT TRANSACTION!!!!!!!!!
axios.post('https://api.blockcypher.com/v1/btc/test3/txs/push', JSON.stringify({
tx: transaction.toString(),
})).then(res => {
console.log('Transaction Successfully Sent');
console.log('Response: ');
console.log(res.data);
})
/*
NOTICE!
Remember that when a user deposits to their HD wallet, they pay fee to send.
Once balance is confirmed, we need to move money to our main wallet.
Moving this money will incur another fee. So add the full amount to users
balance and send the amount MINUS the fee to our big daddy wallet.
*/
// on success
user.balance += bitcore.Unit.fromSatoshis(max).toMilis();
io.emit('increase-balance', {
id: user._id,
amount: bitcore.Unit.fromSatoshis(max).toMilis(),
});
io.emit('notify', {
user_id: user._id,
color: 'success',
message: 'Deposit has been confirmed. Your balance has been updated'
});
// ======================================
})
})
})
})
} await send();
// ========================
user.save((err) => {
console.log('new keypair generated and saved for' + user.username);
// unconfirmed hook
var unconfirmed_hook = {
"event": "unconfirmed-tx",
"address": address,
"url": config.callback_address + "/new-tx"
}
// confirmed hook
var confirmed_hook = {
"event": "confirmed-tx",
"address": address,
"url": config.callback_address + "/confirmed"
}
// delete old webhook
axios({
method: 'DELETE',
url: 'https://api.blockcypher.com/v1/btc/test3/hooks/' + webhook_id,
});
// create new webhooks
// create unconfirmed_hook
axios({
method: 'POST',
url: 'https://api.blockcypher.com/v1/btc/test3/hooks?token=' + config.blockcypher_token,
data: JSON.stringify(unconfirmed_hook)
}).then(res => {
console.log('*NEW* Webhook Unconfirmed Webhook Created')
})
axios({
method: 'POST',
url: 'https://api.blockcypher.com/v1/btc/test3/hooks?token=' + config.blockcypher_token,
data: JSON.stringify(confirmed_hook),
}).then(res => {
console.log('*NEW* Webhook Confirmed Webhook Created')
})
});
});
});
请帮忙。 谢谢。
【问题讨论】:
-
我建议添加一些额外的
console.log方法来比较您的vin交易和生成的vout交易。该错误似乎非常简单,因为它表示 inputs 的 sum 小于 outputs 的总和。区块链交易都只是金额移动的证明,所以问题可能是您使用的输入不足以覆盖您期望的输出,或者 txfee 没有被纳入数学 eq -
如果您可以提供您已生成并尝试签名/提交的
rawtransaction,那也会很有帮助。 -
嘿,抱歉耽搁了几天,忙。 Here's the rawtx 0100000001896ab75fa96301f95fd2f86bda3e0f8284714ef1a788a201e0ac9f5698159e20000000006a47304402207df2ebe1d9c6864c05571e515b7701c4ab6f14e13002484c8fea220c5320fbf5022051e29462a5b8c139b551ec4b66bc6a3b0093754b8d45fb7c8b0d6772fcbb0498012103850a664b27a1d4d066c4cd6b79df1c5a55e86f8c608e0510077b03229e7f7290ffffffff0261180000000000001976a914d22ac447895abd2ed9523042a407c3a85db3fb9188ac0d170000000000001976a914d22ac447895abd2ed9523042a407c3a85db3fb9188ac00000000
-
别担心,我已经解决了这个问题。非常愚蠢的错误,我一生都看不到。
标签: node.js webhooks bitcoin bitcore blockcypher