PHP WebShell
Текущая директория: /opt/BitGoJS/modules/sdk-coin-stx/test/unit
Просмотр файла: util.ts
import assert from 'assert';
import should from 'should';
import { AddressVersion, ClarityType, IntCV, NoneCV, SomeCV, UIntCV, ListCV } from '@stacks/transactions';
import BigNum from 'bn.js';
import * as testData from './resources';
import { StxLib } from '../../src';
const { KeyPair, Utils } = StxLib;
describe('Stx util library', function () {
describe('address', function () {
it('should validate addresses', function () {
const validAddresses = [
'STB44HYPYAT2BB2QE513NSP81HTMYWBJP02HPGK6',
'ST11NJTTKGVT6D1HY4NJRVQWMQM7TVAR091EJ8P2Y',
'SP2T758K6T2YRKG9Q0TJ16B6FP5QQREWZSESRS0PY',
'ST1WVJMS5VS41F0YMH7D2M0VHXRG4CY43ZJZBS60A?memoId=4',
'SPSZBZ3W0JC2MEBN0M9PAM2QB5SH72QYEQAMN6HD?memoId=0',
'SP3BV7092K9ZS9NJ9ZYMPXE69SV6Y6072M7HEZ49E?memoId=255',
];
for (const address of validAddresses) {
Utils.isValidAddressWithPaymentId(address).should.be.true();
}
});
it('should fail to validate invalid addresses', function () {
const invalidAddresses = [
'SP244HYPYAT2BB2QE513NSP81HTMYWBJP02HPGK6',
'ST1T758K6T2YRKG9Q0TJ16B6FP5QQREWZSESRS0PY',
'ST1WVJMS5VS41F0YMH7D2M0VHXRG4CY43ZJZBS60A?memoId=NaN',
'SPSZBZ3W0JC2MEBN0M9PAM2QB5SH72QYEQAMN6HD?memoId=',
'SP3BV7092K9ZS9NJ9ZYMPXE69SV6Y6072M7HEZ49E?memoId=testing',
'',
'abc',
];
for (const address of invalidAddresses) {
should.doesNotThrow(() => Utils.isValidAddress(address));
Utils.isValidAddressWithPaymentId(address).should.be.false();
}
});
it('should generate multisig addresses from compressed public keys', function () {
const pubKeys = [
'0263e1f2f322fb74224e210f9d616fce14d10fa89520dcde3d6d02514cdb16846a',
'02d5de9e1b9c13fc7b67446ebcff4fbb9aa6b1933f907e9aabf32f48d6e0a5064d',
'0296c4b8353c4a938173f80706df480cf6f85523b428d59ee81d9effcf61e5eae8',
];
const address = Utils.getSTXAddressFromPubKeys(pubKeys);
address.address.should.equal('SM1W9PBVTZA9SRNBQJ2A05R3T0ZVYC94PD0AN9KDG');
address.hash160.should.equal('789b2f7afa939c5577909402e07a07f7e6249668');
Utils.getSTXAddressFromPubKeys(pubKeys, AddressVersion.TestnetMultiSig).address.should.equal(
'SN1W9PBVTZA9SRNBQJ2A05R3T0ZVYC94PD0A9GGMZ'
);
Utils.getSTXAddressFromPubKeys(pubKeys, AddressVersion.MainnetMultiSig).address.should.equal(
'SM1W9PBVTZA9SRNBQJ2A05R3T0ZVYC94PD0AN9KDG'
);
});
it('should generate multisig addresses from uncompressed public keys', function () {
const pubKeys = [
'049742b908579ffd225d5e1d9486471f19a101dd04b7a81d11da882e7ac7f3e042989c311524a3335e15dec9338a07bd21b6e4444b6b7744d314cc926a1f0383db',
'0464097ccbc22905ec6f678c846346294033e11a216d133abf6af252294695b3538d65f65b188b6e72e1890e7738f9e221944e618dea1178ef749717b35492de6a',
'042c608408352ab41477ad9dd1cabca9e712de2dff3c5c8bfa4b5f7f1a0f74a32402a826d2ce5f3a6b01c16aeebdd304e235791958bbf97a08b5d4e9dd4db399b7',
];
Utils.getSTXAddressFromPubKeys(pubKeys).address.should.equal('SM2TF8C003JE5YA8B43C2ZAY0K95QFVJNV86FCCQ4');
Utils.getSTXAddressFromPubKeys(pubKeys, AddressVersion.TestnetMultiSig).address.should.equal(
'SN2TF8C003JE5YA8B43C2ZAY0K95QFVJNV90P7YGS'
);
Utils.getSTXAddressFromPubKeys(pubKeys, AddressVersion.MainnetMultiSig).address.should.equal(
'SM2TF8C003JE5YA8B43C2ZAY0K95QFVJNV86FCCQ4'
);
});
it('should generate multisig addresses from compressed and uncompressed public keys', function () {
const pubKeys = [
'04d6f0f7d97a72979596a17fa2946eaeff3703250a62640271eea59477f5b19f39ad01ce2a53025eba365a4f40dd085234194d1d06aefec2a9d4439be0f3c2df34',
'02f6d0597fb6d5467203d080e17f7b4f767ead59fc303b7d7261a832cb44305bb0',
'034c80f991410082824aee4ca48147082997d44e800da9877e694f9cb64b3cb64a',
];
Utils.getSTXAddressFromPubKeys(pubKeys).address.should.equal('SME8PKRHSCB699FEK59F7T7CBB225KH1MCKM67EV');
Utils.getSTXAddressFromPubKeys(pubKeys, AddressVersion.TestnetMultiSig).address.should.equal(
'SNE8PKRHSCB699FEK59F7T7CBB225KH1MDPBVKF9'
);
Utils.getSTXAddressFromPubKeys(pubKeys, AddressVersion.MainnetMultiSig).address.should.equal(
'SME8PKRHSCB699FEK59F7T7CBB225KH1MCKM67EV'
);
});
it('should not generate multisig addresses from invalid input', function () {
assert.throws(() => Utils.getSTXAddressFromPubKeys([]), /Invalid number of public keys/);
assert.throws(() => Utils.getSTXAddressFromPubKeys(['badkey', 'badkey2']), /Invalid public key/);
assert.throws(
() =>
Utils.getSTXAddressFromPubKeys([
'02f6d0597fb6d5467203d080e17f7b4f767ead59fc303b7d7261a832cb44305bb0',
'badkey',
]),
/Invalid public key/
);
});
});
describe('amount', function () {
it('valid amount', function () {
Utils.isValidAmount('10').should.be.true();
});
it('invalid amount', function () {
Utils.isValidAmount('-10').should.be.false();
});
});
describe('private key', function () {
it('should validate proper keys', function () {
const keys = [testData.secretKey1, testData.secretKey2, testData.ACCOUNT_1.prv];
for (const key of keys) {
Utils.isValidPrivateKey(key).should.be.true();
}
});
it('should not validate invalid keys', function () {
const keys = [
'66c88648116b721bb2f394e0007f9d348ea08017b6e604de51a3a7d957d5852409',
'688648116b721bb2f394e0007f9d348ea08017b6e604de51a3a7d957d58524',
'0x66c88648116b721bb2f394e0007f9d348ea08017b6e604de51a3a7d957d58524',
'',
'bitgo-stacks',
'66c88648116b721bb2f394e0007f9d34 8ea08017b6e604de51a3a7d957d58524',
'66c88648116b721bb2f394e0007f9d3rrxx908017b6e604de51a3a7d957d58524',
];
for (const key of keys) {
Utils.isValidPrivateKey(key).should.be.false();
}
});
});
describe('public key', function () {
it('should validate proper keys', function () {
const keys = [testData.pubKey1, testData.pubKey2, testData.pubKey2Compressed];
for (const key of keys) {
Utils.isValidPublicKey(key).should.be.true();
}
});
it('should not validate invalid keys', function () {
const keys = [
'0421d6f42c97d23ec2c0dc21208a9c5edfce4e5bc7b63972e68e86e3cea6f41a94a9a7c24a1ccd83792173f475fdb590cc82f94ff615df39142766e759ce6387',
'0321d6f42c99f7d23ec 2c0dc21208a9c5edfce4e5bc7b63972e68e6e3cea6f41a',
'0aa68c2d6fdb3706b39f32d6f4225275ce062561908fd7ca540a44c92eb8594ea6db9fcfe0b390c0ead3f45c36afd682eab62eb124a63b460945fe1f7c7f8a09e2',
'',
'bitgo-stacks',
'0921d6f42c99f7d23ec2c0dc21208a9c5edfce4e5bc7b63972e68e86e3cea6f41a',
'0321d6f42c99f7d23ec2c0dc21208a9c5edfce4e5bc7b63972e68ezze3cea6f41a',
'0x0321d6f42c99f7d23ec2c0dc21208a9c5edfce4e5bc7b63972e68e86e3cea6f41a',
testData.invalidPubKey1,
testData.invalidPubKey2,
];
for (const key of keys) {
Utils.isValidPublicKey(key).should.be.false();
}
});
});
describe('transaction id', function () {
it('should validate proper ids', function () {
const txIds = [
'0x209a3e196195063b2e5195232087a71fe2329a6dc8d2fca531d48c5a7824f679',
'6a590378c059f78fb698ec0af1ff610586cb1a52ee79fdae69e56430fde08cf4',
'0e0149bc2c819f3ae40cef95ca58955c80bbc9e15f8c7c651c7b86c2214b7f02',
];
for (const txId of txIds) {
Utils.isValidTransactionId(txId).should.be.true();
}
});
it('should not validate invalid ids', function () {
const txIds = [
'',
'bitgo-stacks',
'0x209a3e196195063b2e5195232087a71fe2329a6dc8d2fca531d48c5a7824f67',
'6a590378c059f78fb698ec0af1ff610586cb52ee79fdae69e56430fde08cf4',
'1x209a3e196195063b2e5195232087a71fe2329a6dc8d2fca531d48c5a7824f679',
'6a590378c059f78fb698ec0af1ff610586cb1azz2ee79fdae69e56430fde08cf4',
'0e0149bc2c819f3ae40cef95ca58955c80bbc9e1 5f8c7c651c7b86c2214b7f02',
];
for (const txId of txIds) {
Utils.isValidTransactionId(txId).should.be.false();
}
});
});
describe('transaction memo', function () {
it('check for valid memo strings', function () {
const memoStrings = ['', 'This is a test.', 'Okay', '!!This is thirty four bytes long!!'];
for (const memo of memoStrings) {
Utils.isValidMemo(memo).should.be.true();
}
});
it('check for valid memo strings', function () {
const memoStrings = ['ꜟꜟThis is thirty four chars long!!', 'It was the best of times, it was the worst of times'];
for (const memo of memoStrings) {
Utils.isValidMemo(memo).should.be.false();
}
});
});
describe('sign and verify', function () {
const keyPair1 = new KeyPair({ prv: testData.secretKey1 });
const keyPair2 = new KeyPair({ prv: testData.secretKey2 });
it('sign a message', function () {
should.equal(Utils.signMessage(keyPair1, testData.message1), testData.expectedSignature1);
should.equal(Utils.signMessage(keyPair2, testData.message2), testData.expectedSignature2);
});
it('verify a signature', function () {
Utils.verifySignature(testData.message1, testData.expectedSignature1, keyPair1.getKeys().pub).should.be.true();
// handle compressed and uncompressed public keys properly
Utils.verifySignature(
testData.message2,
testData.expectedSignature2,
keyPair2.getKeys(false).pub
).should.be.true();
Utils.verifySignature(
testData.message2,
testData.expectedSignature2,
keyPair2.getKeys(true).pub
).should.be.true();
});
it('should not verify signatures', function () {
// empty message
assert.throws(
() => Utils.verifySignature('', testData.expectedSignature1, keyPair1.getKeys().pub),
new RegExp('Cannot verify empty messages')
);
// wrong public key
Utils.verifySignature(testData.message1, testData.expectedSignature1, keyPair2.getKeys().pub).should.be.false();
// wrong signature
Utils.verifySignature(testData.message2, testData.expectedSignature1, keyPair2.getKeys().pub).should.be.false();
});
});
describe('stringifyCv', function () {
it('Int type', function () {
const input: IntCV = { type: ClarityType.Int, value: BigInt('100000') };
Utils.stringifyCv(input).should.deepEqual({ type: 0, value: '100000' });
});
it('UInt type', function () {
const input: UIntCV = { type: ClarityType.UInt, value: BigInt('100000') };
Utils.stringifyCv(input).should.deepEqual({ type: 1, value: '100000' });
});
it('OptionalNone type', function () {
const input: NoneCV = { type: ClarityType.OptionalNone };
Utils.stringifyCv(input).should.deepEqual(input);
});
it('OptionalSome type with uint value', function () {
const input: SomeCV = {
type: ClarityType.OptionalSome,
value: { type: ClarityType.UInt, value: BigInt('100000') },
};
Utils.stringifyCv(input).should.deepEqual({ type: 10, value: { type: 1, value: '100000' } });
});
it('OptionalSome type with tuple value', function () {
const input: SomeCV = {
type: ClarityType.OptionalSome,
value: {
type: ClarityType.Tuple,
data: {
hashbytes: { type: ClarityType.Buffer, buffer: Buffer.from('some-hash') },
version: { type: ClarityType.Buffer, buffer: new BigNum(1).toBuffer() },
},
},
};
Utils.stringifyCv(input).should.deepEqual(input);
});
it('List type', function () {
const input: ListCV = { type: ClarityType.List, list: [{ type: ClarityType.UInt, value: BigInt('100000') }] };
Utils.stringifyCv(input).should.deepEqual({ type: 11, list: [{ type: 1, value: '100000' }] });
});
it('List type with empty list', function () {
const input: ListCV = { type: ClarityType.List, list: [] };
Utils.stringifyCv(input).should.deepEqual({ type: 11, list: [] });
});
});
describe('getAddressVersion', function () {
it('should succeed to for valid addresses', function () {
// Mainnet single sig
Utils.getAddressVersion('SP1DN2NGRB2R3W75ST0GAA7DBV1VEBBWYZ1D33DEQ').should.equal(22);
// Mainnet multi sig
Utils.getAddressVersion('SM468VETKA5DB15HWG2QM7Y04EFQKV44R9D6D0QC').should.equal(20);
// Testnet single sig
Utils.getAddressVersion('ST1SRCA93CE1WD8TEG28BSWBFR68J24ZTAB2FAJ0').should.equal(26);
// Testnet multi sig
Utils.getAddressVersion('SN237KBNCA2CZZ32CWMNTF74DFAYCPNJ3MNN6ANDX').should.equal(21);
// With Memo Id
Utils.getAddressVersion('SP1DN2NGRB2R3W75ST0GAA7DBV1VEBBWYZ1D33DEQ?memoId=0').should.equal(22);
Utils.getAddressVersion('SN237KBNCA2CZZ32CWMNTF74DFAYCPNJ3MNN6ANDX?memoId=255').should.equal(21);
});
});
describe('xpubToSTXPubkey', function () {
it('should succeed to convert for valid xpubs', function () {
Utils.xpubToSTXPubkey(
'xpub661MyMwAqRbcGS2HMdvANN7o8ESWqwvr5U4ry5fZdD9VHhymWyfoDQF4vzfKotXgGtJTrwrFRz7XbGFov4FqdKKo6mRYNWvMp7P23DjuJnS'
).should.equal('03f0f3581a4256797fa8478cb6b1da6588f4c4bedc80ab2601e3a1572cf57b6156');
Utils.xpubToSTXPubkey(
'xpub661MyMwAqRbcFEzr5CcpFzPG45rmPf75DTvDobN5gJimCatbHtzR53SbHzDZ1J56byKSsdc8vSujGuQpyPjb7Lsua2NfADJewPxNzL3N6Tj'
).should.equal('0262b7e86c1e36e45d451263b54a1c3d740abeab61d221d1175fc3fdad752853ab');
Utils.xpubToSTXPubkey(
'xpub661MyMwAqRbcGP1adk34VzRQJEMX25rCxjEyU9YFFWNhWNzwPoqgjLoKfnqotLwrz7kBevWbRZnqTSQrQDuJuYUQaDQ5DDPEzEXMwPS9PEf'
).should.equal('036529a0e41cfd1a9d265b74f8d0002c92c5aec10d4239000260a25cfd54e4726c');
});
});
describe('getBaseAddress', function () {
it('should return the base address', async function () {
const addressWithMemo = 'SN237KBNCA2CZZ32CWMNTF74DFAYCPNJ3MNN6ANDX?memoId=255';
const baseAddress = 'SN237KBNCA2CZZ32CWMNTF74DFAYCPNJ3MNN6ANDX';
Utils.getBaseAddress(addressWithMemo).should.equal(baseAddress);
Utils.getBaseAddress(baseAddress).should.equal(baseAddress);
});
});
describe('isSameBaseAddress', function () {
it('should validate if base address match', async function () {
const address = 'SN237KBNCA2CZZ32CWMNTF74DFAYCPNJ3MNN6ANDX?memoId=255';
const baseAddress = 'SN237KBNCA2CZZ32CWMNTF74DFAYCPNJ3MNN6ANDX';
Utils.isSameBaseAddress(address, baseAddress).should.true();
const address2 = 'SN237KBNCA2CZZ32CWMNTF74DFAYCPNJ3MNN6ANDX';
const baseAddress2 = 'SN237KBNCA2CZZ32CWMNTF74DFAYCPNJ3MNN6ANDX';
Utils.isSameBaseAddress(address2, baseAddress2).should.true();
const address3 = 'SN237KBNCA2CZZ32CWMNTF74DFAYCPNJ3MNN6ANDX?memoId=255';
const baseAddress3 = 'ST1SRCA93CE1WD8TEG28BSWBFR68J24ZTAB2FAJ0';
Utils.isSameBaseAddress(address3, baseAddress3).should.false();
const address4 = 'SN237KBNCA2CZZ32CWMNTF74DFAYCPNJ3MNN6ANDX';
const baseAddress4 = 'ST1SRCA93CE1WD8TEG28BSWBFR68J24ZTAB2FAJ0';
Utils.isSameBaseAddress(address4, baseAddress4).should.false();
const address5 = 'SN237KBNCA2CZZ32CWMNTF74DFAYCPNJ3MNN6ANDF';
const baseAddress5 = 'ST1SRCA93CE1WD8TEG28BSWBFR68J24ZTAB2FAJ0';
assert.throws(
() => Utils.isSameBaseAddress(address5, baseAddress5).should.false(),
new RegExp(`invalid address: ${address5}`)
);
});
});
});
Выполнить команду
Для локальной разработки. Не используйте в интернете!