mirror of
https://github.com/Permissionless-Software-Foundation/bch-js.git
synced 2026-09-21 16:51:59 -07:00
325 lines
11 KiB
JavaScript
325 lines
11 KiB
JavaScript
// Public npm libraries
|
|
import assert from 'assert'
|
|
|
|
// Mocks
|
|
import { createRequire } from 'module'
|
|
|
|
// Unit under test (uut)
|
|
import BCHJS from '../../src/bch-js.js'
|
|
const require = createRequire(import.meta.url)
|
|
const fixtures = require('./fixtures/bitcoincash.json')
|
|
// const bchjs = new BCHJS()
|
|
let bchjs
|
|
|
|
// TODO
|
|
// 1. generate testnet p2sh
|
|
// 2. generate cashaddr mainnet p2sh
|
|
// 3. generate cashaddr testnet p2sh
|
|
// 4. create bchjs fromBase58 method
|
|
// * confirm xpub cannot generate WIF
|
|
// * confirm xpriv can generate WIF
|
|
// 5. create fromXPriv method w/ tests and docs
|
|
// 1. mainnet
|
|
// * confirm xpriv generates address
|
|
// * confirm xpriv generates WIF
|
|
// 2. testnet
|
|
// * confirm xpriv generates address
|
|
// * confirm xpriv generates WIF
|
|
// 6. More error test cases.
|
|
|
|
describe('#BitcoinCash', () => {
|
|
beforeEach(() => {
|
|
bchjs = new BCHJS()
|
|
})
|
|
|
|
describe('price conversion', () => {
|
|
it('should exercise toBitcoinCash', () => {
|
|
fixtures.conversion.toBCH.satoshis.forEach(satoshi => {
|
|
it(`should convert ${satoshi[0]} Satoshis to ${satoshi[1]} $BCH`, () => {
|
|
assert.equal(bchjs.BitcoinCash.toBitcoinCash(satoshi[0]), satoshi[1])
|
|
})
|
|
})
|
|
|
|
fixtures.conversion.toBCH.strings.forEach(satoshi => {
|
|
it(`should convert "${satoshi[0]}" Satoshis as a string to ${satoshi[1]} $BCH`, () => {
|
|
assert.equal(bchjs.BitcoinCash.toBitcoinCash(satoshi[0]), satoshi[1])
|
|
})
|
|
})
|
|
|
|
fixtures.conversion.toBCH.not.forEach(bch => {
|
|
it(`converts ${bch[0]} to Bitcoin Cash, not to ${bch[1]} Satoshi`, () => {
|
|
assert.notEqual(bchjs.BitcoinCash.toBitcoinCash(bch[0]), bch[1])
|
|
})
|
|
})
|
|
|
|
fixtures.conversion.toBCH.rounding.forEach(satoshi => {
|
|
it(`rounding ${satoshi[0]} to ${satoshi[1]} $BCH`, () => {
|
|
assert.equal(bchjs.BitcoinCash.toBitcoinCash(satoshi[0]), satoshi[1])
|
|
})
|
|
})
|
|
})
|
|
|
|
it('should exercise toSatoshi', () => {
|
|
fixtures.conversion.toSatoshi.bch.forEach(bch => {
|
|
it(`should convert ${bch[0]} $BCH to ${bch[1]} Satoshis`, () => {
|
|
assert.equal(bchjs.BitcoinCash.toSatoshi(bch[0]), bch[1])
|
|
})
|
|
})
|
|
|
|
fixtures.conversion.toSatoshi.strings.forEach(bch => {
|
|
it(`should convert "${bch[0]}" $BCH as a string to ${bch[1]} Satoshis`, () => {
|
|
assert.equal(bchjs.BitcoinCash.toSatoshi(bch[0]), bch[1])
|
|
})
|
|
})
|
|
|
|
fixtures.conversion.toSatoshi.not.forEach(satoshi => {
|
|
it(`converts ${satoshi[0]} to Satoshi, not to ${satoshi[1]} Bitcoin Cash`, () => {
|
|
assert.notEqual(bchjs.BitcoinCash.toSatoshi(satoshi[0]), satoshi[1])
|
|
})
|
|
})
|
|
|
|
fixtures.conversion.toSatoshi.rounding.forEach(bch => {
|
|
it(`rounding ${bch[0]} to ${bch[1]} Satoshi`, () => {
|
|
assert.equal(bchjs.BitcoinCash.toSatoshi(bch[0]), bch[1])
|
|
})
|
|
})
|
|
})
|
|
|
|
it('should exercise satsToBits', () => {
|
|
fixtures.conversion.satsToBits.bch.forEach(bch => {
|
|
it(`should convert ${bch[0]} BCH to ${bch[1]} bits`, () => {
|
|
assert.equal(
|
|
bchjs.BitcoinCash.satsToBits(bchjs.BitcoinCash.toSatoshi(bch[0])),
|
|
bch[1]
|
|
)
|
|
})
|
|
})
|
|
|
|
fixtures.conversion.satsToBits.strings.forEach(bch => {
|
|
it(`should convert "${bch[0]}" BCH as a string to ${bch[1]} bits`, () => {
|
|
assert.equal(
|
|
bchjs.BitcoinCash.satsToBits(bchjs.BitcoinCash.toSatoshi(bch[0])),
|
|
bch[1]
|
|
)
|
|
})
|
|
})
|
|
})
|
|
//
|
|
// describe('#satsFromBits', () => {
|
|
// fixtures.conversion.satsFromBits.bch.forEach((bch) => {
|
|
// it(`should convert ${bch[1]} bits to ${bch[0]} satoshis`, () => {
|
|
// assert.equal(bchjs.BitcoinCash.satsFromBits(bch[1]), bch[0]);
|
|
// });
|
|
// });
|
|
//
|
|
// fixtures.conversion.satsFromBits.strings.forEach((bch) => {
|
|
// it(`should convert "${bch[1]}" bits as a string to ${bch[0]} satoshis`, () => {
|
|
// assert.equal(bchjs.BitcoinCash.satsFromBits(bch[1]), bch[0]);
|
|
// });
|
|
// });
|
|
// });
|
|
})
|
|
|
|
describe('sign and verify messages', () => {
|
|
it('should exercise signMessageWithPrivKey', () => {
|
|
fixtures.signatures.sign.forEach(sign => {
|
|
it(`should sign a message w/ ${sign.network} ${sign.privateKeyWIF}`, () => {
|
|
const privateKeyWIF = sign.privateKeyWIF
|
|
const message = sign.message
|
|
const signature = bchjs.BitcoinCash.signMessageWithPrivKey(
|
|
privateKeyWIF,
|
|
message
|
|
)
|
|
assert.equal(signature, sign.signature)
|
|
})
|
|
})
|
|
})
|
|
|
|
it('shoudl exercise verifyMessage', () => {
|
|
fixtures.signatures.verify.forEach(sign => {
|
|
it(`should verify a valid signed message from ${sign.network} cashaddr address ${sign.address}`, () => {
|
|
assert.equal(
|
|
bchjs.BitcoinCash.verifyMessage(
|
|
sign.address,
|
|
sign.signature,
|
|
sign.message
|
|
),
|
|
true
|
|
)
|
|
})
|
|
})
|
|
|
|
it('should verify legacy addresses', () => {
|
|
fixtures.signatures.verify.forEach(sign => {
|
|
const legacyAddress = bchjs.Address.toLegacyAddress(sign.address)
|
|
it(`should verify a valid signed message from ${sign.network} legacy address ${legacyAddress}`, () => {
|
|
assert.equal(
|
|
bchjs.BitcoinCash.verifyMessage(
|
|
legacyAddress,
|
|
sign.signature,
|
|
sign.message
|
|
),
|
|
true
|
|
)
|
|
})
|
|
})
|
|
})
|
|
|
|
fixtures.signatures.verify.forEach(sign => {
|
|
// const legacyAddress = bchjs.Address.toLegacyAddress(sign.address)
|
|
it(`should not verify an invalid signed message from ${sign.network} cashaddr address ${sign.address}`, () => {
|
|
assert.equal(
|
|
bchjs.BitcoinCash.verifyMessage(
|
|
sign.address,
|
|
sign.signature,
|
|
'nope'
|
|
),
|
|
false
|
|
)
|
|
})
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('encode and decode to base58Check', () => {
|
|
describe('#encodeBase58Check', () => {
|
|
fixtures.encodeBase58Check.forEach((base58Check, i) => {
|
|
it(`encode ${base58Check.hex} as base58Check ${base58Check.base58Check}`, () => {
|
|
assert.equal(
|
|
bchjs.BitcoinCash.encodeBase58Check(base58Check.hex),
|
|
base58Check.base58Check
|
|
)
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('#decodeBase58Check', () => {
|
|
fixtures.encodeBase58Check.forEach((base58Check, i) => {
|
|
it(`decode ${base58Check.base58Check} as ${base58Check.hex}`, () => {
|
|
assert.equal(
|
|
bchjs.BitcoinCash.decodeBase58Check(base58Check.base58Check),
|
|
base58Check.hex
|
|
)
|
|
})
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('encode and decode BIP21 urls', () => {
|
|
describe('#encodeBIP21', () => {
|
|
fixtures.bip21.valid.forEach((bip21, i) => {
|
|
it(`encode ${bip21.address} as url`, () => {
|
|
const url = bchjs.BitcoinCash.encodeBIP21(
|
|
bip21.address,
|
|
bip21.options
|
|
)
|
|
assert.equal(url, bip21.url)
|
|
})
|
|
})
|
|
fixtures.bip21.valid_regtest.forEach((bip21, i) => {
|
|
it(`encode ${bip21.address} as url`, () => {
|
|
const url = bchjs.BitcoinCash.encodeBIP21(
|
|
bip21.address,
|
|
bip21.options,
|
|
true
|
|
)
|
|
assert.equal(url, bip21.url)
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('#decodeBIP21', () => {
|
|
fixtures.bip21.valid.forEach((bip21, i) => {
|
|
it(`decodes ${bip21.url}`, () => {
|
|
const decoded = bchjs.BitcoinCash.decodeBIP21(bip21.url)
|
|
assert.equal(decoded.options.amount, bip21.options.amount)
|
|
assert.equal(decoded.options.label, bip21.options.label)
|
|
assert.equal(
|
|
bchjs.Address.toCashAddress(decoded.address),
|
|
bchjs.Address.toCashAddress(bip21.address)
|
|
)
|
|
})
|
|
})
|
|
// fixtures.bip21.valid_regtest.forEach((bip21, i) => {
|
|
// it(`decodes ${bip21.url}`, () => {
|
|
// const decoded = bchjs.BitcoinCash.decodeBIP21(bip21.url)
|
|
// assert.equal(decoded.options.amount, bip21.options.amount)
|
|
// assert.equal(decoded.options.label, bip21.options.label)
|
|
// assert.equal(
|
|
// bchjs.Address.toCashAddress(decoded.address, true, true),
|
|
// bchjs.Address.toCashAddress(bip21.address, true, true)
|
|
// )
|
|
// })
|
|
// })
|
|
})
|
|
})
|
|
|
|
describe('#getByteCount', () => {
|
|
fixtures.getByteCount.forEach(fixture => {
|
|
it('get byte count', () => {
|
|
const byteCount = bchjs.BitcoinCash.getByteCount(
|
|
fixture.inputs,
|
|
fixture.outputs
|
|
)
|
|
assert.equal(byteCount, fixture.byteCount)
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('#bip38', function () {
|
|
// Increase timeout for BIP38 tests as they use CPU-intensive scrypt operations
|
|
// Each encrypt/decrypt operation takes ~5-6 seconds in Node.js v22
|
|
this.timeout(60000)
|
|
|
|
describe('#encryptBIP38', () => {
|
|
fixtures.bip38.encrypt.mainnet.forEach(fixture => {
|
|
it(`BIP 38 encrypt wif ${fixture.wif} with password ${fixture.password} on mainnet`, function () {
|
|
this.timeout(60000)
|
|
const encryptedKey = bchjs.BitcoinCash.encryptBIP38(
|
|
fixture.wif,
|
|
fixture.password
|
|
)
|
|
assert.equal(encryptedKey, fixture.encryptedKey)
|
|
})
|
|
})
|
|
|
|
// fixtures.bip38.encrypt.testnet.forEach(fixture => {
|
|
// it(`BIP 38 encrypt wif ${fixture.wif} with password ${fixture.password} on testnet`, function () {
|
|
// this.timeout(60000)
|
|
// const encryptedKey = bchjs.BitcoinCash.encryptBIP38(
|
|
// fixture.wif,
|
|
// fixture.password
|
|
// )
|
|
// assert.equal(encryptedKey, fixture.encryptedKey)
|
|
// })
|
|
// })
|
|
})
|
|
|
|
describe('#decryptBIP38', () => {
|
|
fixtures.bip38.decrypt.mainnet.forEach(fixture => {
|
|
it(`BIP 38 decrypt encrypted key ${fixture.encryptedKey} on mainnet`, function () {
|
|
this.timeout(60000)
|
|
const wif = bchjs.BitcoinCash.decryptBIP38(
|
|
fixture.encryptedKey,
|
|
fixture.password,
|
|
'mainnet'
|
|
)
|
|
assert.equal(wif, fixture.wif)
|
|
})
|
|
})
|
|
|
|
// fixtures.bip38.decrypt.testnet.forEach(fixture => {
|
|
// it(`BIP 38 decrypt encrypted key ${fixture.encryptedKey} on testnet`, function () {
|
|
// this.timeout(60000)
|
|
// const wif = bchjs.BitcoinCash.decryptBIP38(
|
|
// fixture.encryptedKey,
|
|
// fixture.password,
|
|
// 'testnet'
|
|
// )
|
|
// assert.equal(wif, fixture.wif)
|
|
// })
|
|
// })
|
|
})
|
|
})
|
|
})
|