Migrate plugins to lib directory

This commit is contained in:
Josh Harvey 2017-04-15 19:12:29 +03:00
parent 09b29bba56
commit e7ab8223c2
27 changed files with 869 additions and 858 deletions

View file

@ -0,0 +1,146 @@
const path = require('path')
const os = require('os')
const RpcClient = require('bitcoind-rpc')
const fs = require('fs')
const pify = require('pify')
const BN = require('../../../bn')
const NAME = 'Bitcoind'
const SATOSHI_SHIFT = 8
const configPath = path.resolve(os.homedir(), '.bitcoin', 'bitcoin.conf')
const pluginConfig = {
account: '',
bitcoindConfigurationPath: configPath
}
function initRpc () {
const bitcoindConf = parseConf(pluginConfig.bitcoindConfigurationPath)
const rpcConfig = {
protocol: 'http',
user: bitcoindConf.rpcuser,
pass: bitcoindConf.rpcpassword
}
return new RpcClient(rpcConfig)
}
function richError (msg, name) {
const err = new Error(msg)
err.name = name
return err
}
/*
* initialize RpcClient
*/
function parseConf (confPath) {
const conf = fs.readFileSync(confPath)
const lines = conf.toString().split('\n')
const res = {}
for (let i = 0; i < lines.length; i++) {
const keyVal = lines[i].split('=')
// skip when value is empty
if (!keyVal[1]) continue
res[keyVal[0]] = keyVal[1]
}
return res
}
function checkCryptoCode (cryptoCode) {
if (cryptoCode !== 'BTC') throw new Error('Unsupported crypto: ' + cryptoCode)
}
// We want a balance that includes all spends (0 conf) but only deposits that
// have at least 1 confirmation. getbalance does this for us automatically.
function balance (account, cryptoCode) {
return new Promise((resolve, reject) => {
checkCryptoCode(cryptoCode)
const rpc = initRpc()
rpc.getBalance(pluginConfig.account, 1, (err, result) => {
if (err) return reject(err)
if (result.error) {
return reject(richError(result.error, 'bitcoindError'))
}
resolve(BN(result.result).shift(SATOSHI_SHIFT).round())
})
})
}
function sendCoins (account, address, cryptoAtoms, cryptoCode) {
const rpc = initRpc()
const confirmations = 1
const bitcoins = cryptoAtoms.shift(-SATOSHI_SHIFT).toFixed(8)
return new Promise((resolve, reject) => {
checkCryptoCode(cryptoCode)
rpc.sendFrom(pluginConfig.account, address, bitcoins, confirmations, (err, result) => {
if (err) {
if (err.code === -6) {
return reject(richError('Insufficient funds', 'InsufficientFunds'))
}
if (err instanceof Error) {
return reject(err)
}
return reject(richError(err.message, 'bitcoindError'))
}
resolve(result.result)
})
})
}
function newAddress (account, cryptoCode, info) {
return new Promise((resolve, reject) => {
checkCryptoCode(cryptoCode)
const rpc = initRpc()
rpc.getNewAddress((err, result) => {
if (err) return reject(err)
resolve(result.result)
})
})
}
function addressBalance (address, confs) {
const rpc = initRpc()
return pify(rpc.getReceivedByAddress.bind(rpc))(address, confs)
.then(r => BN(r.result).shift(SATOSHI_SHIFT).round())
}
const confirmedBalance = address => addressBalance(address, 1)
const pendingBalance = address => addressBalance(address, 0)
function getStatus (account, toAddress, requested, cryptoCode) {
return Promise.resolve()
.then(() => checkCryptoCode(cryptoCode))
.then(() => confirmedBalance(toAddress))
.then(confirmed => {
if (confirmed.gte(requested)) return {status: 'confirmed'}
return pendingBalance(toAddress)
.then(pending => {
if (pending.gte(requested)) return {status: 'authorized'}
if (pending.gt(0)) return {status: 'insufficientFunds'}
return {status: 'notSeen'}
})
})
}
module.exports = {
NAME,
balance,
sendCoins,
newAddress,
getStatus
}

View file

@ -0,0 +1,91 @@
const BitGo = require('bitgo')
const BN = require('../../../bn')
const pjson = require('../../../package.json')
const userAgent = 'Lamassu-Server/' + pjson.version
const NAME = 'BitGo'
function buildBitgo (account) {
return new BitGo.BitGo({accessToken: account.token, env: 'prod', userAgent: userAgent})
}
function getWallet (account) {
const bitgo = buildBitgo(account)
return bitgo.wallets().get({ id: account.walletId })
}
function checkCryptoCode (cryptoCode) {
if (cryptoCode !== 'BTC') {
return Promise.reject(new Error('Unsupported crypto: ' + cryptoCode))
}
return Promise.resolve()
}
function sendCoins (account, address, cryptoAtoms, cryptoCode) {
return checkCryptoCode(cryptoCode)
.then(() => getWallet(account))
.then(wallet => {
const params = {
address: address,
amount: cryptoAtoms.toNumber(),
walletPassphrase: account.walletPassphrase
}
return wallet.sendCoins(params)
})
.then(result => {
return result.hash
})
.catch(err => {
if (err.message === 'Insufficient funds') {
err.name = 'InsufficientFunds'
}
throw err
})
}
function balance (account, cryptoCode) {
return checkCryptoCode(cryptoCode)
.then(() => getWallet(account))
.then(wallet => BN(wallet.wallet.spendableConfirmedBalance))
}
function newAddress (account, cryptoCode, info) {
return checkCryptoCode(cryptoCode)
.then(() => getWallet(account))
.then(wallet => {
return wallet.createAddress()
.then(result => {
const address = result.address
// If a label was provided, set the label
if (info.label) {
return wallet.setLabel({ address: address, label: info.label })
.then(() => address)
}
return address
})
})
}
function getStatus (account, toAddress, requested, cryptoCode) {
const bitgo = buildBitgo(account)
return checkCryptoCode(cryptoCode)
.then(() => bitgo.blockchain().getAddress({address: toAddress}))
.then(rec => {
if (rec.balance === 0) return {status: 'notSeen'}
if (requested.gt(rec.balance)) return {status: 'insufficientFunds'}
if (requested.gt(rec.confirmedBalance)) return {status: 'authorized'}
return {status: 'confirmed'}
})
}
module.exports = {
NAME,
balance,
sendCoins,
newAddress,
getStatus
}

View file

@ -0,0 +1,30 @@
{
"code": "bitgo",
"display": "BitGo",
"fields": [
{
"code": "token",
"display": "API token",
"fieldType": "string",
"secret": true,
"required": true,
"value": ""
},
{
"code": "walletId",
"display": "Wallet ID",
"fieldType": "string",
"secret": false,
"required": true,
"value": ""
},
{
"code": "walletPassphrase",
"display": "Wallet passphrase",
"fieldType": "string",
"secret": true,
"required": true,
"value": ""
}
]
}

View file

@ -0,0 +1,53 @@
const BN = require('../../../bn')
const NAME = 'FakeWallet'
const SECONDS = 1000
const UNSEEN_TIME = 6 * SECONDS
const PUBLISH_TIME = 12 * SECONDS
const AUTHORIZE_TIME = 60 * SECONDS
let t0
function balance (account, cryptoCode) {
return Promise.resolve()
.then(() => {
if (cryptoCode === 'BTC') return BN(1e8 * 10)
if (cryptoCode === 'ETH') return BN(1e18 * 10)
throw new Error('Unsupported crypto: ' + cryptoCode)
})
}
function sendCoins (account, toAddress, cryptoAtoms, cryptoCode) {
return new Promise(resolve => {
setTimeout(() => {
console.log('[%s] DEBUG: Mock wallet sending %s cryptoAtoms to %s',
cryptoCode, cryptoAtoms.toString(), toAddress)
resolve('<txHash>')
}, 2000)
})
}
function newAddress () {
t0 = Date.now()
return Promise.resolve('<Fake address, don\'t send>')
}
function getStatus (account, toAddress, cryptoAtoms, cryptoCode) {
const elapsed = Date.now() - t0
if (elapsed < UNSEEN_TIME) return Promise.resolve({status: 'notSeen'})
if (elapsed < PUBLISH_TIME) return Promise.resolve({status: 'published'})
if (elapsed < AUTHORIZE_TIME) return Promise.resolve({status: 'authorized'})
console.log('[%s] DEBUG: Mock wallet has confirmed transaction', cryptoCode)
return Promise.resolve({status: 'confirmed'})
}
module.exports = {
NAME,
balance,
sendCoins,
newAddress,
getStatus
}