File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -21,8 +21,10 @@ import {
2121 deserializeTransaction ,
2222 PubKeyEncoding ,
2323 publicKeyFromSignature ,
24+ serializeCV ,
2425 signWithKey ,
2526 StacksTransaction ,
27+ standardPrincipalCV ,
2628 TransactionVersion ,
2729 validateStacksAddress ,
2830} from '@stacks/transactions' ;
@@ -505,6 +507,33 @@ export function getAddressVersion(address: string): AddressVersion {
505507 return createAddress ( baseAddress ) . version ;
506508}
507509
510+ /**
511+ * Encode a Stacks *standard* principal as the Clarity SIP-005 hex wire format
512+ * — a 22-byte blob:
513+ *
514+ * `0x05` || version (1 byte) || hash160 (20 bytes)
515+ *
516+ * Contract principals (`<address>.<contract-name>`) and addresses with a
517+ * `?memoId=…` suffix are rejected. The Clarity type byte (`0x05`) is set
518+ * by `serializeCV` from `@stacks/transactions`, so this helper does not
519+ * hand-roll any byte concatenation.
520+ *
521+ * @param {string } principal a Stacks standard principal (e.g. `SP…` / `ST…`)
522+ * @returns {string } hex-encoded 22-byte Clarity standard principal
523+ */
524+ export function getEncodedPrincipal ( principal : string ) : string {
525+ if ( principal . includes ( '?' ) ) {
526+ throw new UtilsError ( `principal must not include a query string: ${ principal } ` ) ;
527+ }
528+ if ( principal . includes ( '.' ) ) {
529+ throw new UtilsError ( `contract principals are not supported, expected a standard principal: ${ principal } ` ) ;
530+ }
531+ if ( ! isValidAddress ( principal ) ) {
532+ throw new UtilsError ( `invalid Stacks address in principal: ${ principal } ` ) ;
533+ }
534+ return serializeCV ( standardPrincipalCV ( principal ) ) . toString ( 'hex' ) ;
535+ }
536+
508537/**
509538 * Returns a STX pub key from an xpub
510539 *
Original file line number Diff line number Diff line change @@ -323,6 +323,32 @@ describe('Stx util library', function () {
323323 } ) ;
324324 } ) ;
325325
326+ describe ( 'getEncodedPrincipal' , function ( ) {
327+ it ( 'should encode a testnet standard principal as the 22-byte Clarity blob' , function ( ) {
328+ Utils . getEncodedPrincipal ( 'ST390D0WBF60T25P36KMCP6WN1BXQ7TTMMQKNV15C' ) . should . equal (
329+ '051ad206838b7981a116c334e8cb1b950afb73eb54a5'
330+ ) ;
331+ } ) ;
332+
333+ it ( 'should reject contract principals' , function ( ) {
334+ should . throws (
335+ ( ) => Utils . getEncodedPrincipal ( 'ST390D0WBF60T25P36KMCP6WN1BXQ7TTMMQKNV15C.my-contract' ) ,
336+ / c o n t r a c t p r i n c i p a l s a r e n o t s u p p o r t e d /
337+ ) ;
338+ } ) ;
339+
340+ it ( 'should reject addresses with a memoId suffix' , function ( ) {
341+ should . throws (
342+ ( ) => Utils . getEncodedPrincipal ( 'ST390D0WBF60T25P36KMCP6WN1BXQ7TTMMQKNV15C?memoId=0' ) ,
343+ / m u s t n o t i n c l u d e a q u e r y s t r i n g /
344+ ) ;
345+ } ) ;
346+
347+ it ( 'should reject invalid addresses' , function ( ) {
348+ should . throws ( ( ) => Utils . getEncodedPrincipal ( 'not-a-stacks-address' ) , / i n v a l i d S t a c k s a d d r e s s / ) ;
349+ } ) ;
350+ } ) ;
351+
326352 describe ( 'xpubToSTXPubkey' , function ( ) {
327353 it ( 'should succeed to convert for valid xpubs' , function ( ) {
328354 Utils . xpubToSTXPubkey (
You can’t perform that action at this time.
0 commit comments