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
10 changes: 7 additions & 3 deletions examples/voting/contract.algo.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ describe('VotingRoundApp', () => {

const createContract = () => {
const contract = ctx.contract.create(VotingRoundApp)
const snapshotPublicKey = Bytes<32>(keyPair.publicKey)
const snapshotPublicKey = Bytes(keyPair.publicKey).toFixed({ length: 32 })
const metadataIpfsCid = ctx.any.string(16)
const startTime = ctx.any.uint64(Date.now() - 10_000, Date.now())
const endTime = ctx.any.uint64(Date.now() + 10_000, Date.now() + 100_000)
Expand Down Expand Up @@ -52,7 +52,7 @@ describe('VotingRoundApp', () => {
const account = ctx.any.account()
const signature = nacl.sign.detached(toExternalValue(account.bytes), keyPair.secretKey)
ctx.txn.createScope([ctx.any.txn.applicationCall({ sender: account })]).execute(() => {
const preconditions = contract.getPreconditions(Bytes(signature))
const preconditions = contract.getPreconditions(Bytes(signature).toFixed({ length: 64 }))

expect(preconditions.is_allowed_to_vote).toEqual(1)
expect(preconditions.is_voting_open).toEqual(1)
Expand All @@ -75,7 +75,11 @@ describe('VotingRoundApp', () => {
)

ctx.txn.createScope([ctx.any.txn.applicationCall({ appId: app, sender: account })]).execute(() => {
contract.vote(ctx.any.txn.payment({ receiver: app.address, amount: voteMinBalanceReq }), Bytes(signature), answerIds)
contract.vote(
ctx.any.txn.payment({ receiver: app.address, amount: voteMinBalanceReq }),
Bytes(signature).toFixed({ length: 64 }),
answerIds,
)

expect(contract.votesByAccount(account).value.bytes).toEqual(answerIds.bytes)
expect(contract.voterCount.value).toEqual(13)
Expand Down
18 changes: 9 additions & 9 deletions package-lock.json

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

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@
"vitest": "3.2.4"
},
"dependencies": {
"@algorandfoundation/algorand-typescript": "1.0.0-alpha.84",
"@algorandfoundation/puya-ts": "1.0.0-alpha.84",
"@algorandfoundation/algorand-typescript": "1.0.0-alpha.85",
"@algorandfoundation/puya-ts": "1.0.0-alpha.85",
"elliptic": "^6.6.1",
"js-sha256": "^0.11.0",
"js-sha3": "^0.9.3",
Expand Down
7 changes: 3 additions & 4 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Bytes, FixedBytes } from './impl/primitives'
import { Bytes } from './impl/primitives'

/** @internal */
export const UINT64_SIZE = 64
Expand Down Expand Up @@ -40,13 +40,12 @@ export const DEFAULT_ASSET_OPT_IN_MIN_BALANCE = 10_000
/** @internal
* from python code: list(b"\x85Y\xb5\x14x\xfd\x89\xc1vC\xd0]\x15\xa8\xaek\x10\xabG\xbbm\x8a1\x88\x11V\xe6\xbd;\xae\x95\xd1")
*/
export const DEFAULT_GLOBAL_GENESIS_HASH = FixedBytes(
32,
export const DEFAULT_GLOBAL_GENESIS_HASH = Bytes(
new Uint8Array([
133, 89, 181, 20, 120, 253, 137, 193, 118, 67, 208, 93, 21, 168, 174, 107, 16, 171, 71, 187, 109, 138, 49, 136, 17, 86, 230, 189, 59,
174, 149, 209,
]),
)
).toFixed({ length: 32 })

/** @internal
* algorand encoded address of 32 zero bytes
Expand Down
14 changes: 7 additions & 7 deletions src/impl/crypto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,37 +10,37 @@ import { lazyContext } from '../context-helpers/internal-context'
import { InternalError, NotImplementedError } from '../errors'
import { asBytes, asBytesCls, asUint8Array, concatUint8Arrays } from '../util'
import type { StubBytesCompat, StubUint64Compat } from './primitives'
import { Bytes, BytesCls, FixedBytes, Uint64Cls } from './primitives'
import { Bytes, BytesCls, Uint64Cls } from './primitives'

/** @internal */
export const sha256 = (a: StubBytesCompat): bytes<32> => {
const bytesA = BytesCls.fromCompat(a)
const hashArray = js_sha256.sha256.create().update(bytesA.asUint8Array()).digest()
const hashBytes = FixedBytes(32, new Uint8Array(hashArray))
const hashBytes = Bytes(new Uint8Array(hashArray)).toFixed({ length: 32 })
return hashBytes
}

/** @internal */
export const sha3_256 = (a: StubBytesCompat): bytes<32> => {
const bytesA = BytesCls.fromCompat(a)
const hashArray = js_sha3.sha3_256.create().update(bytesA.asUint8Array()).digest()
const hashBytes = FixedBytes(32, new Uint8Array(hashArray))
const hashBytes = Bytes(new Uint8Array(hashArray)).toFixed({ length: 32 })
return hashBytes
}

/** @internal */
export const keccak256 = (a: StubBytesCompat): bytes<32> => {
const bytesA = BytesCls.fromCompat(a)
const hashArray = js_sha3.keccak256.create().update(bytesA.asUint8Array()).digest()
const hashBytes = FixedBytes(32, new Uint8Array(hashArray))
const hashBytes = Bytes(new Uint8Array(hashArray)).toFixed({ length: 32 })
return hashBytes
}

/** @internal */
export const sha512_256 = (a: StubBytesCompat): bytes<32> => {
const bytesA = BytesCls.fromCompat(a)
const hashArray = js_sha512.sha512_256.create().update(bytesA.asUint8Array()).digest()
const hashBytes = FixedBytes(32, new Uint8Array(hashArray))
const hashBytes = Bytes(new Uint8Array(hashArray)).toFixed({ length: 32 })
return hashBytes
}

Expand Down Expand Up @@ -114,7 +114,7 @@ export const ecdsaPkRecover = (

const x = pubKey.getX().toArray('be')
const y = pubKey.getY().toArray('be')
return [FixedBytes(32, x), FixedBytes(32, y)]
return [Bytes(x).toFixed({ length: 32 }), Bytes(y).toFixed({ length: 32 })]
}

/** @internal */
Expand All @@ -127,7 +127,7 @@ export const ecdsaPkDecompress = (v: Ecdsa, a: StubBytesCompat): readonly [bytes

const x = pubKey.getX().toArray('be')
const y = pubKey.getY().toArray('be')
return [FixedBytes(32, new Uint8Array(x)), FixedBytes(32, new Uint8Array(y))]
return [Bytes(x).toFixed({ length: 32 }), Bytes(y).toFixed({ length: 32 })]
}

/** @internal */
Expand Down
92 changes: 0 additions & 92 deletions src/impl/primitives.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type { biguint, BigUintCompat, bytes, BytesCompat, uint64, Uint64Compat } from '@algorandfoundation/algorand-typescript'
import { encodingUtil } from '@algorandfoundation/puya-ts'
import { avmError, AvmError, avmInvariant, CodeError, InternalError } from '../errors'
import type { DeliberateAny } from '../typescript-helpers'
import { nameOfType } from '../typescript-helpers'
import { base32ToUint8Array } from './base-32'

Expand Down Expand Up @@ -88,97 +87,6 @@ export function BigUint(v?: BigUintCompat | string): biguint {
return BigUintCls.fromCompat(v).asAlgoTs()
}

/**
* @internal
* Create a byte array from a string interpolation template and compatible replacements
* @param value *
* @param replacements *
*/
export function FixedBytes<TLength extends uint64 = uint64>(
length: TLength,
value: TemplateStringsArray,
...replacements: BytesCompat[]
): bytes<TLength>
/**
* @internal
* Create a byte array from a utf8 string
*/
export function FixedBytes<TLength extends uint64 = uint64>(length: TLength, value: string): bytes<TLength>
/**
* @internal
* No op, returns the provided byte array.
*/
export function FixedBytes<TLength extends uint64 = uint64>(length: TLength, value: bytes): bytes<TLength>
/**
* @internal
* Create a byte array from a biguint value encoded as a variable length big-endian number *
*/
export function FixedBytes<TLength extends uint64 = uint64>(length: TLength, value: biguint): bytes<TLength>
/**
* @internal
* Create a byte array from a uint64 value encoded as a fixed length 64-bit number
*/
export function FixedBytes<TLength extends uint64 = uint64>(length: TLength, value: uint64): bytes<TLength>
/**
* @internal
* Create a byte array from an Iterable<uint64> where each item is interpreted as a single byte and must be between 0 and 255 inclusively
*/
export function FixedBytes<TLength extends uint64 = uint64>(length: TLength, value: Iterable<uint64>): bytes<TLength>
/**
* @internal
* Create an empty byte array
*/
export function FixedBytes<TLength extends uint64 = uint64>(length: TLength): bytes<TLength>
export function FixedBytes<TLength extends uint64 = uint64>(
length: TLength,
value?: BytesCompat | TemplateStringsArray | biguint | uint64 | Iterable<number>,
...replacements: BytesCompat[]
): bytes<TLength> {
const result = Bytes((value ?? new Uint8Array(length)) as DeliberateAny, ...replacements)
if (length && length !== getNumber(result.length)) {
throw new CodeError(`Invalid bytes constant length of ${result.length}, expected ${length}`)
}
return result.toFixed({ length })
}

/**
* @internal
* Create a new bytes value from a hexadecimal encoded string
* @param hex
*/
FixedBytes.fromHex = <TLength extends uint64 = uint64>(length: TLength, hex: string): bytes<TLength> => {
const result = BytesCls.fromHex(hex).asAlgoTs()
if (length && length !== getNumber(result.length)) {
throw new CodeError(`Expected decoded bytes value of length ${length}, received ${result.length}`)
}
return result.toFixed({ length })
}
/**
* @internal
* Create a new bytes value from a base 64 encoded string
* @param b64
*/
FixedBytes.fromBase64 = <TLength extends uint64 = uint64>(length: TLength, b64: string): bytes<TLength> => {
const result = BytesCls.fromBase64(b64).asAlgoTs()
if (length && length !== getNumber(result.length)) {
throw new CodeError(`Expected decoded bytes value of length ${length}, received ${result.length}`)
}
return result.toFixed({ length })
}

/**
* @internal
* Create a new bytes value from a base 32 encoded string
* @param b32
*/
FixedBytes.fromBase32 = <TLength extends uint64 = uint64>(length: TLength, b32: string): bytes<TLength> => {
const result = BytesCls.fromBase32(b32).asAlgoTs()
if (length && length !== getNumber(result.length)) {
throw new CodeError(`Expected decoded bytes value of length ${length}, received ${result.length}`)
}
return result.toFixed({ length })
}

/**
* @internal
* Create a byte array from a string interpolation template and compatible replacements
Expand Down
2 changes: 0 additions & 2 deletions src/runtime-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ import { flattenAsBytes } from './util'

/** @internal */
export { attachAbiMetadata } from './abi-metadata'
/** @internal */
export { FixedBytes } from './impl/primitives'

/** @internal */
export function switchableValue(x: unknown): bigint | string | boolean {
Expand Down
13 changes: 0 additions & 13 deletions src/test-transformer/node-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,17 +149,4 @@ export const nodeFactory = {
}
return node
},

callFixedBytesFunction(functionName: string, node: ts.CallExpression, length: number) {
const updatedPropertyAccessExpression = factory.createPropertyAccessExpression(
factory.createIdentifier('runtimeHelpers'),
`FixedBytes${functionName === 'Bytes' ? '' : `.${functionName}`}`,
)

return factory.createCallExpression(
updatedPropertyAccessExpression,
node.typeArguments,
[factory.createNumericLiteral(length), ...(node.arguments ?? [])].filter((arg) => !!arg),
)
},
} satisfies Record<string, (...args: DeliberateAny[]) => ts.Node | ts.Node[]>
11 changes: 3 additions & 8 deletions src/test-transformer/visitors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,9 +218,6 @@ class ExpressionVisitor {
updatedNode = nodeFactory.callAbiCallFunction(updatedNode, typeParams)
} else if (isCallingItxnCompose(stubbedFunctionName)) {
updatedNode = nodeFactory.callItxnComposeFunction(updatedNode)
} else if (isCallingBytes(stubbedFunctionName)) {
if (type instanceof ptypes.BytesPType && type.length)
updatedNode = nodeFactory.callFixedBytesFunction(stubbedFunctionName, updatedNode, Number(type.length))
} else {
updatedNode = nodeFactory.callStubbedFunction(updatedNode, infoArg)
}
Expand Down Expand Up @@ -506,7 +503,7 @@ const tryGetStubbedFunctionName = (node: ts.CallExpression, helper: VisitorHelpe
: (node.expression as ts.Identifier)
const functionName = tryGetAlgoTsSymbolName(identityExpression, helper)
if (functionName === undefined) return undefined
const stubbedFunctionNames = ['convertBytes', 'decodeArc4', 'encodeArc4', 'emit', 'methodSelector', 'sizeOf', 'abiCall', 'clone', 'Bytes']
const stubbedFunctionNames = ['convertBytes', 'decodeArc4', 'encodeArc4', 'emit', 'methodSelector', 'sizeOf', 'abiCall', 'clone']

if (stubbedFunctionNames.includes(functionName)) {
if (ts.isPropertyAccessExpression(node.expression)) {
Expand All @@ -516,10 +513,10 @@ const tryGetStubbedFunctionName = (node: ts.CallExpression, helper: VisitorHelpe
return functionName
}

if (['begin', 'next', 'fromHex', 'fromBase64', 'fromBase32'].includes(functionName) && ts.isPropertyAccessExpression(node.expression)) {
if (['begin', 'next'].includes(functionName) && ts.isPropertyAccessExpression(node.expression)) {
const objectExpression = node.expression.expression
const objectName = tryGetAlgoTsSymbolName(objectExpression, helper)
if (['itxnCompose', 'Bytes'].includes(objectName || '')) return functionName
if (['itxnCompose'].includes(objectName || '')) return functionName
}

return undefined
Expand Down Expand Up @@ -550,5 +547,3 @@ const isCallingMethodSelector = (functionName: string | undefined): boolean => '
const isCallingAbiCall = (functionName: string | undefined): boolean => ['abiCall'].includes(functionName ?? '')
const isCallingItxnCompose = (functionName: string | undefined): boolean => ['begin', 'next'].includes(functionName ?? '')
const isCallingClone = (functionName: string | undefined): boolean => 'clone' === (functionName ?? '')
const isCallingBytes = (functionName: string | undefined): boolean =>
['Bytes', 'fromHex', 'fromBase64', 'fromBase32'].includes(functionName ?? '')
Loading