From efc2d129660b2b0ea640e04fd731acf9c558266b Mon Sep 17 00:00:00 2001 From: Bobby Lat Date: Fri, 3 Jan 2025 11:54:34 +0800 Subject: [PATCH 1/3] refactor: remove extra util methods --- src/util.ts | 13 +++---- tests/arc4/address.spec.ts | 3 +- tests/arc4/bool.spec.ts | 2 +- tests/arc4/byte.spec.ts | 3 +- tests/arc4/str.spec.ts | 2 +- tests/arc4/uintn.spec.ts | 3 +- tests/crypto-op-codes.spec.ts | 4 +-- tests/global-state-arc4-values.spec.ts | 2 +- tests/log.spec.ts | 3 +- tests/primitives/biguint.spec.ts | 33 ++++++++---------- tests/primitives/bytes.spec.ts | 3 +- tests/pure-op-codes.spec.ts | 47 +++++++++++++++----------- tests/references/asset.spec.ts | 3 +- tests/state-op-codes.spec.ts | 3 +- tests/util.ts | 18 +--------- 15 files changed, 62 insertions(+), 80 deletions(-) diff --git a/src/util.ts b/src/util.ts index c139cd8..babf8f0 100644 --- a/src/util.ts +++ b/src/util.ts @@ -37,21 +37,18 @@ export const asBigInt = (v: internal.primitives.StubUint64Compat): bigint => asU export const asNumber = (v: internal.primitives.StubUint64Compat): number => asUint64Cls(v).asNumber() -export function extractGenericTypeArgs(t: string): string[] { - const match = t.match(/<(.*)>/) - if (!match) return [] - return match[1].split(',').map((x) => x.trim()) -} - export const asUint64Cls = (val: internal.primitives.StubUint64Compat) => internal.primitives.Uint64Cls.fromCompat(val) -export const asBigUintCls = (val: internal.primitives.StubBigUintCompat) => internal.primitives.BigUintCls.fromCompat(val) +export const asBigUintCls = (val: internal.primitives.StubBigUintCompat | Uint8Array) => + internal.primitives.BigUintCls.fromCompat( + val instanceof Uint8Array ? asBytes(val) : Array.isArray(val) ? asBytes(new Uint8Array(val)) : val, + ) export const asBytesCls = (val: internal.primitives.StubBytesCompat | Uint8Array) => internal.primitives.BytesCls.fromCompat(val) export const asUint64 = (val: internal.primitives.StubUint64Compat) => asUint64Cls(val).asAlgoTs() -export const asBigUint = (val: internal.primitives.StubBigUintCompat) => asBigUintCls(val).asAlgoTs() +export const asBigUint = (val: internal.primitives.StubBigUintCompat | Uint8Array) => asBigUintCls(val).asAlgoTs() export const asBytes = (val: internal.primitives.StubBytesCompat | Uint8Array) => asBytesCls(val).asAlgoTs() diff --git a/tests/arc4/address.spec.ts b/tests/arc4/address.spec.ts index 6b388f8..c18c23b 100644 --- a/tests/arc4/address.spec.ts +++ b/tests/arc4/address.spec.ts @@ -4,8 +4,7 @@ import { TestExecutionContext } from '@algorandfoundation/algorand-typescript-te import { Address, interpretAsArc4 } from '@algorandfoundation/algorand-typescript/arc4' import { afterEach, describe, expect, test } from 'vitest' import { ABI_RETURN_VALUE_LOG_PREFIX } from '../../src/constants' -import { encodeAddress } from '../../src/util' -import { asUint8Array } from '../util' +import { asUint8Array, encodeAddress } from '../../src/util' const abiTypeString = 'address' const testData = [ diff --git a/tests/arc4/bool.spec.ts b/tests/arc4/bool.spec.ts index ca58ded..2103d03 100644 --- a/tests/arc4/bool.spec.ts +++ b/tests/arc4/bool.spec.ts @@ -4,9 +4,9 @@ import { TestExecutionContext } from '@algorandfoundation/algorand-typescript-te import { Bool, interpretAsArc4 } from '@algorandfoundation/algorand-typescript/arc4' import { afterEach, describe, expect, test } from 'vitest' import { ABI_RETURN_VALUE_LOG_PREFIX } from '../../src/constants' +import { asUint8Array } from '../../src/util' import appSpecJson from '../artifacts/arc4-primitive-ops/data/Arc4PrimitiveOpsContract.arc32.json' import { getAlgorandAppClient, getAvmResult } from '../avm-invoker' -import { asUint8Array } from '../util' describe('arc4.Bool', async () => { const appClient = await getAlgorandAppClient(appSpecJson as AppSpec) diff --git a/tests/arc4/byte.spec.ts b/tests/arc4/byte.spec.ts index b094826..1cdcd1c 100644 --- a/tests/arc4/byte.spec.ts +++ b/tests/arc4/byte.spec.ts @@ -5,10 +5,9 @@ import { Byte, interpretAsArc4 } from '@algorandfoundation/algorand-typescript/a import { encodingUtil } from '@algorandfoundation/puya-ts' import { afterEach, describe, expect, it, test } from 'vitest' import { ABI_RETURN_VALUE_LOG_PREFIX, MAX_UINT64 } from '../../src/constants' -import { asBigUintCls } from '../../src/util' +import { asBigUintCls, asUint8Array } from '../../src/util' import appSpecJson from '../artifacts/arc4-primitive-ops/data/Arc4PrimitiveOpsContract.arc32.json' import { getAlgorandAppClient, getAvmResult } from '../avm-invoker' -import { asUint8Array } from '../util' const invalidBytesLengthError = 'byte string must be 1 byte long' describe('arc4.Byte', async () => { diff --git a/tests/arc4/str.spec.ts b/tests/arc4/str.spec.ts index 99cbc1d..a8e1b21 100644 --- a/tests/arc4/str.spec.ts +++ b/tests/arc4/str.spec.ts @@ -5,9 +5,9 @@ import { interpretAsArc4, Str } from '@algorandfoundation/algorand-typescript/ar import { encodingUtil } from '@algorandfoundation/puya-ts' import { afterEach, describe, expect, test } from 'vitest' import { ABI_RETURN_VALUE_LOG_PREFIX, MAX_LOG_SIZE } from '../../src/constants' +import { asUint8Array } from '../../src/util' import appSpecJson from '../artifacts/arc4-primitive-ops/data/Arc4PrimitiveOpsContract.arc32.json' import { getAlgorandAppClient, getAvmResult } from '../avm-invoker' -import { asUint8Array } from '../util' describe('arc4.Str', async () => { const appClient = await getAlgorandAppClient(appSpecJson as AppSpec) diff --git a/tests/arc4/uintn.spec.ts b/tests/arc4/uintn.spec.ts index a12eff7..a4c41be 100644 --- a/tests/arc4/uintn.spec.ts +++ b/tests/arc4/uintn.spec.ts @@ -5,10 +5,9 @@ import { BitSize, interpretAsArc4, UintN, UintN16, UintN256, UintN32, UintN64, U import { encodingUtil } from '@algorandfoundation/puya-ts' import { afterEach, describe, expect, it, test } from 'vitest' import { ABI_RETURN_VALUE_LOG_PREFIX, MAX_UINT512, MAX_UINT64 } from '../../src/constants' -import { asBigUintCls } from '../../src/util' +import { asBigUintCls, asUint8Array } from '../../src/util' import appSpecJson from '../artifacts/arc4-primitive-ops/data/Arc4PrimitiveOpsContract.arc32.json' import { getAlgorandAppClient, getAvmResult } from '../avm-invoker' -import { asUint8Array } from '../util' const invalidBytesLengthError = (length: number) => `byte string must correspond to a uint${length}` describe('arc4.UintN', async () => { diff --git a/tests/crypto-op-codes.spec.ts b/tests/crypto-op-codes.spec.ts index b6d98f1..2875019 100644 --- a/tests/crypto-op-codes.spec.ts +++ b/tests/crypto-op-codes.spec.ts @@ -9,10 +9,10 @@ import { afterEach, describe, expect, it, Mock, test, vi } from 'vitest' import { TestExecutionContext } from '../src' import { LOGIC_DATA_PREFIX, MAX_BYTES_SIZE, PROGRAM_TAG } from '../src/constants' import * as op from '../src/impl/crypto' -import { conactUint8Arrays, decodePublicKey } from '../src/util' +import { asUint8Array, conactUint8Arrays, decodePublicKey } from '../src/util' import appSpecJson from './artifacts/crypto-ops/data/CryptoOpsContract.arc32.json' import { generateAVMTestAccount, getAlgorandAppClientWithApp, getAvmResult } from './avm-invoker' -import { asUint8Array, getPaddedBytes } from './util' +import { getPaddedBytes } from './util' const MAX_ARG_LEN = 2048 const curveMap = { diff --git a/tests/global-state-arc4-values.spec.ts b/tests/global-state-arc4-values.spec.ts index 9d35afb..c5be7e8 100644 --- a/tests/global-state-arc4-values.spec.ts +++ b/tests/global-state-arc4-values.spec.ts @@ -12,10 +12,10 @@ import { import { Address, ARC4Encoded, BitSize, Bool, Byte, DynamicBytes, Str, UintN } from '@algorandfoundation/algorand-typescript/arc4' import { afterEach, describe, expect, test } from 'vitest' import { DeliberateAny, FunctionKeys } from '../src/typescript-helpers' +import { asUint8Array } from '../src/util' import { GlobalStateContract } from './artifacts/state-ops/contract.algo' import arc4AppGlobalAppSpecJson from './artifacts/state-ops/data/GlobalStateContract.arc32.json' import { getAlgorandAppClient, getAvmResult, getLocalNetDefaultAccount } from './avm-invoker' -import { asUint8Array } from './util' describe('ARC4 AppGlobal values', async () => { const appClient = await getAlgorandAppClient(arc4AppGlobalAppSpecJson as AppSpec) diff --git a/tests/log.spec.ts b/tests/log.spec.ts index 4d29ddd..425cf24 100644 --- a/tests/log.spec.ts +++ b/tests/log.spec.ts @@ -17,11 +17,10 @@ import { import { afterEach, describe, expect, it } from 'vitest' import { MAX_UINT512, MAX_UINT64 } from '../src/constants' import { ApplicationTransaction } from '../src/impl/transactions' -import { asBigUint, asBigUintCls } from '../src/util' +import { asBigUint, asBigUintCls, asUint8Array } from '../src/util' import { PrimitiveOpsContract } from './artifacts/primitive-ops/contract.algo' import appSpecJson from './artifacts/primitive-ops/data/PrimitiveOpsContract.arc32.json' import { getAlgorandAppClient, getAvmResultLog } from './avm-invoker' -import { asUint8Array } from './util' describe('log', async () => { const appClient = await getAlgorandAppClient(appSpecJson as AppSpec) diff --git a/tests/primitives/biguint.spec.ts b/tests/primitives/biguint.spec.ts index efbee2a..28031e8 100644 --- a/tests/primitives/biguint.spec.ts +++ b/tests/primitives/biguint.spec.ts @@ -5,12 +5,9 @@ import type { biguint } from '@algorandfoundation/algorand-typescript' import { BigUint, Bytes, internal, Uint64 } from '@algorandfoundation/algorand-typescript' import { describe, expect, it } from 'vitest' import { BIGUINT_OVERFLOW_UNDERFLOW_MESSAGE, MAX_UINT512, MAX_UINT64 } from '../../src/constants' -import { asUint64 } from '../../src/util' +import { asBigUint, asUint64 } from '../../src/util' import appSpecJson from '../artifacts/primitive-ops/data/PrimitiveOpsContract.arc32.json' import { getAlgorandAppClient, getAvmResult, getAvmResultRaw } from '../avm-invoker' -import { abiAsBytes } from '../util' - -const asBigUint = (val: bigint | number) => (typeof val === 'bigint' ? BigUint(val) : BigUint(val)) describe('BigUint', async () => { const appClient = await getAlgorandAppClient(appSpecJson as AppSpec) @@ -176,7 +173,7 @@ describe('BigUint', async () => { const bytesA = internal.encodingUtil.bigIntToUint8Array(bigUintA.valueOf()) const bytesB = internal.encodingUtil.bigIntToUint8Array(bigUintB.valueOf()) - const avmResult = BigUint(abiAsBytes(await getAvmResult({ appClient }, 'verify_biguint_add', bytesA, bytesB))) + const avmResult = asBigUint(await getAvmResult({ appClient }, 'verify_biguint_add', bytesA, bytesB)) let result = bigUintA + bigUintB expect(result, `for values: ${a}, ${b}`).toEqual(avmResult) @@ -200,7 +197,7 @@ describe('BigUint', async () => { const bytesA = internal.encodingUtil.bigIntToUint8Array(bigUintA.valueOf()) const bytesB = internal.encodingUtil.bigIntToUint8Array(bigUintB.valueOf()) - const avmResult = BigUint(abiAsBytes(await getAvmResult({ appClient }, 'verify_biguint_add', bytesA, bytesB))) + const avmResult = asBigUint(await getAvmResult({ appClient }, 'verify_biguint_add', bytesA, bytesB)) let result = bigUintA + bigUintB expect(result, `for values: ${a}, ${b}`).toEqual(avmResult) @@ -254,7 +251,7 @@ describe('BigUint', async () => { const uint64B = Uint64(b) const bytesA = internal.encodingUtil.bigIntToUint8Array(bigUintA.valueOf()) - const avmResult = BigUint(abiAsBytes(await getAvmResult({ appClient }, 'verify_biguint_add_uint64', bytesA, b))) + const avmResult = asBigUint(await getAvmResult({ appClient }, 'verify_biguint_add_uint64', bytesA, b)) let result = bigUintA + BigUint(uint64B) expect(result, `for values: ${a}, ${b}`).toEqual(avmResult) @@ -283,7 +280,7 @@ describe('BigUint', async () => { const bytesA = internal.encodingUtil.bigIntToUint8Array(bigUintA.valueOf()) const bytesB = internal.encodingUtil.bigIntToUint8Array(bigUintB.valueOf()) - const avmResult = BigUint(abiAsBytes(await getAvmResult({ appClient }, 'verify_biguint_sub', bytesA, bytesB))) + const avmResult = asBigUint(await getAvmResult({ appClient }, 'verify_biguint_sub', bytesA, bytesB)) let result = bigUintA - bigUintB expect(result, `for values: ${a}, ${b}`).toEqual(avmResult) @@ -353,7 +350,7 @@ describe('BigUint', async () => { const uint64B = Uint64(b) const bytesA = internal.encodingUtil.bigIntToUint8Array(bigUintA.valueOf()) - const avmResult = BigUint(abiAsBytes(await getAvmResult({ appClient }, 'verify_biguint_sub_uint64', bytesA, b))) + const avmResult = asBigUint(await getAvmResult({ appClient }, 'verify_biguint_sub_uint64', bytesA, b)) const result = bigUintA - BigUint(uint64B) expect(result, `for values: ${a}, ${b}`).toEqual(avmResult) @@ -378,7 +375,7 @@ describe('BigUint', async () => { const bytesA = internal.encodingUtil.bigIntToUint8Array(bigUintA.valueOf()) const bytesB = internal.encodingUtil.bigIntToUint8Array(bigUintB.valueOf()) - const avmResult = BigUint(abiAsBytes(await getAvmResult({ appClient }, 'verify_biguint_mul', bytesA, bytesB))) + const avmResult = asBigUint(await getAvmResult({ appClient }, 'verify_biguint_mul', bytesA, bytesB)) let result = bigUintA * bigUintB expect(result, `for values: ${a}, ${b}`).toEqual(avmResult) @@ -406,7 +403,7 @@ describe('BigUint', async () => { const bytesA = internal.encodingUtil.bigIntToUint8Array(bigUintA.valueOf()) const bytesB = internal.encodingUtil.bigIntToUint8Array(bigUintB.valueOf()) - const avmResult = BigUint(abiAsBytes(await getAvmResult({ appClient }, 'verify_biguint_mul', bytesA, bytesB))) + const avmResult = asBigUint(await getAvmResult({ appClient }, 'verify_biguint_mul', bytesA, bytesB)) let result = bigUintA * bigUintB expect(result, `for values: ${a}, ${b}`).toEqual(avmResult) @@ -461,7 +458,7 @@ describe('BigUint', async () => { const uint64B = asUint64(b) const bytesA = internal.encodingUtil.bigIntToUint8Array(bigUintA.valueOf()) - const avmResult = BigUint(abiAsBytes(await getAvmResult({ appClient }, 'verify_biguint_mul_uint64', bytesA, b))) + const avmResult = asBigUint(await getAvmResult({ appClient }, 'verify_biguint_mul_uint64', bytesA, b)) let result = bigUintA * BigUint(uint64B) expect(result, `for values: ${a}, ${b}`).toEqual(avmResult) @@ -489,7 +486,7 @@ describe('BigUint', async () => { const bytesA = internal.encodingUtil.bigIntToUint8Array(bigUintA.valueOf()) const bytesB = internal.encodingUtil.bigIntToUint8Array(bigUintB.valueOf()) - const avmResult = BigUint(abiAsBytes(await getAvmResult({ appClient }, 'verify_biguint_div', bytesA, bytesB))) + const avmResult = asBigUint(await getAvmResult({ appClient }, 'verify_biguint_div', bytesA, bytesB)) let result = bigUintA / bigUintB expect(result, `for values: ${a}, ${b}`).toEqual(avmResult) @@ -562,7 +559,7 @@ describe('BigUint', async () => { const uint64B = asUint64(b) const bytesA = internal.encodingUtil.bigIntToUint8Array(bigUintA.valueOf()) - const avmResult = BigUint(abiAsBytes(await getAvmResult({ appClient }, 'verify_biguint_div_uint64', bytesA, b))) + const avmResult = asBigUint(await getAvmResult({ appClient }, 'verify_biguint_div_uint64', bytesA, b)) const result = bigUintA / BigUint(uint64B) expect(result, `for values: ${a}, ${b}`).toEqual(avmResult) @@ -587,7 +584,7 @@ describe('BigUint', async () => { const bytesA = internal.encodingUtil.bigIntToUint8Array(bigUintA.valueOf()) const bytesB = internal.encodingUtil.bigIntToUint8Array(bigUintB.valueOf()) - const avmResult = BigUint(abiAsBytes(await getAvmResult({ appClient }, 'verify_biguint_mod', bytesA, bytesB))) + const avmResult = asBigUint(await getAvmResult({ appClient }, 'verify_biguint_mod', bytesA, bytesB)) let result = bigUintA % bigUintB expect(result, `for values: ${a}, ${b}`).toEqual(avmResult) @@ -659,7 +656,7 @@ describe('BigUint', async () => { const uint64B = asUint64(b) const bytesA = internal.encodingUtil.bigIntToUint8Array(bigUintA.valueOf()) - const avmResult = BigUint(abiAsBytes(await getAvmResult({ appClient }, 'verify_biguint_mod_uint64', bytesA, b))) + const avmResult = asBigUint(await getAvmResult({ appClient }, 'verify_biguint_mod_uint64', bytesA, b)) const result = bigUintA % BigUint(uint64B) expect(result, `for values: ${a}, ${b}`).toEqual(avmResult) @@ -708,7 +705,7 @@ describe('BigUint', async () => { const bytesB = internal.encodingUtil.bigIntToUint8Array(bigUintB.valueOf()) it(`${a} ${operator} ${b}`, async () => { - const avmResult = BigUint(abiAsBytes(await getAvmResult({ appClient }, `verify_biguint_${op}`, bytesA, bytesB))) + const avmResult = asBigUint(await getAvmResult({ appClient }, `verify_biguint_${op}`, bytesA, bytesB)) let result = getStubResult(bigUintA, bigUintB) expect(result, `for values: ${a}, ${b}`).toEqual(avmResult) @@ -736,7 +733,7 @@ describe('BigUint', async () => { const bytesA = internal.encodingUtil.bigIntToUint8Array(bigUintA.valueOf()) it(`${a} ${operator} ${b}`, async () => { - const avmResult = BigUint(abiAsBytes(await getAvmResult({ appClient }, `verify_biguint_${op}_uint64`, bytesA, b))) + const avmResult = asBigUint(await getAvmResult({ appClient }, `verify_biguint_${op}_uint64`, bytesA, b)) const result = getStubResult(bigUintA, BigUint(uint64B)) expect(result, `for values: ${a}, ${b}`).toEqual(avmResult) }) diff --git a/tests/primitives/bytes.spec.ts b/tests/primitives/bytes.spec.ts index 5a5b59f..edcee19 100644 --- a/tests/primitives/bytes.spec.ts +++ b/tests/primitives/bytes.spec.ts @@ -3,9 +3,10 @@ import { bytes, Bytes, internal } from '@algorandfoundation/algorand-typescript' import { describe, expect, it } from 'vitest' import { MAX_BYTES_SIZE } from '../../src/constants' import { sha256 } from '../../src/impl' +import { asUint8Array } from '../../src/util' import appSpecJson from '../artifacts/primitive-ops/data/PrimitiveOpsContract.arc32.json' import { getAlgorandAppClient, getAvmResult, getAvmResultRaw } from '../avm-invoker' -import { asUint8Array, getSha256Hash, padUint8Array } from '../util' +import { getSha256Hash, padUint8Array } from '../util' describe('Bytes', async () => { const appClient = await getAlgorandAppClient(appSpecJson as AppSpec) diff --git a/tests/pure-op-codes.spec.ts b/tests/pure-op-codes.spec.ts index 7ab8575..6935465 100644 --- a/tests/pure-op-codes.spec.ts +++ b/tests/pure-op-codes.spec.ts @@ -10,10 +10,10 @@ import { UINT64_OVERFLOW_UNDERFLOW_MESSAGE, } from '../src/constants' import * as op from '../src/impl/pure' -import { asBigUintCls } from '../src/util' +import { asBigUintCls, asUint8Array } from '../src/util' import appSpecJson from './artifacts/miscellaneous-ops/data/MiscellaneousOpsContract.arc32.json' import { getAlgorandAppClient, getAvmResult, getAvmResultRaw } from './avm-invoker' -import { abiAsBytes, asUint8Array, base64Encode, base64UrlEncode, getPaddedBytes, getSha256Hash, intToBytes } from './util' +import { base64Encode, base64UrlEncode, getPaddedBytes, getSha256Hash, intToBytes } from './util' const avmIntArgOverflowError = 'is not a non-negative int or too big to fit in size' const extractOutOfBoundError = /extraction (start|end) \d+ is beyond length/ @@ -66,7 +66,7 @@ describe('Pure op codes', async () => { base64Encode(Bytes([0xff])), base64Encode(Bytes(Array(256).fill(0x00).concat([0xff]))), ])('should decode standard base64 string', async (a) => { - const avmResult = abiAsBytes(await getAvmResult({ appClient }, 'verify_base64_decode_standard', asUint8Array(a)))! + const avmResult = (await getAvmResult({ appClient }, 'verify_base64_decode_standard', asUint8Array(a)))! const result = op.base64Decode(Base64.StdEncoding, a) expect(result).toEqual(avmResult) }) @@ -89,7 +89,7 @@ describe('Pure op codes', async () => { base64UrlEncode(Bytes([0xff])), base64UrlEncode(Bytes(Array(256).fill(0x00).concat([0xff]))), ])('should decode base64url string', async (a) => { - const avmResult = abiAsBytes(await getAvmResult({ appClient }, 'verify_base64_decode_url', asUint8Array(a)))! + const avmResult = (await getAvmResult({ appClient }, 'verify_base64_decode_url', asUint8Array(a)))! const result = op.base64Decode(Base64.URLEncoding, a) expect(result).toEqual(avmResult) }) @@ -135,7 +135,7 @@ describe('Pure op codes', async () => { describe('bsqrt', async () => { test.each([0, 1, 2, 9, 13, 144n, MAX_UINT64, MAX_UINT512])('should compute the square root of a big uint', async (a) => { const uint8ArrayA = internal.encodingUtil.bigIntToUint8Array(BigInt(a)) - const avmResult = abiAsBytes(await getAvmResult({ appClient }, 'verify_bsqrt', uint8ArrayA))! + const avmResult = (await getAvmResult({ appClient }, 'verify_bsqrt', uint8ArrayA))! const result = op.bsqrt(a) const bytesResult = asBigUintCls(result).toBytes() @@ -174,7 +174,7 @@ describe('Pure op codes', async () => { describe('bzero', async () => { test.each([0, 1, 42, MAX_BYTES_SIZE])('should return a zero filled bytes value of the given size', async (a) => { - const avmResult = abiAsBytes(await getAvmResult({ appClient }, 'verify_bzero', a))! + const avmResult = (await getAvmResult({ appClient }, 'verify_bzero', a))! const result = op.bzero(a) const resultHash = Bytes(getSha256Hash(asUint8Array(result))) expect(resultHash).toEqual(avmResult) @@ -202,9 +202,14 @@ describe('Pure op codes', async () => { ['1', '0', 0, MAX_BYTES_SIZE - 2], ['1', '0', MAX_BYTES_SIZE - 2, 0], ])('should retrun concatenated bytes', async (a, b, padASize, padBSize) => { - const avmResult = abiAsBytes( - await getAvmResult({ appClient }, 'verify_concat', asUint8Array(a), asUint8Array(b), padASize, padBSize), - )! + const avmResult = (await getAvmResult( + { appClient }, + 'verify_concat', + asUint8Array(a), + asUint8Array(b), + padASize, + padBSize, + ))! const paddedA = getPaddedBytes(padASize, a) const paddedB = getPaddedBytes(padBSize, b) @@ -424,7 +429,7 @@ describe('Pure op codes', async () => { [256, 3], ])(`should extract bytes from the input`, async (b, c) => { const a = 'hello, world'.repeat(30) - const avmResult = abiAsBytes(await getAvmResult({ appClient }, 'verify_extract', asUint8Array(a), b, c))! + const avmResult = (await getAvmResult({ appClient }, 'verify_extract', asUint8Array(a), b, c))! let result = op.extract(a, Uint64(b), Uint64(c)) expect(result).toEqual(avmResult) @@ -435,7 +440,7 @@ describe('Pure op codes', async () => { }) test.each(['hello, world', 'hi'])('should work to extract bytes from 2 to end for %s', async (a) => { - const avmResult = abiAsBytes(await getAvmResult({ appClient }, 'verify_extract_from_2', asUint8Array(a)))! + const avmResult = (await getAvmResult({ appClient }, 'verify_extract_from_2', asUint8Array(a)))! const result = op.extract(a, 2, 0) expect(result).toEqual(avmResult) }) @@ -661,7 +666,7 @@ describe('Pure op codes', async () => { describe('itob', async () => { test.each([0, 42, 100n, 256, 65535, MAX_UINT64])('should convert uint64 to bytes', async (a) => { - const avmResult = abiAsBytes(await getAvmResult({ appClient }, 'verify_itob', a))! + const avmResult = (await getAvmResult({ appClient }, 'verify_itob', a))! const result = op.itob(a) expect(result).toEqual(avmResult) }) @@ -728,7 +733,7 @@ describe('Pure op codes', async () => { ['hello, world.', 0, 'H'], ['', 0, ''], ])(`should replace bytes in the input`, async (a, b, c) => { - const avmResult = abiAsBytes(await getAvmResult({ appClient }, 'verify_replace', asUint8Array(a), b, asUint8Array(c)))! + const avmResult = (await getAvmResult({ appClient }, 'verify_replace', asUint8Array(a), b, asUint8Array(c)))! const result = op.replace(a, b, c) expect(result).toEqual(avmResult) }) @@ -756,9 +761,13 @@ describe('Pure op codes', async () => { [Bytes([0x00, 0x00, 0xff]), Bytes([0xff]), 0n], [Bytes([0x00, 0x00, 0xff]), Bytes([0xff]), 1n], ])(`should select bytes according to the input`, async (a, b, c) => { - const avmResult = abiAsBytes( - await getAvmResult({ appClient }, 'verify_select_bytes', asUint8Array(a), asUint8Array(b), c === true ? 1 : c === false ? 0 : c), - )! + const avmResult = (await getAvmResult( + { appClient }, + 'verify_select_bytes', + asUint8Array(a), + asUint8Array(b), + c === true ? 1 : c === false ? 0 : c, + ))! const result = op.select(a, b, c) expect(result).toEqual(avmResult) }) @@ -809,7 +818,7 @@ describe('Pure op codes', async () => { [intToBytes(MAX_UINT64), 0, 0], [intToBytes(MAX_UINT512), 0, 0], ])(`should set the bit at the given index of bytes value`, async (a, b, c) => { - const avmResult = abiAsBytes(await getAvmResult({ appClient }, 'verify_setbit_bytes', asUint8Array(a), b, c))! + const avmResult = (await getAvmResult({ appClient }, 'verify_setbit_bytes', asUint8Array(a), b, c))! const result = op.setBit(a, b, c) as bytes expect(result).toEqual(avmResult) }) @@ -886,7 +895,7 @@ describe('Pure op codes', async () => { [intToBytes(MAX_UINT64), 0, 0], [intToBytes(MAX_UINT512), 0, 0], ])(`should set bytes in the input`, async (a, b, c) => { - const avmResult = abiAsBytes(await getAvmResult({ appClient }, 'verify_setbyte', asUint8Array(a), b, c))! + const avmResult = (await getAvmResult({ appClient }, 'verify_setbyte', asUint8Array(a), b, c))! const result = op.setByte(a, b, c) expect(result).toEqual(avmResult) }) @@ -1007,7 +1016,7 @@ describe('Pure op codes', async () => { ['hello, world.', 0, 13], ['', 0, 0], ])('should extract substring from the input', async (a, b, c) => { - const avmResult = abiAsBytes(await getAvmResult({ appClient }, 'verify_substring', asUint8Array(a), b, c)) + const avmResult = await getAvmResult({ appClient }, 'verify_substring', asUint8Array(a), b, c) const result = op.substring(a, b, c) expect(result).toEqual(avmResult) }) diff --git a/tests/references/asset.spec.ts b/tests/references/asset.spec.ts index cf534f3..980d72c 100644 --- a/tests/references/asset.spec.ts +++ b/tests/references/asset.spec.ts @@ -2,8 +2,7 @@ import { Account, Bytes, Uint64 } from '@algorandfoundation/algorand-typescript' import { afterEach, describe, expect, it, test } from 'vitest' import { TestExecutionContext } from '../../src' import { AssetCls } from '../../src/impl/asset' -import { asBytes, asUint64 } from '../../src/util' -import { asUint8Array } from '../util' +import { asBytes, asUint64, asUint8Array } from '../../src/util' describe('Asset', () => { const ctx = new TestExecutionContext() diff --git a/tests/state-op-codes.spec.ts b/tests/state-op-codes.spec.ts index 938c6fb..8e8a29b 100644 --- a/tests/state-op-codes.spec.ts +++ b/tests/state-op-codes.spec.ts @@ -12,7 +12,7 @@ import { AccountCls } from '../src/impl/account' import { InnerTxn } from '../src/impl/itxn' import { ApplicationTransaction } from '../src/impl/transactions' import { DeliberateAny } from '../src/typescript-helpers' -import { asBigInt, asNumber, asUint64Cls } from '../src/util' +import { asBigInt, asNumber, asUint64Cls, asUint8Array } from '../src/util' import { AppExpectingEffects } from './artifacts/created-app-asset/contract.algo' import { ItxnDemoContract, @@ -43,7 +43,6 @@ import { getLocalNetDefaultAccount, INITIAL_BALANCE_MICRO_ALGOS, } from './avm-invoker' -import { asUint8Array } from './util' describe('State op codes', async () => { const ctx = new TestExecutionContext() diff --git a/tests/util.ts b/tests/util.ts index ae307dc..37c5e6f 100644 --- a/tests/util.ts +++ b/tests/util.ts @@ -1,6 +1,6 @@ import { Bytes, bytes, internal } from '@algorandfoundation/algorand-typescript' import { createHash } from 'crypto' -import type { ABIValue } from './avm-invoker' +import { asUint8Array } from '../src/util' export const padUint8Array = (arr: Uint8Array, padSize: number): Uint8Array => { const paddedUint8Array = new Uint8Array(arr.length + padSize) @@ -8,9 +8,6 @@ export const padUint8Array = (arr: Uint8Array, padSize: number): Uint8Array => { return paddedUint8Array } -export const asUint8Array = (value: internal.primitives.StubBytesCompat): Uint8Array => - internal.primitives.BytesCls.fromCompat(value).asUint8Array() - export const base64Encode = (value: internal.primitives.StubBytesCompat): bytes => Bytes(Buffer.from(asUint8Array(value)).toString('base64')) @@ -28,16 +25,3 @@ export const getPaddedBytes = (padSize: number, value: internal.primitives.StubB export const intToBytes = (value: internal.primitives.StubBigUintCompat): internal.primitives.BytesCls => internal.primitives.BigUintCls.fromCompat(value).toBytes() - -export const abiAsBytes = (value: ABIValue) => { - if (Array.isArray(value) && value.every((i) => typeof i === 'number')) { - return Bytes(new Uint8Array(value)) - } - if (value instanceof Uint8Array) { - return Bytes(value) - } - if (typeof value === 'string') { - return Bytes(value) - } - throw new Error(`Value cannot be converted to bytes`) -} From 3b939fd54c4982208034f700460cfbb0bf3c0158 Mon Sep 17 00:00:00 2001 From: Bobby Lat Date: Fri, 3 Jan 2025 12:07:13 +0800 Subject: [PATCH 2/3] refactor: encode ZERO_ADDRESS without using algosdk --- examples/htlc-logicsig/signature.algo.ts | 5 ++--- examples/htlc-logicsig/signature.spec.ts | 6 ++---- examples/rollup.config.ts | 9 ++++++--- src/constants.ts | 3 +-- src/impl/account.ts | 2 +- src/impl/global.ts | 2 +- tests/avm-invoker.ts | 1 - 7 files changed, 13 insertions(+), 15 deletions(-) diff --git a/examples/htlc-logicsig/signature.algo.ts b/examples/htlc-logicsig/signature.algo.ts index df6cf1f..8c83506 100644 --- a/examples/htlc-logicsig/signature.algo.ts +++ b/examples/htlc-logicsig/signature.algo.ts @@ -1,11 +1,10 @@ import { Account, Bytes, Global, LogicSig, op, TransactionType, Txn, Uint64, uint64 } from '@algorandfoundation/algorand-typescript' -import algosdk from 'algosdk' export default class HashedTimeLockedLogicSig extends LogicSig { program(): boolean | uint64 { // Participants - const sellerAddress = Bytes(algosdk.decodeAddress('6ZHGHH5Z5CTPCF5WCESXMGRSVK7QJETR63M3NY5FJCUYDHO57VTCMJOBGY').publicKey) - const buyerAddress = Bytes(algosdk.decodeAddress('7Z5PWO2C6LFNQFGHWKSK5H47IQP5OJW2M3HA2QPXTY3WTNP5NU2MHBW27M').publicKey) + const sellerAddress = Bytes.fromBase32('6ZHGHH5Z5CTPCF5WCESXMGRSVK7QJETR63M3NY5FJCUYDHO57VTC') + const buyerAddress = Bytes.fromBase32('7Z5PWO2C6LFNQFGHWKSK5H47IQP5OJW2M3HA2QPXTY3WTNP5NU2M') const seller = Account(sellerAddress) const buyer = Account(buyerAddress) diff --git a/examples/htlc-logicsig/signature.spec.ts b/examples/htlc-logicsig/signature.spec.ts index c9cab8f..d819b05 100644 --- a/examples/htlc-logicsig/signature.spec.ts +++ b/examples/htlc-logicsig/signature.spec.ts @@ -1,11 +1,9 @@ import { Account, Bytes } from '@algorandfoundation/algorand-typescript' import { TestExecutionContext } from '@algorandfoundation/algorand-typescript-testing' -import algosdk from 'algosdk' import { afterEach, describe, expect, it } from 'vitest' import HashedTimeLockedLogicSig from './signature.algo' -const ZERO_ADDRESS_B32 = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ' -const ZERO_ADDRESS = Bytes.fromBase32(ZERO_ADDRESS_B32) +const ZERO_ADDRESS = Bytes.fromBase32('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA') describe('HTLC LogicSig', () => { const ctx = new TestExecutionContext() @@ -15,7 +13,7 @@ describe('HTLC LogicSig', () => { }) it('seller receives payment if correct secret is provided', () => { - const receiverAddress = Bytes(algosdk.decodeAddress('6ZHGHH5Z5CTPCF5WCESXMGRSVK7QJETR63M3NY5FJCUYDHO57VTCMJOBGY').publicKey) + const receiverAddress = Bytes.fromBase32('6ZHGHH5Z5CTPCF5WCESXMGRSVK7QJETR63M3NY5FJCUYDHO57VTC') ctx.txn .createScope([ ctx.any.txn.payment({ diff --git a/examples/rollup.config.ts b/examples/rollup.config.ts index d16a189..4aa1a7a 100644 --- a/examples/rollup.config.ts +++ b/examples/rollup.config.ts @@ -6,14 +6,17 @@ import { puyaTsTransformer } from '../src/test-transformer' const config: RollupOptions = { input: [ + 'examples/auction/contract.algo.ts', 'examples/calculator/contract.algo.ts', 'examples/hello-world-abi/contract.algo.ts', 'examples/hello-world/contract.algo.ts', - 'examples/auction/contract.algo.ts', - 'examples/voting/contract.algo.ts', + 'examples/htlc-logicsig/signature.algo.ts', + 'examples/precompiled/contract.algo.ts', + 'examples/scratch-storage/contract.algo.ts', 'examples/simple-voting/contract.algo.ts', + 'examples/tealscript/example.algo.ts', + 'examples/voting/contract.algo.ts', 'examples/zk-whitelist/contract.algo.ts', - 'examples/precompiled/contract.algo.ts', ], output: [ { diff --git a/src/constants.ts b/src/constants.ts index b218a66..20e9908 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -28,8 +28,7 @@ export const DEFAULT_GLOBAL_GENESIS_HASH = Bytes( ) // algorand encoded address of 32 zero bytes -export const ZERO_ADDRESS_B32 = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ' -export const ZERO_ADDRESS = Bytes.fromBase32(ZERO_ADDRESS_B32) +export const ZERO_ADDRESS = Bytes.fromBase32('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA') /** "\x09" # pragma version 9 diff --git a/src/impl/account.ts b/src/impl/account.ts index 0f5f67d..614d8a8 100644 --- a/src/impl/account.ts +++ b/src/impl/account.ts @@ -97,6 +97,6 @@ export class AccountCls extends BytesBackedCls implements Account { if (assetOrApp instanceof ApplicationCls) { return this.data.optedApplications.has(asUint64Cls(assetOrApp.id).asBigInt()) } - throw new internal.errors.InternalError('Invalid argument type. Must be an `algopy.Asset` or `algopy.Application` instance.') + throw new internal.errors.InternalError('Invalid argument type. Must be an `Asset` or `Application` instance.') } } diff --git a/src/impl/global.ts b/src/impl/global.ts index 5418937..393cc88 100644 --- a/src/impl/global.ts +++ b/src/impl/global.ts @@ -42,7 +42,7 @@ const getGlobalData = (): GlobalData => { } const getMissingValueErrorMessage = (name: keyof GlobalData) => - `'algopy.Global' object has no value set for attribute named '${name}'. Use \`context.ledger.patchGlobalData({${name}: your_value})\` to set the value in your test setup."` + `'Global' object has no value set for attribute named '${name}'. Use \`context.ledger.patchGlobalData({${name}: your_value})\` to set the value in your test setup."` export const Global: internal.opTypes.GlobalType = { /** diff --git a/tests/avm-invoker.ts b/tests/avm-invoker.ts index b54e858..844ff7c 100644 --- a/tests/avm-invoker.ts +++ b/tests/avm-invoker.ts @@ -90,7 +90,6 @@ export const generateAVMTestAccount = async (): Promise => { - // const account = generateAccount() const account = await generateAVMTestAccount() return Account(Bytes.fromBase32(account.addr.toString())) } From db3c6279c95fb0c2891b6a2ce49066ae53bf70d6 Mon Sep 17 00:00:00 2001 From: Bobby Lat Date: Fri, 3 Jan 2025 13:36:43 +0800 Subject: [PATCH 3/3] refactor: make parallel calls to avm in test to reduce wait time in tests --- tests/primitives/uint64.spec.ts | 6 ++--- tests/state-op-codes.spec.ts | 40 +++++++++++++++++++++------------ 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/tests/primitives/uint64.spec.ts b/tests/primitives/uint64.spec.ts index c5abea8..2d56dc9 100644 --- a/tests/primitives/uint64.spec.ts +++ b/tests/primitives/uint64.spec.ts @@ -1,13 +1,11 @@ import { AppSpec } from '@algorandfoundation/algokit-utils/types/app-spec' import { internal, uint64, Uint64 } from '@algorandfoundation/algorand-typescript' import { describe, expect, it } from 'vitest' -import { UINT64_OVERFLOW_UNDERFLOW_MESSAGE } from '../../src/constants' +import { MAX_UINT64, UINT64_OVERFLOW_UNDERFLOW_MESSAGE } from '../../src/constants' +import { asUint64 } from '../../src/util' import appSpecJson from '../artifacts/primitive-ops/data/PrimitiveOpsContract.arc32.json' import { getAlgorandAppClient, getAvmResult } from '../avm-invoker' -const MAX_UINT64 = 2n ** 64n - 1n -const asUint64 = (val: bigint | number) => (typeof val === 'bigint' ? Uint64(val) : Uint64(val)) - describe('Unit64', async () => { const appClient = await getAlgorandAppClient(appSpecJson as AppSpec) diff --git a/tests/state-op-codes.spec.ts b/tests/state-op-codes.spec.ts index 8e8a29b..84326de 100644 --- a/tests/state-op-codes.spec.ts +++ b/tests/state-op-codes.spec.ts @@ -52,8 +52,7 @@ describe('State op codes', async () => { }) describe('AcctParams', async () => { - const appClient = await getAlgorandAppClient(acctParamsAppSpecJson as AppSpec) - const dummyAccount = await generateTestAccount() + const [appClient, dummyAccount] = await Promise.all([getAlgorandAppClient(acctParamsAppSpecJson as AppSpec), generateTestAccount()]) test.each([ ['verify_acct_balance', INITIAL_BALANCE_MICRO_ALGOS + 100_000], @@ -100,8 +99,11 @@ describe('State op codes', async () => { }) describe('AppParams', async () => { - const [appClient, app] = await getAlgorandAppClientWithApp(appParamsAppSpecJson as AppSpec) - const dummyAccount = await getLocalNetDefaultAccount() + const [[appClient, app], dummyAccount] = await Promise.all([ + getAlgorandAppClientWithApp(appParamsAppSpecJson as AppSpec), + getLocalNetDefaultAccount(), + ]) + test.each([ ['verify_app_params_get_approval_program', undefined], ['verify_app_params_get_clear_state_program', undefined], @@ -142,8 +144,11 @@ describe('State op codes', async () => { }) describe('AssetHolding', async () => { - const appClient = await getAlgorandAppClient(assetHoldingAppSpecJson as AppSpec) - const dummyAccount = await getLocalNetDefaultAccount() + const [appClient, dummyAccount] = await Promise.all([ + getAlgorandAppClient(assetHoldingAppSpecJson as AppSpec), + getLocalNetDefaultAccount(), + ]) + test.each([ ['verify_asset_holding_get', 100], ['verify_asset_frozen_get', false], @@ -174,8 +179,10 @@ describe('State op codes', async () => { }) describe('AssetParams', async () => { - const appClient = await getAlgorandAppClient(assetParamsAppSpecJson as AppSpec) - const dummyAccount = await getLocalNetDefaultAccount() + const [appClient, dummyAccount] = await Promise.all([ + getAlgorandAppClient(assetParamsAppSpecJson as AppSpec), + getLocalNetDefaultAccount(), + ]) test.each([ ['verify_asset_params_get_total', 100n], @@ -437,8 +444,11 @@ describe('State op codes', async () => { }) describe('AppGlobal', async () => { - const appClient = await getAlgorandAppClient(appGlobalAppSpecJson as AppSpec) - const [_exAppClient, exApp] = await getAlgorandAppClientWithApp(appGlobalExAppSpecJson as AppSpec) + const [appClient, [_exAppClient, exApp]] = await Promise.all([ + getAlgorandAppClient(appGlobalAppSpecJson as AppSpec), + getAlgorandAppClientWithApp(appGlobalExAppSpecJson as AppSpec), + ]) + it('should be able to put, get and delete app global state', async () => { const bytesKey = 'global_bytes' const uint64Key = 'global_uint64' @@ -510,10 +520,12 @@ describe('State op codes', async () => { }) describe('AppLocal', async () => { - const appClient = await getAlgorandAppClient(appLocalAppSpecJson as AppSpec) - const [exAppClient, exApp] = await getAlgorandAppClientWithApp(appLocalExAppSpecJson as AppSpec) - await tryOptIn(appClient) - await tryOptIn(exAppClient) + const [appClient, [exAppClient, exApp]] = await Promise.all([ + getAlgorandAppClient(appLocalAppSpecJson as AppSpec), + getAlgorandAppClientWithApp(appLocalExAppSpecJson as AppSpec), + ]) + + await Promise.all([tryOptIn(appClient), tryOptIn(exAppClient)]) it('should be able to put, get and delete app local state', async () => { const localNetAccount = await getLocalNetDefaultAccount()