import { InvalidAddressError } from "bchaddrjs" ; import bs58check from "bs58check" ; import cashaddr , { ValidationError } from "cashaddrjs" ; enum Format { Legacy = "legacy" , Bitpay = "bitpay" , Cashaddr = "cashaddr" } enum Network { Mainnet = "mainnet" , Testnet = "testnet" } enum Type { P2PKH = "p2pkh" , P2SH = "p2sh" } const VERSION_BYTE = { [ Format . Legacy ] : { [ Network . Mainnet ] : { [ Type . P2PKH ] : 0 , [ Type . P2SH ] : 5 , } , [ Network . Testnet ] : { [ Type . P2PKH ] : 111 , [ Type . P2SH ] : 196 , } , } , [ Format . Bitpay ] : { [ Network . Mainnet ] : { [ Type . P2PKH ] : 28 , [ Type . P2SH ] : 40 , } , [ Network . Testnet ] : { [ Type . P2PKH ] : 111 , [ Type . P2SH ] : 196 , } , } , } ; const BASE_58_CHECK_PAYLOAD_LENGTH = 21 ; const decodeBase58Address = ( address ) => { try { const payload = bs58check . decode ( address ) ; if ( payload . length !== BASE_58_CHECK_PAYLOAD_LENGTH ) { throw new InvalidAddressError ( ) ; } const versionByte = payload [ 0 ] ; const hash = Array . prototype . slice . call ( payload , 1 ) ; switch ( versionByte ) { case VERSION_BYTE [ Format . Legacy ] [ Network . Mainnet ] [ Type . P2PKH ] : return { hash : hash , format : Format . Legacy , network : Network . Mainnet , type : Type . P2PKH , } ; case VERSION_BYTE [ Format . Legacy ] [ Network . Mainnet ] [ Type . P2SH ] : return { hash : hash , format : Format . Legacy , network : Network . Mainnet , type : Type . P2SH , } ; case VERSION_BYTE [ Format . Legacy ] [ Network . Testnet ] [ Type . P2PKH ] : return { hash : hash , format : Format . Legacy , network : Network . Testnet , type : Type . P2PKH , } ; case VERSION_BYTE [ Format . Legacy ] [ Network . Testnet ] [ Type . P2SH ] : return { hash : hash , format : Format . Legacy , network : Network . Testnet , type : Type . P2SH , } ; case VERSION_BYTE [ Format . Bitpay ] [ Network . Mainnet ] [ Type . P2PKH ] : return { hash : hash , format : Format . Bitpay , network : Network . Mainnet , type : Type . P2PKH , } ; case VERSION_BYTE [ Format . Bitpay ] [ Network . Mainnet ] [ Type . P2SH ] : return { hash : hash , format : Format . Bitpay , network : Network . Mainnet , type : Type . P2SH , } ; } } catch ( error ) { } throw new InvalidAddressError ( ) ; } ; const decodeCashAddressWithPrefix = ( address ) => { try { const decoded = cashaddr . decode ( address ) ; const hash = Array . prototype . slice . call ( decoded . hash , 0 ) ; const type = decoded . type === "P2PKH" ? Type . P2PKH : Type . P2SH ; switch ( decoded . prefix ) { case "bitcoincash" : return { hash : hash , format : Format . Cashaddr , network : Network . Mainnet , type : type , } ; case "bchtest" : case "bchreg" : return { hash : hash , format : Format . Cashaddr , network : Network . Testnet , type : type , } ; } } catch ( error ) { } throw new InvalidAddressError ( ) ; } ; const decodeCashAddress = ( address ) => { if ( address . indexOf ( ":" ) !== - 1 ) { try { return decodeCashAddressWithPrefix ( address ) ; } catch ( error ) { } } else { const prefixes = [ "bitcoincash" , "bchtest" , "bchreg" ] ; for ( let i = 0 ; i < prefixes . length ; ++ i ) { try { const prefix = prefixes [ i ] ; return decodeCashAddressWithPrefix ( prefix + ":" + address ) ; } catch ( error ) { } } } throw new InvalidAddressError ( ) ; } ; const getTypeBits = ( type ) => { switch ( type . toLowerCase ( ) ) { case Type . P2PKH : return 0 ; case Type . P2SH : return 8 ; default : throw new ValidationError ( "Invalid type: " + type + "." ) ; } } ; export const decodeBitcoinCashAddress = ( address ) : Buffer => { try { return Buffer . from ( decodeBase58Address ( address ) . hash ) ; } catch ( error ) { } try { const { hash , type } = decodeCashAddress ( address ) ; return Buffer . concat ( [ Buffer . from ( [ getTypeBits ( type ) ] ) , Buffer . from ( hash ) , ] ) ; } catch ( error ) { } throw new InvalidAddressError ( ) ; } ;