zcash-grant-system/blockchain/src/util.spec.ts

197 lines
6.4 KiB
TypeScript

import 'mocha';
import assert from 'assert';
import bitcore from 'zcash-bitcore-lib';
import * as util from './util';
describe('util', () => {
describe('generateApiKey', () => {
it('Should generate a a secrey key and hash', () => {
const key = util.generateApiKey();
assert.ok(key.hash);
assert.ok(key.key);
});
it('Should generate a random API key', () => {
const key1 = util.generateApiKey();
const key2 = util.generateApiKey();
assert.notEqual(key1.hash, key2.hash);
assert.notEqual(key1.key, key2.key);
});
});
describe('authenticate', () => {
const key = util.generateApiKey();
let oldHash: any;
before(() => {
oldHash = process.env.API_SECRET_HASH;
process.env.API_SECRET_HASH = key.hash;
});
it('Should authenticate a key generated from generateApiKey', () => {
assert.ok(util.authenticate(key.key));
});
after(() => {
process.env.API_SECRET_HASH = oldHash;
});
});
// Keys and values taken from https://iancoleman.io/bip39/
describe('deriveTransparentAddress', () => {
const xpub = 'xpub6DKCpzYonPtjhfL9Gc6cJRxqtX3pvw3ACLguiZByfS1vic1EqgHPRBu7inUvoNxBT1m6BNuU5uUSSo5X3Zzi5mbrByBBQwhvNmmi8HErHt6';
const addresses = {
mainnet: {
0: 't1MZtRMbCE6uJTbVot6XczUKNvG5iRgcf8d',
999: 't1aCsQns9UuRZzdXp71gFTpcMomyFfpWE1W',
},
testnet: {
0: 'tmDQdkC5bcmQobqhFYpqMr8z8XFAXragbZ6',
999: 'tmS3cjdMYsZw58sjFmjyzKVH7Qm458gbea7',
},
};
let oldXPub: any;
before(() => {
oldXPub = process.env.BIP32_XPUB;
process.env.BIP32_XPUB = xpub;
});
it('Should generate the correct address for mainnet m/0/0', () => {
const addr = util.deriveTransparentAddress(0, bitcore.Networks.mainnet);
assert.equal(addr, addresses.mainnet[0]);
});
it('Should generate the correct address for index m/0/999', () => {
const addr = util.deriveTransparentAddress(999, bitcore.Networks.mainnet);
assert.equal(addr, addresses.mainnet[999]);
});
it('Should generate the correct address for testnet m/0/0', () => {
const addr = util.deriveTransparentAddress(0, bitcore.Networks.testnet);
assert.equal(addr, addresses.testnet[0]);
});
it('Should generate the correct address for testnet index m/0/999', () => {
const addr = util.deriveTransparentAddress(999, bitcore.Networks.testnet);
assert.equal(addr, addresses.testnet[999]);
});
it('Should throw on numbers greater than or equal to 2^31', () => {
assert.ok(util.deriveTransparentAddress(Math.pow(2, 31) - 1, bitcore.Networks.mainnet));
assert.throws(() => {
util.deriveTransparentAddress(Math.pow(2, 31), bitcore.Networks.mainnet);
});
});
it('Should throw on numbers less than 0', () => {
assert.throws(() => {
util.deriveTransparentAddress(-1, bitcore.Networks.mainnet);
});
});
after(() => {
process.env.BIP32_XPUB = oldXPub;
});
});
describe('dedupeArray', () => {
it('Should remove duplicates', () => {
const numArray = [1, 2, 3, 3];
assert.deepEqual(util.dedupeArray(numArray), [1, 2, 3]);
const stringArray = ['two', 'one', 'two', 'three'];
assert.deepEqual(util.dedupeArray(stringArray), ['two', 'one', 'three']);
const one = { 1: 'one' };
const two = { 2: 'two' };
const three = { 3: 'three' };
const objArray = [one, two, three, one];
assert.deepEqual(util.dedupeArray(objArray), [one, two, three]);
});
it('Should leave non-duplicate arrays unchanged', () => {
const arr = ['one', 'two', 'three'];
assert.deepEqual(util.dedupeArray(arr), arr);
});
it('Should deduplicate by reference, not deep equality', () => {
const testObj = { test: 'test' };
const arr = [testObj, { ...testObj }, testObj];
assert.equal(util.dedupeArray(arr).length, 2);
});
});
describe('removeItem', () => {
it('Should remove all instances of an item', () => {
const numArray = [1, 2, 3, 3];
assert.deepEqual(util.removeItem(numArray, 2), [1, 3, 3]);
const stringArray = ['two', 'one', 'two', 'three'];
assert.deepEqual(util.removeItem(stringArray, 'two'), ['one', 'three']);
const one = { 1: 'one' };
const two = { 2: 'two' };
const three = { 3: 'three' };
const objArray = [one, two, three, one];
assert.deepEqual(util.removeItem(objArray, three), [one, two, one]);
});
it('Should remove by reference, not deep equality', () => {
const testObj = { test: 'test' };
const arr = [testObj, { ...testObj }, testObj];
assert.equal(util.removeItem(arr, testObj).length, 1);
});
});
describe('encodeHexMemo & decodeHexMemo', () => {
const memo = 'hello tester!';
const hex = '68656c6c6f2074657374657221';
it('encodeHexMemo should encode a memo string as hex', () => {
const thisHex = util.encodeHexMemo(memo);
assert.equal(thisHex, hex);
});
it('decodeHexMemo should decode a hex memo to a string', () => {
const thisMemo = util.decodeHexMemo(hex);
assert.equal(thisMemo, memo);
});
it('encodeHexMemo and decodeHexMemo should be compatible', () => {
assert.equal(util.decodeHexMemo(util.encodeHexMemo(memo)), memo);
assert.equal(util.encodeHexMemo(util.decodeHexMemo(hex)), hex);
});
});
describe('makeContributionMemo & getContributionIdFromMemo', () => {
const cid = 123;
const hex = '436f6e747269627574696f6e20313233206f6e204772616e742e696f';
it('makeContributionMemo should make an encoded memo in the right format', () => {
assert.equal(util.makeContributionMemo(cid), hex);
});
it('getContributionIdFromMemo should get the contribution ID from a hex memo', () => {
assert.equal(util.getContributionIdFromMemo(hex), cid);
});
it('getContributionIdFromMemo should handle zero-padded hex', () => {
assert.equal(util.getContributionIdFromMemo(hex.padEnd(512, '0')), cid);
});
it('Both methods should be compatible', () => {
assert.equal(util.getContributionIdFromMemo(util.makeContributionMemo(cid)), cid);
});
});
describe('toBaseUnit', () => {
it('Should convert 20 ZEC to 2000000000 Zat', () => {
assert.equal(util.toBaseUnit(20), 2000000000);
});
it('Should convert 0.00005 ZEC to 5000 Zat', () => {
assert.equal(util.toBaseUnit(0.00005), 5000);
});
});
});