mirror of
https://github.com/alexgo-io/stacks.js.git
synced 2026-01-12 22:52:34 +08:00
feat: function to convert pox address details to a btc address
This commit is contained in:
@@ -19,21 +19,49 @@ export class InvalidAddressError extends Error {
|
||||
}
|
||||
}
|
||||
|
||||
export const BitcoinNetworkVersion = {
|
||||
mainnet: {
|
||||
P2PKH: 0x00, // 0
|
||||
P2SH: 0x05, // 5
|
||||
},
|
||||
testnet: {
|
||||
P2PKH: 0x6f, // 111
|
||||
P2SH: 0xc4, // 196
|
||||
},
|
||||
} as const;
|
||||
|
||||
export function btcAddressVersionToHashMode(btcAddressVersion: number): AddressHashMode {
|
||||
switch (btcAddressVersion) {
|
||||
case 0: // btc mainnet P2PKH
|
||||
case BitcoinNetworkVersion.mainnet.P2PKH:
|
||||
return AddressHashMode.SerializeP2PKH;
|
||||
case 111: // btc mainnet P2PKH
|
||||
case BitcoinNetworkVersion.testnet.P2PKH:
|
||||
return AddressHashMode.SerializeP2PKH;
|
||||
case 5: // btc mainnet P2SH
|
||||
case BitcoinNetworkVersion.mainnet.P2SH:
|
||||
return AddressHashMode.SerializeP2SH;
|
||||
case 196: // btc testnet P2SH
|
||||
case BitcoinNetworkVersion.testnet.P2SH:
|
||||
return AddressHashMode.SerializeP2SH;
|
||||
default:
|
||||
throw new Error('Invalid pox address version');
|
||||
}
|
||||
}
|
||||
|
||||
export function hashModeToBtcAddressVersion(
|
||||
hashMode: AddressHashMode,
|
||||
network: 'mainnet' | 'testnet'
|
||||
): number {
|
||||
if (!['mainnet', 'testnet'].includes(network)) {
|
||||
throw new Error(`Invalid network argument: ${network}`);
|
||||
}
|
||||
switch (hashMode) {
|
||||
case AddressHashMode.SerializeP2PKH:
|
||||
return BitcoinNetworkVersion[network].P2PKH;
|
||||
case AddressHashMode.SerializeP2SH:
|
||||
return BitcoinNetworkVersion[network].P2SH;
|
||||
default:
|
||||
throw new Error(`Invalid pox address hash mode: ${hashMode}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function getAddressHashMode(btcAddress: string) {
|
||||
try {
|
||||
const { version } = address.fromBase58Check(btcAddress);
|
||||
@@ -57,6 +85,22 @@ export function decodeBtcAddress(btcAddress: string) {
|
||||
};
|
||||
}
|
||||
|
||||
export function poxAddressToBtcAddress(
|
||||
version: Buffer,
|
||||
hashBytes: Buffer,
|
||||
network: 'mainnet' | 'testnet'
|
||||
) {
|
||||
if (version.byteLength !== 1) {
|
||||
throw new Error(`Invalid byte length for version buffer: ${version.toString('hex')}`);
|
||||
}
|
||||
if (hashBytes.byteLength !== 20) {
|
||||
throw new Error(`Invalid byte length for hashBytes: ${hashBytes.toString('hex')}`);
|
||||
}
|
||||
const btcNetworkVersion = hashModeToBtcAddressVersion(version[0], network);
|
||||
const btcAddress = address.toBase58Check(hashBytes, btcNetworkVersion);
|
||||
return btcAddress;
|
||||
}
|
||||
|
||||
export function getBTCAddress(version: Buffer, checksum: Buffer) {
|
||||
const btcAddress = address.toBase58Check(checksum, new BN(version).toNumber());
|
||||
return btcAddress;
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
intCV,
|
||||
} from '@stacks/transactions';
|
||||
import { address as btcAddress } from 'bitcoinjs-lib';
|
||||
import { decodeBtcAddress, getAddressHashMode, InvalidAddressError } from '../src/utils';
|
||||
import { decodeBtcAddress, getAddressHashMode, InvalidAddressError, poxAddressToBtcAddress } from '../src/utils';
|
||||
|
||||
beforeEach(() => {
|
||||
fetchMock.resetMocks();
|
||||
@@ -893,3 +893,52 @@ test('pox address hash mode', async () => {
|
||||
expect(() => decodeBtcAddress(p2wsh)).toThrowError(InvalidAddressError);
|
||||
expect(() => decodeBtcAddress(p2wshTestnet)).toThrowError(InvalidAddressError);
|
||||
})
|
||||
|
||||
|
||||
test('pox address to btc address', () => {
|
||||
const vectors: {
|
||||
version: Buffer;
|
||||
hashBytes: Buffer;
|
||||
network: 'mainnet' | 'testnet';
|
||||
expectedBtcAddr: string;
|
||||
}[] = [
|
||||
{
|
||||
version: Buffer.from([0x01]),
|
||||
hashBytes: Buffer.from('07366658d1e5f0f75c585a17b618b776f4f10a6b', 'hex'),
|
||||
network: 'mainnet',
|
||||
expectedBtcAddr: '32M9pegJxqXBoxXSKBN1s7HJUR2YMkMaFg'
|
||||
},
|
||||
{
|
||||
version: Buffer.from([0x01]),
|
||||
hashBytes: Buffer.from('9b24b88b1334b0a17a99c09470c4df06ffd3ea22', 'hex'),
|
||||
network: 'mainnet',
|
||||
expectedBtcAddr: '3FqLegt1Lo1JuhiBAQQiM5WwDdmefTo5zd',
|
||||
},
|
||||
{
|
||||
version: Buffer.from([0x00]),
|
||||
hashBytes: Buffer.from('fde9c82d7bc43f55e9054438470c3ca8d6e7237f', 'hex'),
|
||||
network: 'mainnet',
|
||||
expectedBtcAddr: '1Q9a1zGPfJ4oH5Xaz5wc7BdvWV21fSNkkr',
|
||||
},
|
||||
{
|
||||
version: Buffer.from([0x00]),
|
||||
hashBytes: Buffer.from('5dc795522f81dcb7eb774a0b8e84b612e3edc141', 'hex'),
|
||||
network: 'testnet',
|
||||
expectedBtcAddr: 'mp4pEBdJiMh6aL5Uhs6nZX1XhyZ4V2xrzg',
|
||||
},
|
||||
{
|
||||
version: Buffer.from([0x01]),
|
||||
hashBytes: Buffer.from('3149c3eba2d21cfdeea56894866b8f4cd11b72ad', 'hex'),
|
||||
network: 'testnet',
|
||||
expectedBtcAddr: '2MwjqTzEJodSaoehcxRSqfWrvJMGZHq4tdC',
|
||||
}
|
||||
];
|
||||
|
||||
vectors.forEach(item => {
|
||||
const btcAddress = poxAddressToBtcAddress(item.version, item.hashBytes, item.network);
|
||||
expect(btcAddress).toBe(item.expectedBtcAddr);
|
||||
const decodedAddress = decodeBtcAddress(btcAddress);
|
||||
expect(decodedAddress.hashMode).toBe(item.version[0]);
|
||||
expect(decodedAddress.data.toString('hex')).toBe(item.hashBytes.toString('hex'));
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user