@@ -2,6 +2,7 @@ import type {
22 Account as AccountType ,
33 BigUintCompat ,
44 bytes ,
5+ NTuple ,
56 StringCompat ,
67 uint64 ,
78 Uint64Compat ,
@@ -127,14 +128,14 @@ export class UFixedNxMImpl<N extends BitSize, M extends number> extends UFixedNx
127128 private precision : M
128129 typeInfo : TypeInfo
129130
130- constructor ( typeInfo : TypeInfo | string , v : `${number } .${number } `) {
131+ constructor ( typeInfo : TypeInfo | string , v ? : `${number } .${number } `) {
131132 super ( v )
132133 this . typeInfo = typeof typeInfo === 'string' ? JSON . parse ( typeInfo ) : typeInfo
133134 const genericArgs = this . typeInfo . genericArgs as uFixedNxMGenericArgs
134135 this . bitSize = UFixedNxMImpl . getMaxBitsLength ( this . typeInfo ) as N
135136 this . precision = parseInt ( genericArgs . m . name , 10 ) as M
136137
137- const trimmedValue = trimTrailingDecimalZeros ( v )
138+ const trimmedValue = trimTrailingDecimalZeros ( v ?? '0.0' )
138139 assert ( regExpNxM ( this . precision ) . test ( trimmedValue ) , `expected positive decimal literal with max of ${ this . precision } decimal places` )
139140
140141 const bigIntValue = BigInt ( trimmedValue . replace ( '.' , '' ) )
@@ -308,7 +309,7 @@ const checkItemTypeName = (type: TypeInfo, value: ARC4Encoded) => {
308309}
309310type StaticArrayGenericArgs = { elementType : TypeInfo ; size : TypeInfo }
310311const arrayProxyHandler = < TItem > ( ) => ( {
311- get ( target : { items : TItem [ ] } , prop : PropertyKey ) {
312+ get ( target : { items : readonly TItem [ ] } , prop : PropertyKey ) {
312313 const idx = prop ? parseInt ( prop . toString ( ) , 10 ) : NaN
313314 if ( ! isNaN ( idx ) ) {
314315 if ( idx >= 0 && idx < target . items . length ) return target . items [ idx ]
@@ -337,8 +338,9 @@ const arrayProxyHandler = <TItem>() => ({
337338 return Reflect . set ( target , prop , value )
338339 } ,
339340} )
341+ const isInitialisingFromBytesSymbol = Symbol ( 'IsInitialisingFromBytes' )
340342export class StaticArrayImpl < TItem extends ARC4Encoded , TLength extends number > extends StaticArray < TItem , TLength > {
341- private value ?: TItem [ ]
343+ private value ?: NTuple < TItem , TLength >
342344 private uint8ArrayValue ?: Uint8Array
343345 private size : number
344346 typeInfo : TypeInfo
@@ -347,23 +349,33 @@ export class StaticArrayImpl<TItem extends ARC4Encoded, TLength extends number>
347349 constructor ( typeInfo : TypeInfo | string , ...items : TItem [ ] & { length : TLength } )
348350 constructor ( typeInfo : TypeInfo | string , ...items : TItem [ ] )
349351 constructor ( typeInfo : TypeInfo | string , ...items : TItem [ ] & { length : TLength } ) {
350- super ( ...( items as DeliberateAny ) )
352+ // if first item is the symbol, we are initialising from bytes
353+ // so we don't need to pass the items to the super constructor
354+ const isInitialisingFromBytes = items . length === 1 && ( items [ 0 ] as DeliberateAny ) === isInitialisingFromBytesSymbol
355+ super ( ...( isInitialisingFromBytes ? [ ] : ( items as DeliberateAny ) ) )
356+
351357 this . typeInfo = typeof typeInfo === 'string' ? JSON . parse ( typeInfo ) : typeInfo
352358 this . genericArgs = this . typeInfo . genericArgs as StaticArrayGenericArgs
353-
354359 this . size = parseInt ( this . genericArgs . size . name , 10 )
355- if ( items . length && items . length !== this . size ) {
356- throw new CodeError ( `expected ${ this . size } items, not ${ items . length } ` )
357- }
358360
359- assert ( areAllARC4Encoded ( items ) , 'expected ARC4 type' )
361+ // if we are not initialising from bytes, we need to check and set the items
362+ if ( ! isInitialisingFromBytes ) {
363+ if ( items . length && items . length !== this . size ) {
364+ throw new CodeError ( `expected ${ this . size } items, not ${ items . length } ` )
365+ }
360366
361- items . forEach ( ( item ) => {
362- checkItemTypeName ( this . genericArgs . elementType , item )
363- } )
367+ assert ( areAllARC4Encoded ( items ) , 'expected ARC4 type' )
364368
365- this . value = items . length ? items : undefined
369+ items . forEach ( ( item ) => {
370+ checkItemTypeName ( this . genericArgs . elementType , item )
371+ } )
366372
373+ if ( items . length ) {
374+ this . value = items as NTuple < TItem , TLength >
375+ } else {
376+ this . uint8ArrayValue = new Uint8Array ( StaticArrayImpl . getMaxBytesLength ( this . typeInfo ) )
377+ }
378+ }
367379 return new Proxy ( this , arrayProxyHandler < TItem > ( ) ) as StaticArrayImpl < TItem , TLength >
368380 }
369381
@@ -382,10 +394,10 @@ export class StaticArrayImpl<TItem extends ARC4Encoded, TLength extends number>
382394 return this . size
383395 }
384396
385- get items ( ) : TItem [ ] {
397+ get items ( ) : NTuple < TItem , TLength > {
386398 if ( this . uint8ArrayValue ) {
387399 const childTypes = Array ( this . size ) . fill ( this . genericArgs . elementType )
388- this . value = decode ( this . uint8ArrayValue , childTypes ) as TItem [ ]
400+ this . value = decode ( this . uint8ArrayValue , childTypes ) as NTuple < TItem , TLength >
389401 this . uint8ArrayValue = undefined
390402 return this . value
391403 } else if ( this . value ) {
@@ -417,7 +429,7 @@ export class StaticArrayImpl<TItem extends ARC4Encoded, TLength extends number>
417429 )
418430 }
419431
420- get native ( ) : TItem [ ] {
432+ get native ( ) : NTuple < TItem , TLength > {
421433 return this . items
422434 }
423435
@@ -431,7 +443,8 @@ export class StaticArrayImpl<TItem extends ARC4Encoded, TLength extends number>
431443 assert ( bytesValue . slice ( 0 , 4 ) . equals ( ABI_RETURN_VALUE_LOG_PREFIX ) , 'ABI return prefix not found' )
432444 bytesValue = bytesValue . slice ( 4 )
433445 }
434- const result = new StaticArrayImpl ( typeInfo )
446+ // pass the symbol to the constructor to let it know we are initialising from bytes
447+ const result = new StaticArrayImpl < ARC4Encoded , number > ( typeInfo , isInitialisingFromBytesSymbol as DeliberateAny )
435448 result . uint8ArrayValue = asUint8Array ( bytesValue )
436449 return result
437450 }
@@ -504,7 +517,7 @@ export class AddressImpl extends Address {
504517 return Account ( this . value . bytes )
505518 }
506519
507- get items ( ) : ByteImpl [ ] {
520+ get items ( ) : readonly ByteImpl [ ] {
508521 return this . value . items
509522 }
510523
@@ -646,18 +659,27 @@ export class TupleImpl<TTuple extends [ARC4Encoded, ...ARC4Encoded[]]> extends T
646659 typeInfo : TypeInfo
647660 genericArgs : TypeInfo [ ]
648661
649- constructor ( typeInfo : TypeInfo | string )
650662 constructor ( typeInfo : TypeInfo | string , ...items : TTuple ) {
651- super ( ...items )
663+ // if first item is the symbol, we are initialising from bytes
664+ // so we don't need to pass the items to the super constructor
665+ const isInitialisingFromBytes = items . length === 1 && ( items [ 0 ] as DeliberateAny ) === isInitialisingFromBytesSymbol
666+ super ( ...( isInitialisingFromBytes ? ( [ ] as DeliberateAny ) : items ) )
652667 this . typeInfo = typeof typeInfo === 'string' ? JSON . parse ( typeInfo ) : typeInfo
653668 this . genericArgs = Object . values ( this . typeInfo . genericArgs as Record < string , TypeInfo > )
654669
655- assert ( areAllARC4Encoded ( items ) , 'expected ARC4 type' )
670+ // if we are not initialising from bytes, we need to check and set the items
671+ if ( ! isInitialisingFromBytes ) {
672+ assert ( areAllARC4Encoded ( items ) , 'expected ARC4 type' )
656673
657- items . forEach ( ( item , index ) => {
658- checkItemTypeName ( this . genericArgs [ index ] , item )
659- } )
660- this . value = items . length ? items : undefined
674+ items . forEach ( ( item , index ) => {
675+ checkItemTypeName ( this . genericArgs [ index ] , item )
676+ } )
677+ if ( items . length ) {
678+ this . value = items
679+ } else {
680+ this . uint8ArrayValue = new Uint8Array ( TupleImpl . getMaxBytesLength ( this . typeInfo ) )
681+ }
682+ }
661683 }
662684
663685 get bytes ( ) : bytes {
@@ -705,7 +727,8 @@ export class TupleImpl<TTuple extends [ARC4Encoded, ...ARC4Encoded[]]> extends T
705727 assert ( bytesValue . slice ( 0 , 4 ) . equals ( ABI_RETURN_VALUE_LOG_PREFIX ) , 'ABI return prefix not found' )
706728 bytesValue = bytesValue . slice ( 4 )
707729 }
708- const result = new TupleImpl ( typeInfo )
730+ // pass the symbol to the constructor to let it know we are initialising from bytes
731+ const result = new TupleImpl ( typeInfo , isInitialisingFromBytesSymbol as DeliberateAny )
709732 result . uint8ArrayValue = asUint8Array ( bytesValue )
710733 return result
711734 }
@@ -920,9 +943,9 @@ export class StaticBytesImpl extends StaticBytes {
920943
921944 constructor ( typeInfo : TypeInfo | string , value ?: bytes | string ) {
922945 super ( value )
923- const uint8ArrayValue = asUint8Array ( value ?? new Uint8Array ( ) )
924- this . value = StaticArrayImpl . fromBytesImpl ( uint8ArrayValue , typeInfo ) as StaticArrayImpl < ByteImpl , number >
925946 this . typeInfo = typeof typeInfo === 'string' ? JSON . parse ( typeInfo ) : typeInfo
947+ const uint8ArrayValue = asUint8Array ( value ?? new Uint8Array ( StaticBytesImpl . getMaxBytesLength ( this . typeInfo ) ) )
948+ this . value = StaticArrayImpl . fromBytesImpl ( uint8ArrayValue , typeInfo ) as StaticArrayImpl < ByteImpl , number >
926949 return new Proxy ( this , arrayProxyHandler < ByteImpl > ( ) ) as StaticBytesImpl
927950 }
928951
@@ -1086,6 +1109,8 @@ const getMaxLengthOfStaticContentType = (type: TypeInfo): number => {
10861109 case 'biguint' :
10871110 return UINT512_SIZE / BITS_IN_BYTE
10881111 case 'boolean' :
1112+ return 8
1113+ case 'Bool' :
10891114 return 1
10901115 case 'Address' :
10911116 return AddressImpl . getMaxBytesLength ( type )
@@ -1103,8 +1128,9 @@ const getMaxLengthOfStaticContentType = (type: TypeInfo): number => {
11031128 return TupleImpl . getMaxBytesLength ( type )
11041129 case 'Struct' :
11051130 return StructImpl . getMaxBytesLength ( type )
1131+ default :
1132+ throw new CodeError ( `unsupported type ${ type . name } ` )
11061133 }
1107- throw new CodeError ( `unsupported type ${ type . name } ` )
11081134}
11091135
11101136const encode = ( values : ARC4Encoded [ ] ) => {
@@ -1338,7 +1364,7 @@ export const getArc4Encoded = (value: DeliberateAny): ARC4Encoded => {
13381364 } , [ ] )
13391365 const genericArgs : TypeInfo [ ] = result . map ( ( x ) => ( x as DeliberateAny ) . typeInfo )
13401366 const typeInfo = { name : `Tuple<[${ genericArgs . map ( ( x ) => x . name ) . join ( ',' ) } ]>` , genericArgs }
1341- return new TupleImpl ( typeInfo , ...( result as [ ] ) )
1367+ return new TupleImpl ( typeInfo , ...( result as [ ARC4Encoded , ... ARC4Encoded [ ] ] ) )
13421368 }
13431369 if ( typeof value === 'object' ) {
13441370 const result = Object . values ( value ) . reduce ( ( acc : ARC4Encoded [ ] , cur : DeliberateAny ) => {
@@ -1359,3 +1385,15 @@ export const arc4EncodedLengthImpl = (typeInfoString: string): uint64 => {
13591385 const typeInfo = JSON . parse ( typeInfoString )
13601386 return getMaxLengthOfStaticContentType ( typeInfo )
13611387}
1388+
1389+ export const tryArc4EncodedLengthImpl = ( typeInfoString : string | TypeInfo ) : uint64 | undefined => {
1390+ const typeInfo = typeof typeInfoString === 'string' ? JSON . parse ( typeInfoString ) : typeInfoString
1391+ try {
1392+ return getMaxLengthOfStaticContentType ( typeInfo )
1393+ } catch ( e ) {
1394+ if ( e instanceof CodeError && e . message . startsWith ( 'unsupported type' ) ) {
1395+ return undefined
1396+ }
1397+ throw e
1398+ }
1399+ }
0 commit comments