Support ZEC
This commit is contained in:
parent
9b51565303
commit
45e6e2b82d
10 changed files with 105 additions and 47 deletions
|
|
@ -155,27 +155,34 @@ function fetchData () {
|
||||||
return machineLoader.getMachineNames()
|
return machineLoader.getMachineNames()
|
||||||
.then(machineList => ({
|
.then(machineList => ({
|
||||||
currencies: massageCurrencies(currencies),
|
currencies: massageCurrencies(currencies),
|
||||||
cryptoCurrencies: [{crypto: 'BTC', display: 'Bitcoin'}, {crypto: 'ETH', display: 'Ethereum'}],
|
cryptoCurrencies: [
|
||||||
|
{crypto: 'BTC', display: 'Bitcoin'},
|
||||||
|
{crypto: 'ETH', display: 'Ethereum'},
|
||||||
|
{crypto: 'ZEC', display: 'Zcash'}
|
||||||
|
],
|
||||||
languages: languages,
|
languages: languages,
|
||||||
countries,
|
countries,
|
||||||
accounts: [
|
accounts: [
|
||||||
{code: 'bitpay', display: 'Bitpay', class: 'ticker', cryptos: ['BTC']},
|
{code: 'bitpay', display: 'Bitpay', class: 'ticker', cryptos: ['BTC']},
|
||||||
{code: 'kraken', display: 'Kraken', class: 'ticker', cryptos: ['BTC', 'ETH']},
|
{code: 'kraken', display: 'Kraken', class: 'ticker', cryptos: ['BTC', 'ETH', 'ZEC']},
|
||||||
{code: 'bitstamp', display: 'Bitstamp', class: 'ticker', cryptos: ['BTC']},
|
{code: 'bitstamp', display: 'Bitstamp', class: 'ticker', cryptos: ['BTC']},
|
||||||
{code: 'coinbase', display: 'Coinbase', class: 'ticker', cryptos: ['BTC', 'ETH']},
|
{code: 'coinbase', display: 'Coinbase', class: 'ticker', cryptos: ['BTC', 'ETH']},
|
||||||
{code: 'bitcoind', display: 'bitcoind', class: 'wallet', cryptos: ['BTC']},
|
{code: 'bitcoind', display: 'bitcoind', class: 'wallet', cryptos: ['BTC']},
|
||||||
{code: 'bitgo', display: 'BitGo', class: 'wallet', cryptos: ['BTC']},
|
{code: 'bitgo', display: 'BitGo', class: 'wallet', cryptos: ['BTC']},
|
||||||
{code: 'geth', display: 'geth', class: 'wallet', cryptos: ['ETH']},
|
{code: 'geth', display: 'geth', class: 'wallet', cryptos: ['ETH']},
|
||||||
{code: 'mock-wallet', display: 'Mock wallet', class: 'wallet', cryptos: ['BTC', 'ETH']},
|
{code: 'zcashd', display: 'zcashd', class: 'wallet', cryptos: ['ZEC']},
|
||||||
{code: 'no-exchange', display: 'No exchange', class: 'exchange', cryptos: ['BTC', 'ETH']},
|
{code: 'bitstamp', display: 'Bitstamp', class: 'exchange', cryptos: ['BTC']},
|
||||||
{code: 'mock-exchange', display: 'Mock exchange', class: 'exchange', cryptos: ['BTC', 'ETH']},
|
{code: 'kraken', display: 'Kraken', class: 'exchange', cryptos: ['BTC', 'ETH', 'ZEC']},
|
||||||
|
{code: 'mock-wallet', display: 'Mock wallet', class: 'wallet', cryptos: ['BTC', 'ETH', 'ZEC']},
|
||||||
|
{code: 'no-exchange', display: 'No exchange', class: 'exchange', cryptos: ['BTC', 'ETH', 'ZEC']},
|
||||||
|
{code: 'mock-exchange', display: 'Mock exchange', class: 'exchange', cryptos: ['BTC', 'ETH', 'ZEC']},
|
||||||
{code: 'mock-sms', display: 'Mock SMS', class: 'sms'},
|
{code: 'mock-sms', display: 'Mock SMS', class: 'sms'},
|
||||||
{code: 'mock-id-verify', display: 'Mock ID verifier', class: 'idVerifier'},
|
{code: 'mock-id-verify', display: 'Mock ID verifier', class: 'idVerifier'},
|
||||||
{code: 'twilio', display: 'Twilio', class: 'sms'},
|
{code: 'twilio', display: 'Twilio', class: 'sms'},
|
||||||
{code: 'mailjet', display: 'Mailjet', class: 'email'},
|
{code: 'mailjet', display: 'Mailjet', class: 'email'},
|
||||||
{code: 'all-zero-conf', display: 'All pass', class: 'zeroConf'},
|
{code: 'all-zero-conf', display: 'All pass', class: 'zeroConf'},
|
||||||
{code: 'blockcypher', display: 'Blockcypher', class: 'zeroConf', cryptos: ['BTC']},
|
{code: 'blockcypher', display: 'Blockcypher', class: 'zeroConf', cryptos: ['BTC']},
|
||||||
{code: 'mock-zero-conf', display: 'Mock 0-conf', class: 'zeroConf', cryptos: ['BTC']}
|
{code: 'mock-zero-conf', display: 'Mock 0-conf', class: 'zeroConf', cryptos: ['BTC', 'ZEC']}
|
||||||
],
|
],
|
||||||
machines: machineList.map(machine => ({machine: machine.deviceId, display: machine.name}))
|
machines: machineList.map(machine => ({machine: machine.deviceId, display: machine.name}))
|
||||||
}))
|
}))
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,28 @@
|
||||||
const coins = {
|
const coins = {
|
||||||
BTC: {unitScale: 8},
|
BTC: {unitScale: 8},
|
||||||
ETH: {unitScale: 18}
|
ETH: {unitScale: 18},
|
||||||
|
ZEC: {unitScale: 8}
|
||||||
}
|
}
|
||||||
|
|
||||||
const cryptoDisplays = [
|
const cryptoDisplays = [
|
||||||
{cryptoCode: 'BTC', display: 'Bitcoin'},
|
{cryptoCode: 'BTC', display: 'Bitcoin'},
|
||||||
{cryptoCode: 'ETH', display: 'Ethereum'}
|
{cryptoCode: 'ETH', display: 'Ethereum'},
|
||||||
|
{cryptoCode: 'ZEC', display: 'Zcash'}
|
||||||
]
|
]
|
||||||
|
|
||||||
module.exports = {coins, cryptoDisplays, buildUrl}
|
module.exports = {coins, cryptoDisplays, buildUrl, unitScale}
|
||||||
|
|
||||||
function buildUrl (cryptoCode, address) {
|
function buildUrl (cryptoCode, address) {
|
||||||
switch (cryptoCode) {
|
switch (cryptoCode) {
|
||||||
case 'BTC': return `bitcoin:${address}`
|
case 'BTC': return `bitcoin:${address}`
|
||||||
case 'ETH': return `ethereum:${address}`
|
case 'ETH': return `ethereum:${address}`
|
||||||
|
case 'ZEC': return `zcash:${address}`
|
||||||
default: throw new Error(`Unsupported crypto: ${cryptoCode}`)
|
default: throw new Error(`Unsupported crypto: ${cryptoCode}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function unitScale (cryptoCode) {
|
||||||
|
const scaleRec = coins[cryptoCode]
|
||||||
|
if (!scaleRec) throw new Error(`Unsupported crypto: ${cryptoCode}`)
|
||||||
|
return scaleRec.unitScale
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,27 @@
|
||||||
var BigNumber = require('bignumber.js')
|
const BigNumber = require('bignumber.js')
|
||||||
|
|
||||||
var TEN = new BigNumber(10)
|
const coinUtils = require('../../coin-utils')
|
||||||
|
|
||||||
var UNIT_SCALES = {
|
const TEN = new BigNumber(10)
|
||||||
BTC: 8,
|
|
||||||
ETH: 18
|
const PAIRS = {
|
||||||
|
BTC: {
|
||||||
|
USD: 'XXBTZUSD',
|
||||||
|
EUR: 'XXBTZEUR'
|
||||||
|
},
|
||||||
|
ETH: {
|
||||||
|
USD: 'XETHZUSD',
|
||||||
|
EUR: 'XETHZEUR'
|
||||||
|
},
|
||||||
|
ZEC: {
|
||||||
|
USD: 'XZECZUSD',
|
||||||
|
EUR: 'XZECZEUR'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function unitScale (cryptoCoin) {
|
module.exports = {PAIRS, toUnit}
|
||||||
return UNIT_SCALES[cryptoCoin]
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.toUnit = function toUnit (cryptoAtoms, cryptoCoin) {
|
function toUnit (cryptoAtoms, cryptoCoin) {
|
||||||
var scale = TEN.pow(unitScale(cryptoCoin))
|
var scale = TEN.pow(coinUtils.unitScale(cryptoCoin))
|
||||||
return cryptoAtoms.div(scale)
|
return cryptoAtoms.div(scale)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,7 @@
|
||||||
const Kraken = require('kraken-api')
|
const Kraken = require('kraken-api')
|
||||||
const coinmath = require('../common/kraken')
|
const common = require('../common/kraken')
|
||||||
|
|
||||||
var PAIRS = {
|
var PAIRS = common.PAIRS
|
||||||
BTC: {
|
|
||||||
USD: 'XXBTZUSD',
|
|
||||||
EUR: 'XXBTZEUR'
|
|
||||||
},
|
|
||||||
ETH: {
|
|
||||||
USD: 'XETHZUSD',
|
|
||||||
EUR: 'XETHZEUR'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {buy, sell}
|
module.exports = {buy, sell}
|
||||||
|
|
||||||
|
|
@ -23,8 +14,8 @@ function sell (account, cryptoAtoms, fiatCode, cryptoCode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function trade (account, type, cryptoAtoms, fiatCode, cryptoCode) {
|
function trade (account, type, cryptoAtoms, fiatCode, cryptoCode) {
|
||||||
const kraken = new Kraken(account.key, account.secret)
|
const kraken = new Kraken(account.apiKey, account.privateKey)
|
||||||
const amount = coinmath.toUnit(cryptoAtoms, cryptoCode)
|
const amount = common.toUnit(cryptoAtoms, cryptoCode)
|
||||||
|
|
||||||
if (amount.lte('0.01')) {
|
if (amount.lte('0.01')) {
|
||||||
const err = new Error('Order size too small')
|
const err = new Error('Order size too small')
|
||||||
|
|
|
||||||
|
|
@ -2,20 +2,12 @@ const axios = require('axios')
|
||||||
const _ = require('lodash/fp')
|
const _ = require('lodash/fp')
|
||||||
|
|
||||||
const BN = require('../../../bn')
|
const BN = require('../../../bn')
|
||||||
|
const common = require('../../common/kraken')
|
||||||
|
|
||||||
exports.NAME = 'Kraken'
|
exports.NAME = 'Kraken'
|
||||||
exports.SUPPORTED_MODULES = ['ticker']
|
exports.SUPPORTED_MODULES = ['ticker']
|
||||||
|
|
||||||
const PAIRS = {
|
const PAIRS = common.PAIRS
|
||||||
BTC: {
|
|
||||||
USD: 'XXBTZUSD',
|
|
||||||
EUR: 'XXBTZEUR'
|
|
||||||
},
|
|
||||||
ETH: {
|
|
||||||
USD: 'XETHZUSD',
|
|
||||||
EUR: 'XETHZEUR'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function findCurrency (fxRates, fiatCode) {
|
function findCurrency (fxRates, fiatCode) {
|
||||||
const rates = _.find(_.matchesProperty('code', fiatCode), fxRates)
|
const rates = _.find(_.matchesProperty('code', fiatCode), fxRates)
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ function balance (account, cryptoCode) {
|
||||||
.then(() => {
|
.then(() => {
|
||||||
if (cryptoCode === 'BTC') return BN(1e8 * 10)
|
if (cryptoCode === 'BTC') return BN(1e8 * 10)
|
||||||
if (cryptoCode === 'ETH') return BN(1e18 * 10)
|
if (cryptoCode === 'ETH') return BN(1e18 * 10)
|
||||||
|
if (cryptoCode === 'ZEC') return BN(1e8 * 10)
|
||||||
throw new Error('Unsupported crypto: ' + cryptoCode)
|
throw new Error('Unsupported crypto: ' + cryptoCode)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -24,6 +25,7 @@ function pendingBalance (account, cryptoCode) {
|
||||||
.then(() => {
|
.then(() => {
|
||||||
if (cryptoCode === 'BTC') return BN(1e8 * 10.1)
|
if (cryptoCode === 'BTC') return BN(1e8 * 10.1)
|
||||||
if (cryptoCode === 'ETH') return BN(1e18 * 10.1)
|
if (cryptoCode === 'ETH') return BN(1e18 * 10.1)
|
||||||
|
if (cryptoCode === 'ZEC') return BN(1e8 * 10.1)
|
||||||
throw new Error('Unsupported crypto: ' + cryptoCode)
|
throw new Error('Unsupported crypto: ' + cryptoCode)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -33,16 +35,18 @@ function confirmedBalance (account, cryptoCode) {
|
||||||
.then(() => {
|
.then(() => {
|
||||||
if (cryptoCode === 'BTC') return BN(1e8 * 10)
|
if (cryptoCode === 'BTC') return BN(1e8 * 10)
|
||||||
if (cryptoCode === 'ETH') return BN(1e18 * 10)
|
if (cryptoCode === 'ETH') return BN(1e18 * 10)
|
||||||
|
if (cryptoCode === 'ZEC') return BN(1e8 * 10)
|
||||||
throw new Error('Unsupported crypto: ' + cryptoCode)
|
throw new Error('Unsupported crypto: ' + cryptoCode)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: This makes it easier to test insufficient funds errors
|
// Note: This makes it easier to test insufficient funds errors
|
||||||
let sendCount = 0
|
let sendCount = 100
|
||||||
|
|
||||||
function isInsufficient (cryptoAtoms, cryptoCode) {
|
function isInsufficient (cryptoAtoms, cryptoCode) {
|
||||||
if (cryptoCode === 'BTC') return cryptoAtoms.gt(1e5 * 10 * sendCount)
|
if (cryptoCode === 'BTC') return cryptoAtoms.gt(1e5 * 10 * sendCount)
|
||||||
if (cryptoCode === 'ETH') return cryptoAtoms.gt(1e18 * 0.25 * sendCount)
|
if (cryptoCode === 'ETH') return cryptoAtoms.gt(1e18 * 0.25 * sendCount)
|
||||||
|
if (cryptoCode === 'ZEC') return cryptoAtoms.gt(1e5 * 0.25 * sendCount)
|
||||||
throw new Error('Unsupported crypto: ' + cryptoCode)
|
throw new Error('Unsupported crypto: ' + cryptoCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
"express-ws": "^3.0.0",
|
"express-ws": "^3.0.0",
|
||||||
"got": "^7.0.0",
|
"got": "^7.0.0",
|
||||||
"helmet": "^3.6.1",
|
"helmet": "^3.6.1",
|
||||||
|
"kraken-api": "^0.1.7",
|
||||||
"lodash": "^4.17.2",
|
"lodash": "^4.17.2",
|
||||||
"mem": "^1.1.0",
|
"mem": "^1.1.0",
|
||||||
"migrate": "^0.2.2",
|
"migrate": "^0.2.2",
|
||||||
|
|
|
||||||
|
|
@ -32590,6 +32590,8 @@ var _user$project$Transaction$multiplier = function (code) {
|
||||||
return 1.0e8;
|
return 1.0e8;
|
||||||
case 'ETH':
|
case 'ETH':
|
||||||
return 1.0e18;
|
return 1.0e18;
|
||||||
|
case 'ZEC':
|
||||||
|
return 1.0e8;
|
||||||
default:
|
default:
|
||||||
return 1.0;
|
return 1.0;
|
||||||
}
|
}
|
||||||
|
|
@ -33670,8 +33672,8 @@ var _user$project$NavBar$view = F2(
|
||||||
ctor: '::',
|
ctor: '::',
|
||||||
_0: {
|
_0: {
|
||||||
ctor: '_Tuple3',
|
ctor: '_Tuple3',
|
||||||
_0: 'Twilio',
|
_0: 'Kraken',
|
||||||
_1: _user$project$CoreTypes$AccountRoute('twilio'),
|
_1: _user$project$CoreTypes$AccountRoute('kraken'),
|
||||||
_2: true
|
_2: true
|
||||||
},
|
},
|
||||||
_1: {
|
_1: {
|
||||||
|
|
@ -33682,11 +33684,20 @@ var _user$project$NavBar$view = F2(
|
||||||
_1: _user$project$CoreTypes$AccountRoute('mailjet'),
|
_1: _user$project$CoreTypes$AccountRoute('mailjet'),
|
||||||
_2: true
|
_2: true
|
||||||
},
|
},
|
||||||
|
_1: {
|
||||||
|
ctor: '::',
|
||||||
|
_0: {
|
||||||
|
ctor: '_Tuple3',
|
||||||
|
_0: 'Twilio',
|
||||||
|
_1: _user$project$CoreTypes$AccountRoute('twilio'),
|
||||||
|
_2: true
|
||||||
|
},
|
||||||
_1: {ctor: '[]'}
|
_1: {ctor: '[]'}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
_1: {
|
_1: {
|
||||||
ctor: '::',
|
ctor: '::',
|
||||||
|
|
|
||||||
22
schemas/kraken.json
Normal file
22
schemas/kraken.json
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"code": "kraken",
|
||||||
|
"display": "Kraken",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"code": "apiKey",
|
||||||
|
"display": "API Key",
|
||||||
|
"fieldType": "string",
|
||||||
|
"secret": true,
|
||||||
|
"required": true,
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "privateKey",
|
||||||
|
"display": "Private Key",
|
||||||
|
"fieldType": "password",
|
||||||
|
"secret": true,
|
||||||
|
"required": true,
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
13
yarn.lock
13
yarn.lock
|
|
@ -3108,6 +3108,13 @@ kind-of@^3.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
is-buffer "^1.1.5"
|
is-buffer "^1.1.5"
|
||||||
|
|
||||||
|
kraken-api@^0.1.7:
|
||||||
|
version "0.1.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/kraken-api/-/kraken-api-0.1.7.tgz#b752435e6917ba71d9e734a5fed3fa5961622de8"
|
||||||
|
dependencies:
|
||||||
|
querystring ">=0.2.0"
|
||||||
|
request ">=2.27.0"
|
||||||
|
|
||||||
last-line-stream@^1.0.0:
|
last-line-stream@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/last-line-stream/-/last-line-stream-1.0.0.tgz#d1b64d69f86ff24af2d04883a2ceee14520a5600"
|
resolved "https://registry.yarnpkg.com/last-line-stream/-/last-line-stream-1.0.0.tgz#d1b64d69f86ff24af2d04883a2ceee14520a5600"
|
||||||
|
|
@ -4122,6 +4129,10 @@ qs@^4.0.0:
|
||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/qs/-/qs-4.0.0.tgz#c31d9b74ec27df75e543a86c78728ed8d4623607"
|
resolved "https://registry.yarnpkg.com/qs/-/qs-4.0.0.tgz#c31d9b74ec27df75e543a86c78728ed8d4623607"
|
||||||
|
|
||||||
|
querystring@>=0.2.0:
|
||||||
|
version "0.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
|
||||||
|
|
||||||
ramda@^0.22.1:
|
ramda@^0.22.1:
|
||||||
version "0.22.1"
|
version "0.22.1"
|
||||||
resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.22.1.tgz#031da0c3df417c5b33c96234757eb37033f36a0e"
|
resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.22.1.tgz#031da0c3df417c5b33c96234757eb37033f36a0e"
|
||||||
|
|
@ -4356,7 +4367,7 @@ repeating@^2.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
is-finite "^1.0.0"
|
is-finite "^1.0.0"
|
||||||
|
|
||||||
request@2.81.x, request@^2.81.0:
|
request@2.81.x, request@>=2.27.0, request@^2.81.0:
|
||||||
version "2.81.0"
|
version "2.81.0"
|
||||||
resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0"
|
resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue