Skip to content
This repository was archived by the owner on Jan 25, 2024. It is now read-only.

Commit 8ddc032

Browse files
src/coins.js: add getMainnet/getTestnet
These methods are useful when grouping tests
1 parent 4827e8a commit 8ddc032

File tree

3 files changed

+146
-7
lines changed

3 files changed

+146
-7
lines changed

src/coins.js

Lines changed: 105 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,56 +3,151 @@ const typeforce = require('typeforce')
33

44
const networks = require('./networks')
55

6+
/**
7+
* @param network
8+
* @returns {string} the name of the network. Returns undefined if network is not a value
9+
* of `networks`
10+
*/
11+
function getNetworkName (network) {
12+
return Object.keys(networks).find(n => networks[n] === network)
13+
}
14+
15+
/**
16+
* @param network
17+
* @returns {Object} the mainnet corresponding to a testnet
18+
*/
19+
function getMainnet (network) {
20+
switch (network) {
21+
case networks.bitcoin:
22+
case networks.testnet:
23+
return networks.bitcoin
24+
25+
case networks.bitcoincash:
26+
case networks.bitcoincashTestnet:
27+
return networks.bitcoincash
28+
29+
case networks.bitcoingold:
30+
// FIXME(https://github.com/BitGo/bitgo-utxo-lib/issues/50): define bitcoingoldTest
31+
return networks.bitcoingold
32+
33+
case networks.bitcoinsv:
34+
case networks.bitcoinsvTestnet:
35+
return networks.bitcoinsv
36+
37+
case networks.dash:
38+
case networks.dashTest:
39+
return networks.dash
40+
41+
case networks.litecoin:
42+
case networks.litecoinTest:
43+
return networks.litecoin
44+
45+
case networks.zcash:
46+
case networks.zcashTest:
47+
return networks.zcash
48+
}
49+
throw new TypeError(`invalid network`)
50+
}
51+
52+
/**
53+
* @param network
54+
* @returns {boolean} true iff network is a mainnet
55+
*/
56+
function isMainnet (network) {
57+
return getMainnet(network) === network
58+
}
59+
60+
/**
61+
* @param network
62+
* @returns {boolean} true iff network is a testnet
63+
*/
64+
function isTestnet (network) {
65+
return getMainnet(network) !== network
66+
}
67+
68+
const networksArray = Object.keys(networks).map(name => networks[name])
69+
const mainnets = networksArray.filter(isMainnet)
70+
const testnets = networksArray.filter(isTestnet)
71+
const mainnetTestnetPairs = new Map(
72+
mainnets.map(m => [m, testnets.filter(t => getMainnet(t) === m)])
73+
)
74+
75+
/**
76+
* @param network
77+
* @returns {Object|undefined} - The testnet corresponding to a mainnet.
78+
* Returns undefined if a network has no testnet.
79+
*/
80+
function getTestnet (network) {
81+
if (isTestnet(network)) {
82+
return network
83+
}
84+
const testnets = mainnetTestnetPairs.get(network)
85+
if (testnets === undefined) {
86+
throw new Error(`invalid argument`)
87+
}
88+
if (testnets.length === 0) {
89+
return
90+
}
91+
if (testnets.length === 1) {
92+
return testnets[0]
93+
}
94+
throw new Error(`more than one testnet for ${getNetworkName(network)}`)
95+
}
96+
97+
/**
98+
* @param network
99+
* @returns {boolean} true iff network bitcoin or testnet
100+
*/
6101
function isBitcoin (network) {
7-
return typeforce.value(networks.bitcoin.coin)(network.coin)
102+
return getMainnet(network) === networks.bitcoin
8103
}
9104

10105
/**
11106
* @param network
12107
* @returns {boolean} true iff network is bitcoincash or bitcoincashTestnet
13108
*/
14109
function isBitcoinCash (network) {
15-
return typeforce.value(networks.bitcoincash.coin)(network.coin)
110+
return getMainnet(network) === networks.bitcoincash
16111
}
17112

18113
/**
19114
* @param network
20115
* @returns {boolean} true iff network is bitcoingold
21116
*/
22117
function isBitcoinGold (network) {
23-
return typeforce.value(networks.bitcoingold.coin)(network.coin)
118+
return getMainnet(network) === networks.bitcoingold
24119
}
25120

26121
/**
27122
* @param network
28123
* @returns {boolean} true iff network is bitcoinsv or bitcoinsvTestnet
29124
*/
30125
function isBitcoinSV (network) {
31-
return typeforce.value(networks.bitcoinsv.coin)(network.coin)
126+
return getMainnet(network) === networks.bitcoinsv
32127
}
33128

34129
/**
35130
* @param network
36131
* @returns {boolean} true iff network is dash or dashTest
37132
*/
38133
function isDash (network) {
39-
return typeforce.value(networks.dash.coin)(network.coin)
134+
return getMainnet(network) === networks.dash
40135
}
41136

42137
/**
43138
* @param network
44139
* @returns {boolean} true iff network is litecoin or litecoinTest
45140
*/
46141
function isLitecoin (network) {
47-
return typeforce.value(networks.litecoin.coin)(network.coin)
142+
return getMainnet(network) === networks.litecoin
48143
}
49144

50145
/**
51146
* @param network
52147
* @returns {boolean} true iff network is zcash or zcashTest
53148
*/
54149
function isZcash (network) {
55-
return typeforce.value(networks.zcash.coin)(network.coin)
150+
return getMainnet(network) === networks.zcash
56151
}
57152

58153
/**
@@ -78,6 +173,8 @@ module.exports = {
78173
LTC: networks.litecoin.coin,
79174
ZEC: networks.zcash.coin,
80175

176+
getNetworkName,
177+
81178
getMainnet,
82179
isMainnet,
83180
getTestnet,
@@ -96,4 +193,5 @@ module.exports = {
96193
* @deprecated: use isValidNetwork
97194
*/
98195
isValidCoin: isValidNetwork
196+
99197
}

src/networks.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ module.exports = {
153153
messagePrefix: '\x19Litecoin Signed Message:\n',
154154
bech32: 'ltc',
155155
bip32: {
156+
// FIXME(BG-16466): these are incorrect
156157
public: 0x019da462,
157158
private: 0x019d9cfe
158159
},
@@ -165,6 +166,7 @@ module.exports = {
165166
messagePrefix: '\x19Litecoin Signed Message:\n',
166167
bech32: 'tltc',
167168
bip32: {
169+
// FIXME(BG-16466): these are incorrect
168170
public: 0x0488b21e,
169171
private: 0x0488ade4
170172
},

test/networks.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,26 @@ describe('networks', function () {
7171
assert(coins.isValidNetwork(network))
7272
})
7373

74+
it('getNetworkName() returns network name', function () {
75+
assert.strictEqual(name, coins.getNetworkName(network))
76+
})
77+
78+
it('has corresponding testnet/mainnet', function () {
79+
if (coins.isMainnet(network)) {
80+
assert.strictEqual(coins.isTestnet(network), false)
81+
assert.strictEqual(coins.getMainnet(network), network)
82+
assert.strictEqual(
83+
typeof coins.getTestnet(network),
84+
(network === networks.bitcoingold) ? 'undefined' : 'object'
85+
)
86+
} else {
87+
assert.strictEqual(coins.isMainnet(network), false)
88+
assert.strictEqual(coins.getTestnet(network), network)
89+
assert.notStrictEqual(coins.getMainnet(network), network)
90+
assert.strictEqual(typeof coins.getMainnet(network), 'object')
91+
}
92+
})
93+
7494
it('has expected properties', function () {
7595
assert.strictEqual(typeof network, 'object')
7696
assert.strictEqual(typeof network.messagePrefix, 'string')
@@ -80,6 +100,25 @@ describe('networks', function () {
80100
assert.strictEqual(typeof network.scriptHash, 'number')
81101
assert.strictEqual(typeof network.wif, 'number')
82102
assert.strictEqual(typeof network.coin, 'string')
103+
104+
// FIXME(BG-16466): litecoin should not be a special case here -- all forks have the same bip32 values
105+
const isLitecoin = coins.getMainnet(network) === networks.litecoin
106+
107+
if (coins.isMainnet(network)) {
108+
assert.strictEqual(
109+
(network.bip32.public === networks.bitcoin.bip32.public), !isLitecoin
110+
)
111+
assert.strictEqual(
112+
(network.bip32.private === networks.bitcoin.bip32.private), !isLitecoin
113+
)
114+
} else {
115+
assert.strictEqual(
116+
(network.bip32.public === networks.testnet.bip32.public), !isLitecoin
117+
)
118+
assert.strictEqual(
119+
(network.bip32.private === networks.testnet.bip32.private), !isLitecoin
120+
)
121+
}
83122
})
84123

85124
for (const otherName in networks) {

0 commit comments

Comments
 (0)