AVM Opcodes
The coverage file provides a comprehensive list of all opcodes and their respective types, categorized as Mockable, Emulated, or Native within the algorand-typescript-testing package. This section highlights a subset of opcodes and types that typically require interaction with the test execution context.
Native opcodes are assumed to function as they do in the Algorand Virtual Machine, given their stateless nature. If you encounter issues with any Native opcodes, please raise an issue in the algorand-typescript-testing repo or contribute a PR following the Contributing guide.
import { TestExecutionContext } from '@algorandfoundation/algorand-typescript-testing';
// Create the context manager for snippets belowconst ctx = new TestExecutionContext();Implemented Types
Section titled “Implemented Types”These types are fully implemented in TypeScript and behave identically to their AVM counterparts:
1. Cryptographic Operations
Section titled “1. Cryptographic Operations”The following opcodes are demonstrated:
op.sha256op.keccak256op.ecdsaVerify
import { op } from '@algorandfoundation/algorand-typescript';
// SHA256 hashconst data = Bytes('Hello, World!');const hashed = op.sha256(data);
// Keccak256 hashconst keccakHashed = op.keccak256(data);
// ECDSA verificationconst messageHash = Bytes.fromHex( 'f809fd0aa0bb0f20b354c6b2f86ea751957a4e262a546bd716f34f69b9516ae1',);const sigR = Bytes.fromHex('18d96c7cda4bc14d06277534681ded8a94828eb731d8b842e0da8105408c83cf');const sigS = Bytes.fromHex('7d33c61acf39cbb7a1d51c7126f1718116179adebd31618c4604a1f03b5c274a');const pubkeyX = Bytes.fromHex('f8140e3b2b92f7cbdc8196bc6baa9ce86cf15c18e8ad0145d50824e6fa890264');const pubkeyY = Bytes.fromHex('bd437b75d6f1db67155a95a0da4b41f2b6b3dc5d42f7db56238449e404a6c0a3');
const result = op.ecdsaVerify(op.Ecdsa.Secp256r1, messageHash, sigR, sigS, pubkeyX, pubkeyY);expect(result).toBe(true);2. Arithmetic and Bitwise Operations
Section titled “2. Arithmetic and Bitwise Operations”The following opcodes are demonstrated:
op.addwop.bitLengthop.getBitop.setBit
import { op, Uint64 } from '@algorandfoundation/algorand-typescript';
// Addition with carryconst [result, carry] = op.addw(Uint64(2n ** 63n), Uint64(2n ** 63n));
// Bitwise operationsconst value = Uint64(42);const bitLength = op.bitLength(value);const isBitSet = op.getBit(value, 3);const newValue = op.setBit(value, 2, 1);For a comprehensive list of all opcodes and types, refer to the coverage page.
Emulated Types Requiring Transaction Context
Section titled “Emulated Types Requiring Transaction Context”These types necessitate interaction with the transaction context:
algopy.op.Global
Section titled “algopy.op.Global”import { TestExecutionContext } from '@algorandfoundation/algorand-typescript-testing';import { op, arc4, uint64, Uint64 } from '@algorandfoundation/algorand-typescript';import { TestExecutionContext } from '@algorandfoundation/algorand-typescript-testing';
class MyContract extends arc4.Contract { @arc4.abimethod() checkGlobals(): uint64 { return op.Global.minTxnFee + op.Global.minBalance; }}
// Create the context manager for snippets belowconst ctx = new TestExecutionContext();ctx.ledger.patchGlobalData({ minTxnFee: 1000, minBalance: 100000,});
const contract = ctx.contract.create(MyContract);const result = contract.checkGlobals();expect(result).toEqual(101000);algopy.op.Txn
Section titled “algopy.op.Txn”import { op, arc4 } from '@algorandfoundation/algorand-typescript';import { TestExecutionContext } from '@algorandfoundation/algorand-typescript-testing';
class MyContract extends arc4.Contract { @arc4.abimethod() checkTxnFields(): arc4.Address { return new arc4.Address(op.Txn.sender); }}
// Create the context manager for snippets belowconst ctx = new TestExecutionContext();
const contract = ctx.contract.create(MyContract);const customSender = ctx.any.account();ctx.txn.createScope([ctx.any.txn.applicationCall({ sender: customSender })]).execute(() => { const result = contract.checkTxnFields(); expect(result).toEqual(customSender);});algopy.op.AssetHoldingGet
Section titled “algopy.op.AssetHoldingGet”import { Account, arc4, Asset, op, uint64, Uint64 } from '@algorandfoundation/algorand-typescript';import { TestExecutionContext } from '@algorandfoundation/algorand-typescript-testing';
class AssetContract extends arc4.Contract { @arc4.abimethod() checkAssetHolding(account: Account, asset: Asset): uint64 { const [balance, _] = op.AssetHolding.assetBalance(account, asset); return balance; }}
// Create the context manager for snippets belowconst ctx = new TestExecutionContext();
const contract = ctx.contract.create(AssetContract);const asset = ctx.any.asset({ total: 1000000 });const account = ctx.any.account({ optedAssetBalances: new Map([[asset.id, Uint64(5000)]]) });
const result = contract.checkAssetHolding(account, asset);expect(result).toEqual(5000);algopy.op.AppGlobal
Section titled “algopy.op.AppGlobal”import { arc4, bytes, Bytes, op, uint64, Uint64 } from '@algorandfoundation/algorand-typescript';import { TestExecutionContext } from '@algorandfoundation/algorand-typescript-testing';
class StateContract extends arc4.Contract { @arc4.abimethod() setAndGetState(key: bytes, value: uint64): uint64 { op.AppGlobal.put(key, value); return op.AppGlobal.getUint64(key); }}
// Create the context manager for snippets belowconst ctx = new TestExecutionContext();
const contract = ctx.contract.create(StateContract);const key = Bytes('test_key');const value = Uint64(42);const result = contract.setAndGetState(key, value);expect(result).toEqual(value);
const [storedValue, _] = ctx.ledger.getGlobalState(contract, key);expect(storedValue?.value).toEqual(42);algopy.op.Block
Section titled “algopy.op.Block”import { arc4, bytes, op } from '@algorandfoundation/algorand-typescript';import { TestExecutionContext } from '@algorandfoundation/algorand-typescript-testing';
class BlockInfoContract extends arc4.Contract { @arc4.abimethod() getBlockSeed(): bytes { return op.Block.blkSeed(1000); }}// Create the context manager for snippets belowconst ctx = new TestExecutionContext();
const contract = ctx.contract.create(BlockInfoContract);ctx.ledger.patchBlockData(1000, { seed: op.itob(123456), timestamp: 1625097600 });
const seed = contract.getBlockSeed();expect(seed).toEqual(op.itob(123456));algopy.op.AcctParamsGet
Section titled “algopy.op.AcctParamsGet”import type { Account, uint64 } from '@algorandfoundation/algorand-typescript';import { arc4, assert, op, Uint64 } from '@algorandfoundation/algorand-typescript';import { TestExecutionContext } from '@algorandfoundation/algorand-typescript-testing';
class AccountParamsContract extends arc4.Contract { @arc4.abimethod() getAccountBalance(account: Account): uint64 { const [balance, exists] = op.AcctParams.acctBalance(account); assert(exists); return balance; }}// Create the context manager for snippets belowconst ctx = new TestExecutionContext();
const contract = ctx.contract.create(AccountParamsContract);const account = ctx.any.account({ balance: 1000000 });
const balance = contract.getAccountBalance(account);expect(balance).toEqual(Uint64(1000000));algopy.op.AppParamsGet
Section titled “algopy.op.AppParamsGet”import type { Application } from '@algorandfoundation/algorand-typescript';import { arc4, assert, op } from '@algorandfoundation/algorand-typescript';import { TestExecutionContext } from '@algorandfoundation/algorand-typescript-testing';
class AppParamsContract extends arc4.Contract { @arc4.abimethod() getAppCreator(appId: Application): arc4.Address { const [creator, exists] = op.AppParams.appCreator(appId); assert(exists); return new arc4.Address(creator); }}// Create the context manager for snippets belowconst ctx = new TestExecutionContext();
const contract = ctx.contract.create(AppParamsContract);const app = ctx.any.application();const creator = contract.getAppCreator(app);expect(creator).toEqual(ctx.defaultSender);algopy.op.AssetParamsGet
Section titled “algopy.op.AssetParamsGet”import type { uint64 } from '@algorandfoundation/algorand-typescript';import { arc4, assert, op } from '@algorandfoundation/algorand-typescript';import { TestExecutionContext } from '@algorandfoundation/algorand-typescript-testing';
class AssetParamsContract extends arc4.Contract { @arc4.abimethod() getAssetTotal(assetId: uint64): uint64 { const [total, exists] = op.AssetParams.assetTotal(assetId); assert(exists); return total; }}// Create the context manager for snippets belowconst ctx = new TestExecutionContext();
const contract = ctx.contract.create(AssetParamsContract);const asset = ctx.any.asset({ total: 1000000, decimals: 6 });const total = contract.getAssetTotal(asset.id);expect(total).toEqual(1000000);algopy.op.Box
Section titled “algopy.op.Box”import type { bytes } from '@algorandfoundation/algorand-typescript';import { arc4, assert, Bytes, op } from '@algorandfoundation/algorand-typescript';import { TestExecutionContext } from '@algorandfoundation/algorand-typescript-testing';
class BoxStorageContract extends arc4.Contract { @arc4.abimethod() storeAndRetrieve(key: bytes, value: bytes): bytes { op.Box.put(key, value); const [retrievedValue, exists] = op.Box.get(key); assert(exists); return retrievedValue; }}// Create the context manager for snippets belowconst ctx = new TestExecutionContext();const contract = ctx.contract.create(BoxStorageContract);
const key = Bytes('test_key');const value = Bytes('test_value');
const result = contract.storeAndRetrieve(key, value);expect(result).toEqual(value);
const storedValue = ctx.ledger.getBox(contract, key);expect(storedValue).toEqual(value);algopy.compile_contract
Section titled “algopy.compile_contract”import { arc4, compile, uint64 } from '@algorandfoundation/algorand-typescript';import { TestExecutionContext } from '@algorandfoundation/algorand-typescript-testing';
class MockContract extends arc4.Contract {}
class ContractFactory extends arc4.Contract { @arc4.abimethod() compileAndGetBytes(): uint64 { const contractResponse = compile(MockContract); return compiled.localBytes; }}// Create the context manager for snippets belowconst ctx = new TestExecutionContext();
const contract = ctx.contract.create(ContractFactory);const mockApp = ctx.any.application({ localNumBytes: 4 });ctx.setCompiledApp(MockContract, mockApp.id);
const result = contract.compileAndGetBytes();expect(result).toBe(4);Mockable Opcodes
Section titled “Mockable Opcodes”These opcodes are mockable in algorand-typescript-testing, allowing for controlled testing of complex operations. Note that the module being mocked is @algorandfoundation/algorand-typescript-testing/internal which holds the stub implementations of algorand-typescript functions to be executed in Node.js environment.
algopy.op.vrf_verify
Section titled “algopy.op.vrf_verify”import { expect, Mock, test, vi } from 'vitest';import { bytes, Bytes, op, VrfVerify } from '@algorandfoundation/algorand-typescript';
vi.mock( import('@algorandfoundation/algorand-typescript-testing/internal'), async importOriginal => { const mod = await importOriginal(); return { ...mod, op: { ...mod.op, vrfVerify: vi.fn(), }, }; },);
test('mock vrfVerify', () => { const mockedVrfVerify = op.vrfVerify as Mock<typeof op.vrfVerify>; const mockResult = [Bytes('mock_output'), true] as readonly [bytes, boolean]; mockedVrfVerify.mockReturnValue(mockResult); const result = op.vrfVerify( VrfVerify.VrfAlgorand, Bytes('proof'), Bytes('message'), Bytes('public_key'), );
expect(result).toEqual(mockResult);});algopy.op.EllipticCurve
Section titled “algopy.op.EllipticCurve”import { expect, Mock, test, vi } from 'vitest';import { Bytes, op } from '@algorandfoundation/algorand-typescript';
vi.mock( import('@algorandfoundation/algorand-typescript-testing/internal'), async importOriginal => { const mod = await importOriginal(); return { ...mod, op: { ...mod.op, EllipticCurve: { ...mod.op.EllipticCurve, add: vi.fn(), }, }, }; },);test('mock EllipticCurve', () => { const mockedEllipticCurveAdd = op.EllipticCurve.add as Mock<typeof op.EllipticCurve.add>; const mockResult = Bytes('mock_output'); mockedEllipticCurveAdd.mockReturnValue(mockResult);
const result = op.EllipticCurve.add(op.Ec.BN254g1, Bytes('A'), Bytes('B')); expect(result).toEqual(mockResult);});These examples demonstrate how to mock key mockable opcodes in algorand-typescript-testing. Use similar techniques (in your preferred testing framework) for other mockable opcodes like mimc, and JsonRef.
Mocking these opcodes allows you to:
- Control complex operations’ behavior not covered by implemented and emulated types.
- Test edge cases and error conditions.
- Isolate contract logic from external dependencies.
// test cleanupctx.reset();