Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions src/encoders.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { biguint, bytes, OnCompleteAction, TransactionType, uint64 } from '@algorandfoundation/algorand-typescript'
import { ARC4Encoded } from '@algorandfoundation/algorand-typescript/arc4'
import { encodingUtil } from '@algorandfoundation/puya-ts'
import { InternalError } from './errors'
import { CodeError, InternalError } from './errors'
import { BytesBackedCls, Uint64BackedCls } from './impl/base'
import { arc4Encoders, encodeArc4Impl, getArc4Encoder, tryArc4EncodedLengthImpl } from './impl/encoded-types'
import { arc4Encoders, encodeArc4Impl, getArc4Encoder, getMaxLengthOfStaticContentType } from './impl/encoded-types'
import { BigUint, Uint64, type StubBytesCompat } from './impl/primitives'
import { AccountCls, ApplicationCls, AssetCls } from './impl/reference'
import type { DeliberateAny } from './typescript-helpers'
Expand Down Expand Up @@ -90,7 +90,13 @@ export const toBytes = (val: unknown): bytes => {
throw new InternalError(`Invalid type for bytes: ${nameOfType(val)}`)
}

export const minLengthForType = (typeInfo: TypeInfo): number => {
const minArc4StaticLength = tryArc4EncodedLengthImpl(typeInfo)
return minArc4StaticLength ?? 0
export const minLengthForType = (typeInfo: TypeInfo): number | undefined => {
try {
return getMaxLengthOfStaticContentType(typeInfo, false)
} catch (e) {
if (e instanceof CodeError && e.message.startsWith('unsupported type')) {
return undefined
}
throw e
}
}
18 changes: 3 additions & 15 deletions src/impl/encoded-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1103,14 +1103,14 @@ const findBoolTypes = (values: TypeInfo[], index: number, delta: number): number
return until
}

const getMaxLengthOfStaticContentType = (type: TypeInfo): number => {
export const getMaxLengthOfStaticContentType = (type: TypeInfo, asArc4Encoded: boolean = true): number => {
switch (trimGenericTypeName(type.name)) {
case 'uint64':
return UINT64_SIZE / BITS_IN_BYTE
case 'biguint':
return UINT512_SIZE / BITS_IN_BYTE
case 'boolean':
return 8
return asArc4Encoded ? 1 : 8
case 'Bool':
return 1
case 'Address':
Expand Down Expand Up @@ -1409,17 +1409,5 @@ export const getArc4Encoded = (value: DeliberateAny, sourceTypeInfoString?: stri

export const arc4EncodedLengthImpl = (typeInfoString: string): uint64 => {
const typeInfo = JSON.parse(typeInfoString)
return getMaxLengthOfStaticContentType(typeInfo)
}

export const tryArc4EncodedLengthImpl = (typeInfoString: string | TypeInfo): uint64 | undefined => {
const typeInfo = typeof typeInfoString === 'string' ? JSON.parse(typeInfoString) : typeInfoString
try {
return getMaxLengthOfStaticContentType(typeInfo)
} catch (e) {
if (e instanceof CodeError && e.message.startsWith('unsupported type')) {
return undefined
}
throw e
}
return getMaxLengthOfStaticContentType(typeInfo, true)
}
12 changes: 4 additions & 8 deletions src/impl/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { lazyContext } from '../context-helpers/internal-context'
import type { TypeInfo } from '../encoders'
import { getEncoder, minLengthForType, toBytes } from '../encoders'
import { AssertError, CodeError, InternalError } from '../errors'
import { getGenericTypeInfo, tryArc4EncodedLengthImpl } from '../runtime-helpers'
import { getGenericTypeInfo } from '../runtime-helpers'
import { asBytes, asBytesCls, asNumber, asUint8Array, conactUint8Arrays } from '../util'
import type { StubBytesCompat, StubUint64Compat } from './primitives'
import { Bytes, Uint64, Uint64Cls } from './primitives'
Expand Down Expand Up @@ -162,7 +162,7 @@ export class BoxCls<TValue> {

create(options?: { size?: StubUint64Compat }): boolean {
const optionSize = options?.size !== undefined ? asNumber(options.size) : undefined
const valueTypeSize = tryArc4EncodedLengthImpl(this.valueType)
const valueTypeSize = minLengthForType(this.valueType)
if (valueTypeSize === undefined && optionSize === undefined) {
throw new InternalError(`${this.valueType.name} does not have a fixed byte size. Please specify a size argument`)
}
Expand All @@ -176,11 +176,7 @@ export class BoxCls<TValue> {
)
}
}
lazyContext.ledger.setBox(
this.#app,
this.key,
new Uint8Array(Math.max(asNumber(options?.size ?? 0), this.valueType ? minLengthForType(this.valueType) : 0)),
)
lazyContext.ledger.setBox(this.#app, this.key, new Uint8Array(Math.max(asNumber(options?.size ?? 0), valueTypeSize ?? 0)))
return true
}

Expand All @@ -198,7 +194,7 @@ export class BoxCls<TValue> {
return materialised
}
set value(v: TValue) {
const isStaticValueType = tryArc4EncodedLengthImpl(this.valueType) !== undefined
const isStaticValueType = minLengthForType(this.valueType) !== undefined
const newValueBytes = asUint8Array(toBytes(v))
if (isStaticValueType && this.exists) {
const originalValueBytes = lazyContext.ledger.getBox(this.#app, this.key)
Expand Down
6 changes: 5 additions & 1 deletion tests/arc4/encode-decode-arc4.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,12 +225,16 @@ describe('arc4EncodedLength', () => {
expect(arc4EncodedLength<uint64>()).toEqual(8)
expect(arc4EncodedLength<biguint>()).toEqual(64)
expect(arc4EncodedLength<Bool>()).toEqual(1)
expect(arc4EncodedLength<boolean>()).toEqual(8)
expect(arc4EncodedLength<boolean>()).toEqual(1)
expect(arc4EncodedLength<UintN<512>>()).toEqual(64)
expect(arc4EncodedLength<[uint64, uint64, boolean]>()).toEqual(17)
expect(arc4EncodedLength<[uint64, uint64, boolean, boolean]>()).toEqual(17)
expect(arc4EncodedLength<Tuple<[StaticArray<Bool, 10>, Bool]>>()).toEqual(3)
expect(arc4EncodedLength<StaticStruct>()).toEqual(395)
expect(arc4EncodedLength<[StaticArray<Bool, 10>, boolean, boolean]>()).toEqual(3)
expect(
arc4EncodedLength<[[boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean], boolean, boolean]>(),
).toEqual(3)
})
})

Expand Down