Skip to content

Commit

Permalink
Merge pull request #12 from algorandfoundation/feat-arc4-dynamic-types
Browse files Browse the repository at this point in the history
feat: arc4 types
  • Loading branch information
boblat authored Dec 12, 2024
2 parents 38d47f9 + 4de4c08 commit e295a2f
Show file tree
Hide file tree
Showing 30 changed files with 10,002 additions and 105 deletions.
3 changes: 1 addition & 2 deletions .nsprc
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
{
}
{}
19 changes: 9 additions & 10 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const MAX_UINT8 = 2 ** 8 - 1
export const MAX_UINT64 = 2n ** 64n - 1n
export const MAX_UINT512 = 2n ** 512n - 1n
export const MAX_BYTES_SIZE = 4096
export const MAX_LOG_SIZE = 1024
export const MAX_ITEMS_IN_LOG = 32
export const MAX_BOX_SIZE = 32768
export const BITS_IN_BYTE = 8
Expand Down
35 changes: 17 additions & 18 deletions src/encoders.ts
Original file line number Diff line number Diff line change
@@ -1,62 +1,61 @@
import { biguint, BigUint, bytes, Bytes, internal, TransactionType, uint64, Uint64 } from '@algorandfoundation/algorand-typescript'
import { biguint, BigUint, bytes, internal, TransactionType, uint64, Uint64 } from '@algorandfoundation/algorand-typescript'
import { OnCompleteAction } from '@algorandfoundation/algorand-typescript/arc4'
import { AccountCls } from './impl/account'
import { ApplicationCls } from './impl/application'
import { AssetCls } from './impl/asset'
import { arc4Encoders, getArc4Encoder } from './impl/encoded-types'
import { DeliberateAny } from './typescript-helpers'
import { asBytes, asUint8Array } from './util'

export interface TypeInfo {
export type TypeInfo = {
name: string
genericArgs?: TypeInfo[] | Record<string, TypeInfo>
}

type fromBytes<T> = (val: Uint8Array, typeInfo: TypeInfo) => T
export type fromBytes<T> = (val: Uint8Array | internal.primitives.StubBytesCompat, typeInfo: TypeInfo, prefix?: 'none' | 'log') => T

const booleanFromBytes: fromBytes<boolean> = (val) => {
return internal.encodingUtil.uint8ArrayToBigInt(val) > 0n
return internal.encodingUtil.uint8ArrayToBigInt(asUint8Array(val)) > 0n
}

const bigUintFromBytes: fromBytes<biguint> = (val) => {
return BigUint(internal.encodingUtil.uint8ArrayToBigInt(val))
return BigUint(internal.encodingUtil.uint8ArrayToBigInt(asUint8Array(val)))
}

const bytesFromBytes: fromBytes<bytes> = (val) => {
return Bytes(val)
return asBytes(val)
}

const stringFromBytes: fromBytes<string> = (val) => {
return Bytes(val).toString()
return asBytes(val).toString()
}

const uint64FromBytes: fromBytes<uint64> = (val) => {
return Uint64(internal.encodingUtil.uint8ArrayToBigInt(val))
return Uint64(internal.encodingUtil.uint8ArrayToBigInt(asUint8Array(val)))
}

const onCompletionFromBytes: fromBytes<OnCompleteAction> = (val) => {
return Uint64(internal.encodingUtil.uint8ArrayToBigInt(val)) as OnCompleteAction
return Uint64(internal.encodingUtil.uint8ArrayToBigInt(asUint8Array(val))) as OnCompleteAction
}

const transactionTypeFromBytes: fromBytes<TransactionType> = (val) => {
return Uint64(internal.encodingUtil.uint8ArrayToBigInt(val)) as TransactionType
return Uint64(internal.encodingUtil.uint8ArrayToBigInt(asUint8Array(val))) as TransactionType
}

export const encoders = {
export const encoders: Record<string, fromBytes<DeliberateAny>> = {
account: AccountCls.fromBytes,
application: ApplicationCls.fromBytes,
asset: AssetCls.fromBytes,
'bool(ean)?': booleanFromBytes,
boolean: booleanFromBytes,
biguint: bigUintFromBytes,
bytes: bytesFromBytes,
string: stringFromBytes,
uint64: uint64FromBytes,
OnCompleteAction: onCompletionFromBytes,
TransactionType: transactionTypeFromBytes,
// 'Tuple<*>': tupleFromBytes,
...arc4Encoders,
}

export const getEncoder = <T>(typeInfo: TypeInfo): fromBytes<T> => {
const encoder = Object.entries(encoders).find(([k, _]) => new RegExp(`^${k}$`, 'i').test(typeInfo.name))?.[1]
if (!encoder) {
throw new Error(`No encoder found for type ${typeInfo.name}`)
}
return encoder as fromBytes<T>
return getArc4Encoder<T>(typeInfo, encoders)
}
15 changes: 10 additions & 5 deletions src/impl/base.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Bytes, bytes, Uint64, uint64 } from '@algorandfoundation/algorand-typescript'
import { bytes, internal, Uint64, uint64 } from '@algorandfoundation/algorand-typescript'
import { encodingUtil } from '@algorandfoundation/puya-ts'
import type { TypeInfo } from '../encoders'

Expand All @@ -14,8 +14,12 @@ export abstract class BytesBackedCls {
// this.#typeInfo = typeInfo
}

static fromBytes<T extends BytesBackedCls>(this: { new (v: bytes, typeInfo?: TypeInfo): T }, value: Uint8Array, typeInfo?: TypeInfo) {
return new this(Bytes(value), typeInfo)
static fromBytes<T extends BytesBackedCls>(
this: { new (v: bytes, typeInfo?: TypeInfo): T },
value: internal.primitives.StubBytesCompat | Uint8Array,
typeInfo?: TypeInfo,
) {
return new this(internal.primitives.BytesCls.fromCompat(value).asAlgoTs(), typeInfo)
}
}

Expand All @@ -30,8 +34,9 @@ export abstract class Uint64BackedCls {
this.#value = value
}

static fromBytes<T extends Uint64BackedCls>(this: { new (v: uint64): T }, value: Uint8Array) {
const uint64Value = Uint64(encodingUtil.uint8ArrayToBigInt(value))
static fromBytes<T extends Uint64BackedCls>(this: { new (v: uint64): T }, value: internal.primitives.StubBytesCompat | Uint8Array) {
const uint8ArrayValue = value instanceof Uint8Array ? value : internal.primitives.BytesCls.fromCompat(value).asUint8Array()
const uint64Value = Uint64(encodingUtil.uint8ArrayToBigInt(uint8ArrayValue))
return new this(uint64Value)
}
}
Loading

0 comments on commit e295a2f

Please sign in to comment.