diff --git a/.gitignore b/.gitignore index f877f0b0..c82eea8a 100644 --- a/.gitignore +++ b/.gitignore @@ -66,3 +66,6 @@ __pycache__/ env/ venv/ ENV/ + +# Polytest (temporary files until polytest branch merged to main) +.polytest_algokit-polytest/ \ No newline at end of file diff --git a/algokit-configs/openapi-converter/specs/algod.oas3.json b/algokit-configs/openapi-converter/specs/algod.oas3.json index 629768e8..652da26e 100644 --- a/algokit-configs/openapi-converter/specs/algod.oas3.json +++ b/algokit-configs/openapi-converter/specs/algod.oas3.json @@ -4054,9 +4054,7 @@ "description": "base64 encoded program bytes" }, "sourcemap": { - "type": "object", - "properties": {}, - "description": "JSON of the source map" + "$ref": "#/components/schemas/SourceMap" } } } @@ -4695,8 +4693,7 @@ "id", "network", "proto", - "rwd", - "timestamp" + "rwd" ], "type": "object", "properties": { @@ -4994,6 +4991,7 @@ "type": "integer", "description": "unique asset identifier", "x-go-type": "basics.AssetIndex", + "x-algokit-field-rename": "id", "x-algokit-bigint": true }, "params": { @@ -6551,6 +6549,39 @@ } }, "description": "Proof of transaction in a block." + }, + "SourceMap": { + "type": "object", + "required": [ + "version", + "sources", + "names", + "mappings" + ], + "properties": { + "version": { + "type": "integer" + }, + "sources": { + "description": "A list of original sources used by the \"mappings\" entry.", + "type": "array", + "items": { + "type": "string" + } + }, + "names": { + "description": "A list of symbol names used by the \"mappings\" entry.", + "type": "array", + "items": { + "type": "string" + } + }, + "mappings": { + "description": "A string with the encoded mapping data.", + "type": "string" + } + }, + "description": "Source map for the program" } }, "responses": { @@ -7333,9 +7364,7 @@ "description": "base64 encoded program bytes" }, "sourcemap": { - "type": "object", - "properties": {}, - "description": "JSON of the source map" + "$ref": "#/components/schemas/SourceMap" } } } diff --git a/algokit-configs/openapi-converter/specs/indexer.oas3.json b/algokit-configs/openapi-converter/specs/indexer.oas3.json index 9573accc..da9b30cb 100644 --- a/algokit-configs/openapi-converter/specs/indexer.oas3.json +++ b/algokit-configs/openapi-converter/specs/indexer.oas3.json @@ -3587,6 +3587,7 @@ "index": { "type": "integer", "description": "unique asset identifier", + "x-algokit-field-rename": "id", "x-algokit-bigint": true }, "deleted": { diff --git a/oas-generator/src/oas_generator/generator/models.py b/oas-generator/src/oas_generator/generator/models.py index c12d28db..78f9752b 100644 --- a/oas-generator/src/oas_generator/generator/models.py +++ b/oas-generator/src/oas_generator/generator/models.py @@ -122,6 +122,8 @@ class FieldDescriptor: is_signed_txn: bool is_optional: bool is_nullable: bool + inline_object_schema: dict | None = None + inline_meta_name: str | None = None @dataclass diff --git a/oas-generator/src/oas_generator/generator/template_engine.py b/oas-generator/src/oas_generator/generator/template_engine.py index 5fdc0a0d..5866d69d 100644 --- a/oas-generator/src/oas_generator/generator/template_engine.py +++ b/oas-generator/src/oas_generator/generator/template_engine.py @@ -199,6 +199,8 @@ def _build_model_descriptor(self, name: str, schema: Schema, all_schemas: Schema signed_txn = False bytes_flag = False bigint_flag = False + inline_object_schema = None + if is_array and isinstance(items, dict): if "$ref" in items: ref_model = ts_pascal_case(items["$ref"].split("/")[-1]) @@ -209,15 +211,31 @@ def _build_model_descriptor(self, name: str, schema: Schema, all_schemas: Schema else: if "$ref" in (prop_schema or {}): ref_model = ts_pascal_case(prop_schema["$ref"].split("/")[-1]) - fmt = prop_schema.get(constants.SchemaKey.FORMAT) - bytes_flag = fmt == "byte" or prop_schema.get(constants.X_ALGOKIT_BYTES_BASE64) is True - bigint_flag = bool(prop_schema.get(constants.X_ALGOKIT_BIGINT) is True) - signed_txn = bool(prop_schema.get(constants.X_ALGOKIT_SIGNED_TXN) is True) + # Check for special codec flags first + elif bool(prop_schema.get(constants.X_ALGOKIT_SIGNED_TXN) is True): + signed_txn = True + # For inline nested objects, store the schema for inline metadata generation + elif (prop_schema.get(constants.SchemaKey.TYPE) == "object" and + "properties" in prop_schema and + "$ref" not in prop_schema and + prop_schema.get(constants.X_ALGOKIT_SIGNED_TXN) is not True): + # Store the inline object schema for metadata generation + inline_object_schema = prop_schema + else: + fmt = prop_schema.get(constants.SchemaKey.FORMAT) + bytes_flag = fmt == "byte" or prop_schema.get(constants.X_ALGOKIT_BYTES_BASE64) is True + bigint_flag = bool(prop_schema.get(constants.X_ALGOKIT_BIGINT) is True) + signed_txn = bool(prop_schema.get(constants.X_ALGOKIT_SIGNED_TXN) is True) is_optional = prop_name not in required_fields # Nullable per OpenAPI is_nullable = bool(prop_schema.get(constants.SchemaKey.NULLABLE) is True) + # Generate inline metadata name for nested objects + inline_meta_name = None + if inline_object_schema: + inline_meta_name = f"{model_name}{ts_pascal_case(canonical)}Meta" + fields.append( FieldDescriptor( name=name_camel, @@ -230,6 +248,8 @@ def _build_model_descriptor(self, name: str, schema: Schema, all_schemas: Schema is_signed_txn=signed_txn, is_optional=is_optional, is_nullable=is_nullable, + inline_object_schema=inline_object_schema, + inline_meta_name=inline_meta_name, ) ) @@ -855,56 +875,27 @@ def generate( if ts_pascal_case(name) in all_used_types} - # Generate components (only used schemas) files.update(self.schema_processor.generate_models(output_dir, used_schemas)) if service_class == "AlgodApi": models_dir = output_dir / constants.DirectoryName.SRC / constants.DirectoryName.MODELS - # Add SuggestedParams custom model + # Generate the custom typed models files[models_dir / "suggested-params.ts"] = self.renderer.render( - "models/transaction-params/suggested-params.ts.j2", - {"spec": spec}, - ) - - # Custom typed block models - # Block-specific models (prefixed to avoid shape collisions) - files[models_dir / "block-eval-delta.ts"] = self.renderer.render( - "models/block/block-eval-delta.ts.j2", - {"spec": spec}, - ) - files[models_dir / "block-state-delta.ts"] = self.renderer.render( - "models/block/block-state-delta.ts.j2", - {"spec": spec}, - ) - files[models_dir / "block-account-state-delta.ts"] = self.renderer.render( - "models/block/block-account-state-delta.ts.j2", - {"spec": spec}, - ) - # BlockAppEvalDelta is implemented by repurposing application-eval-delta.ts.j2 to new name - files[models_dir / "block-app-eval-delta.ts"] = self.renderer.render( - "models/block/application-eval-delta.ts.j2", - {"spec": spec}, - ) - files[models_dir / "block_state_proof_tracking_data.ts"] = self.renderer.render( - "models/block/block-state-proof-tracking-data.ts.j2", - {"spec": spec}, - ) - files[models_dir / "block_state_proof_tracking.ts"] = self.renderer.render( - "models/block/block-state-proof-tracking.ts.j2", - {"spec": spec}, - ) - files[models_dir / "signed-txn-in-block.ts"] = self.renderer.render( - "models/block/signed-txn-in-block.ts.j2", + "models/custom/suggested-params.ts.j2", {"spec": spec}, ) files[models_dir / "block.ts"] = self.renderer.render( - "models/block/block.ts.j2", + "models/custom/block.ts.j2", {"spec": spec}, ) files[models_dir / "get-block.ts"] = self.renderer.render( - "models/block/get-block.ts.j2", + "models/custom/get-block.ts.j2", + {"spec": spec}, + ) + files[models_dir / "ledger-state-delta.ts"] = self.renderer.render( + "models/custom/ledger-state-delta.ts.j2", {"spec": spec}, ) @@ -914,22 +905,8 @@ def generate( extras = ( "\n" "export type { SuggestedParams, SuggestedParamsMeta } from './suggested-params';\n" - "export type { BlockEvalDelta } from './block-eval-delta';\n" - "export { BlockEvalDeltaMeta } from './block-eval-delta';\n" - "export type { BlockStateDelta } from './block-state-delta';\n" - "export { BlockStateDeltaMeta } from './block-state-delta';\n" - "export type { BlockAccountStateDelta } from './block-account-state-delta';\n" - "export { BlockAccountStateDeltaMeta } from './block-account-state-delta';\n" - "export type { BlockAppEvalDelta } from './block-app-eval-delta';\n" - "export { BlockAppEvalDeltaMeta } from './block-app-eval-delta';\n" - "export type { BlockStateProofTrackingData } from './block_state_proof_tracking_data';\n" - "export { BlockStateProofTrackingDataMeta } from './block_state_proof_tracking_data';\n" - "export type { BlockStateProofTracking } from './block_state_proof_tracking';\n" - "export { BlockStateProofTrackingMeta } from './block_state_proof_tracking';\n" "export type { Block } from './block';\n" "export { BlockMeta } from './block';\n" - "export type { SignedTxnInBlock } from './signed-txn-in-block';\n" - "export { SignedTxnInBlockMeta } from './signed-txn-in-block';\n" ) files[index_path] = base_index + extras files.update(self._generate_client_files(output_dir, client_class, service_class)) @@ -962,7 +939,6 @@ def _generate_runtime( core_dir / "fetch-http-request.ts": ("base/src/core/fetch-http-request.ts.j2", context), core_dir / "api-error.ts": ("base/src/core/api-error.ts.j2", context), core_dir / "request.ts": ("base/src/core/request.ts.j2", context), - core_dir / "serialization.ts": ("base/src/core/serialization.ts.j2", context), core_dir / "codecs.ts": ("base/src/core/codecs.ts.j2", context), core_dir / "model-runtime.ts": ("base/src/core/model-runtime.ts.j2", context), # Project files diff --git a/oas-generator/src/oas_generator/templates/apis/service.ts.j2 b/oas-generator/src/oas_generator/templates/apis/service.ts.j2 index a262320f..3bd6fee0 100644 --- a/oas-generator/src/oas_generator/templates/apis/service.ts.j2 +++ b/oas-generator/src/oas_generator/templates/apis/service.ts.j2 @@ -14,7 +14,7 @@ import { {% for t in sorted %}{{ t }}Meta{% if not loop.last %}, {% endif %}{% e {% macro field_type_meta(type_name) -%} {%- if type_name in import_types -%} -({ kind: 'model', meta: () => {{ type_name }}Meta } as const) +({ kind: 'model', meta: {{ type_name }}Meta } as const) {%- elif type_name == 'SignedTransaction' -%} ({ kind: 'codec', codecKey: 'SignedTransaction' } as const) {%- elif type_name == 'Uint8Array' -%} @@ -105,8 +105,8 @@ export class {{ service_class_name }} { {%- endif %} ): Promise<{{ op.responseTsType }}> { const headers: Record = {}; - {% set supports_msgpack = op.returnsMsgpack or (op.requestBody and op.requestBody.supportsMsgpack) %} - const responseFormat: BodyFormat = {% if op.forceMsgpackQuery %}'msgpack'{% elif supports_msgpack %}'json'{% else %}'json'{% endif %}; + {% set body_format = 'msgpack' if op.forceMsgpackQuery else 'json' %} + const responseFormat: BodyFormat = '{{ body_format }}' headers['Accept'] = {{ service_class_name }}.acceptFor(responseFormat); {% if op.requestBody and op.method.upper() not in ['GET', 'HEAD'] %} @@ -118,9 +118,11 @@ export class {{ service_class_name }} { const bodyMeta = {{ meta_expr(op.requestBody.tsType) }}; const mediaType = bodyMeta ? {{ service_class_name }}.mediaFor(responseFormat) : undefined; if (mediaType) headers['Content-Type'] = mediaType; - const serializedBody = bodyMeta && body !== undefined - ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) - : body; + {% if op.requestBody and not meta_expr(op.requestBody.tsType) == 'undefined' %} + const serializedBody = body ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : undefined; + {% else %} + const serializedBody = body; + {% endif %} {% endif %} {% endif %} @@ -132,7 +134,11 @@ export class {{ service_class_name }} { } {% endif %} - const payload = await this.httpRequest.request({ + {% if op.responseTsType == 'void' %} + await this.httpRequest.request({ + {% else %} + const payload = await this.httpRequest.request<{{'Uint8Array' if body_format == 'msgpack' else 'string'}}>({ + {% endif %} method: '{{ op.method }}', url: '{{ op.path }}', path: { @@ -158,11 +164,13 @@ export class {{ service_class_name }} { {% endif %} }); - const responseMeta = {{ meta_expr(op.responseTsType) }}; - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat); - } - return payload as {{ op.responseTsType }}; + {% if op.responseTsType != 'void' %} + {% if meta_expr(op.responseTsType) == 'undefined' %} + return payload; + {% else %} + return AlgorandSerializer.decode(payload, {{ meta_expr(op.responseTsType) }}, responseFormat); + {% endif %} + {% endif %} } {% endfor %} diff --git a/oas-generator/src/oas_generator/templates/base/src/core/codecs.ts.j2 b/oas-generator/src/oas_generator/templates/base/src/core/codecs.ts.j2 index 35549be3..d500c6b6 100644 --- a/oas-generator/src/oas_generator/templates/base/src/core/codecs.ts.j2 +++ b/oas-generator/src/oas_generator/templates/base/src/core/codecs.ts.j2 @@ -1,42 +1,28 @@ import { decode as msgpackDecode, encode as msgpackEncode } from 'algorand-msgpack' -export function encodeMsgPack(data: T): Uint8Array { +export function encodeMsgPack(data: ApiData): Uint8Array { return new Uint8Array(msgpackEncode(data, { sortKeys: true, ignoreUndefined: true })); } -export function decodeMsgPack(buffer: Uint8Array): T { - const map = msgpackDecode(buffer, { useMap: true }) as unknown; - return mapToObject(map) as T; +type MsgPackDecodeOptions = { + useMap: boolean; + rawBinaryStringKeys: boolean; + rawBinaryStringValues: boolean; } -/** - * Converts a Map structure from msgpack decoding to a plain object structure. - * Maps are converted to objects recursively, except for the special case - * where the field name is "r" which remains as a Map. - */ -function mapToObject(value: unknown, fieldName?: string): unknown { - // Preserve Uint8Array as-is - if (value instanceof Uint8Array) { - return value; - } else if (value instanceof Map) { - // Special case: keep "r" field as Map - if (fieldName === 'r') { - const newMap = new Map(); - for (const [k, v] of value.entries()) { - newMap.set(k, mapToObject(v)); - } - return newMap; - } - - // Convert Map to object - const obj: Record = {}; - for (const [k, v] of value.entries()) { - obj[k] = mapToObject(v, k); - } - return obj; - } else if (Array.isArray(value)) { - return value.map((item) => mapToObject(item)); - } - - return value; +export function decodeMsgPack( + buffer: Uint8Array, + options: MsgPackDecodeOptions = { useMap: true, rawBinaryStringKeys: true, rawBinaryStringValues: true }, +): Map { + return msgpackDecode(buffer, options) as Map; } +export type ApiData = + | null + | undefined + | string + | number + | bigint + | boolean + | Uint8Array + | object + | Map // TODO: NC - Do we ever have a string key? diff --git a/oas-generator/src/oas_generator/templates/base/src/core/model-runtime.ts.j2 b/oas-generator/src/oas_generator/templates/base/src/core/model-runtime.ts.j2 index dde27e9d..649ff070 100644 --- a/oas-generator/src/oas_generator/templates/base/src/core/model-runtime.ts.j2 +++ b/oas-generator/src/oas_generator/templates/base/src/core/model-runtime.ts.j2 @@ -1,19 +1,24 @@ import { - encodeSignedTransaction as transactEncodeSignedTransaction, - decodeSignedTransaction as transactDecodeSignedTransaction, + addressFromPublicKey, + decodedTransactionMapToObject, + fromSignedTransactionDto, + toSignedTransactionDto, type SignedTransaction, } from '@algorandfoundation/algokit-transact'; -import { encodeMsgPack, decodeMsgPack } from './codecs'; -import { toBase64, fromBase64 } from './serialization'; +import { Buffer } from 'buffer'; +import { ApiData, decodeMsgPack, encodeMsgPack } from './codecs'; export type BodyFormat = 'json' | 'msgpack' | 'map'; export interface ScalarFieldType { readonly kind: 'scalar'; + // TODO: NC - Make this a type field readonly isBytes?: boolean; readonly isBigint?: boolean; + readonly isAddress?: boolean; } +// TODO: NC - Needs to be renamed export interface CodecFieldType { readonly kind: 'codec'; readonly codecKey: string; @@ -34,7 +39,13 @@ export interface RecordFieldType { readonly value: FieldType; } -export type FieldType = ScalarFieldType | CodecFieldType | ModelFieldType | ArrayFieldType | RecordFieldType; +export interface MapFieldType { + readonly kind: 'map'; + readonly keyType: 'number' | 'bigint' | 'bytes'; + readonly value: FieldType; +} + +export type FieldType = ScalarFieldType | CodecFieldType | ModelFieldType | ArrayFieldType | RecordFieldType | MapFieldType; export interface FieldMetadata { readonly name: string; @@ -61,39 +72,22 @@ export interface ModelMetadata { readonly passThrough?: FieldType; } -// Registry for model metadata to avoid direct circular imports between model files -const modelMetaRegistry = new Map(); - -export function registerModelMeta(name: string, meta: ModelMetadata): void { - modelMetaRegistry.set(name, meta); -} - -export function getModelMeta(name: string): ModelMetadata { - const meta = modelMetaRegistry.get(name); - if (!meta) throw new Error(`Model metadata not registered: ${name}`); - return meta; -} - -export interface TypeCodec { - encode(value: TValue, format: BodyFormat): unknown; - decode(value: unknown, format: BodyFormat): TValue; +export interface EncodeableTypeConverter> { + beforeEncoding(value: T, format: BodyFormat): Record; + afterDecoding(decoded: Record | Map, format: BodyFormat): T; } -const codecRegistry = new Map>(); - -export function registerCodec(key: string, codec: TypeCodec): void { - codecRegistry.set(key, codec as TypeCodec); -} +const encodeableTypeConverterRegistry = new Map>>(); -export function getCodec(key: string): TypeCodec | undefined { - return codecRegistry.get(key) as TypeCodec | undefined; +export function registerEncodeableTypeConverter(key: string, codec: EncodeableTypeConverter>): void { + encodeableTypeConverterRegistry.set(key, codec); } export class AlgorandSerializer { - static encode(value: unknown, meta: ModelMetadata, format: 'map'): Map - static encode(value: unknown, meta: ModelMetadata, format: 'json'): string - static encode(value: unknown, meta: ModelMetadata, format?: 'msgpack'): Uint8Array - static encode(value: unknown, meta: ModelMetadata, format: BodyFormat = 'msgpack'): Uint8Array | string | Map { + static encode(value: Record, meta: ModelMetadata, format: 'map'): Map + static encode(value: Record, meta: ModelMetadata, format: 'json'): string + static encode(value: Record, meta: ModelMetadata, format?: 'msgpack'): Uint8Array + static encode(value: Record, meta: ModelMetadata, format: BodyFormat = 'msgpack'): Uint8Array | string | Map { if (format === 'map') { // For map format, use msgpack transformation to preserve types like bigint, then convert to nested Maps const wire = this.transform(value, meta, { direction: 'encode', format: 'msgpack' }); @@ -107,25 +101,25 @@ export class AlgorandSerializer { return typeof wire === 'string' ? wire : JSON.stringify(wire); } - static decode(payload: unknown, meta: ModelMetadata, format: BodyFormat = 'msgpack'): T { - let wire: unknown = payload; + static decode(value: Uint8Array | string, meta: ModelMetadata, format: BodyFormat = 'msgpack'): T { + let wire: ApiData = value; if (format === 'msgpack') { - if (payload instanceof Uint8Array) { - wire = decodeMsgPack(payload); + if (value instanceof Uint8Array) { + wire = decodeMsgPack(value); } - } else if (typeof payload === 'string') { - wire = JSON.parse(payload); + } else if (typeof value === 'string') { + wire = JSON.parse(value); } return this.transform(wire, meta, { direction: 'decode', format }) as T; } - private static transform(value: unknown, meta: ModelMetadata, ctx: TransformContext): unknown { + private static transform(value: ApiData, meta: ModelMetadata, ctx: TransformContext): ApiData { if (value === undefined || value === null) { return value; } if (meta.codecKey) { - return this.applyCodec(value, meta.codecKey, ctx); + return this.applyEncodeableTypeConversion(value, meta.codecKey, ctx); } switch (meta.kind) { @@ -139,22 +133,20 @@ export class AlgorandSerializer { } } - private static transformObject(value: unknown, meta: ModelMetadata, ctx: TransformContext): unknown { + private static transformObject(value: ApiData, meta: ModelMetadata, ctx: TransformContext): ApiData { const fields = meta.fields ?? []; - const hasFlattenedSignedTxn = fields.some( - (f) => f.flattened && f.type.kind === 'codec' && f.type.codecKey === 'SignedTransaction', - ); + const hasFlattenedField = fields.some((f) => f.flattened); if (ctx.direction === 'encode') { - const src = value as Record; - const out: Record = {}; + const src = value as Record; + const out: Record = {}; for (const field of fields) { const fieldValue = src[field.name]; if (fieldValue === undefined) continue; const encoded = this.transformType(fieldValue, field.type, ctx); if (encoded === undefined && fieldValue === undefined) continue; - if (field.flattened && field.type.kind === 'codec' && field.type.codecKey === 'SignedTransaction') { - // Merge signed transaction map into parent - const mapValue = encoded as Record; + if (field.flattened) { + // Merge flattened field into parent + const mapValue = encoded as Record; for (const [k, v] of Object.entries(mapValue ?? {})) out[k] = v; continue; } @@ -169,66 +161,206 @@ export class AlgorandSerializer { return out; } - const src = value as Record; - const out: Record = {}; + // Decoding + const out: Record = {}; const fieldByWire = new Map(fields.filter((f) => !!f.wireKey).map((field) => [field.wireKey as string, field])); - for (const [wireKey, wireValue] of Object.entries(src)) { - const field = fieldByWire.get(wireKey); + // Build a map of wire keys for each flattened field + const flattenedFieldWireKeys = new Map>(); + if (hasFlattenedField) { + for (const field of fields) { + if (field.flattened && field.type.kind === 'model') { + const modelMeta = typeof field.type.meta === 'function' ? field.type.meta() : field.type.meta; + const wireKeys = this.collectWireKeys(modelMeta); + flattenedFieldWireKeys.set(field, wireKeys); + } + } + } + + const entries = value instanceof Map ? Array.from(value.entries()) : Object.entries(value as Record); + const unmatchedEntries = new Map(); + + for (const [key, wireValue] of entries) { + const wireKey = key instanceof Uint8Array ? Buffer.from(key).toString('utf-8') : key; + const isStringKey = typeof wireKey === 'string'; + const field = isStringKey ? fieldByWire.get(wireKey) : undefined; + if (field) { const decoded = this.transformType(wireValue, field.type, ctx); - out[field.name] = decoded; + out[field.name] = decoded === null && !field.nullable ? undefined : decoded; continue; } - if (meta.additionalProperties) { + + if (isStringKey && meta.additionalProperties) { out[wireKey] = this.transformType(wireValue, meta.additionalProperties, ctx); continue; } - // If we have a flattened SignedTransaction, skip unknown keys (e.g., 'sig', 'txn') - if (!hasFlattenedSignedTxn) { - out[wireKey] = wireValue; + + // Store unmatched entries for potential flattened field reconstruction + if (isStringKey) { + unmatchedEntries.set(wireKey, wireValue) } } - // If there are flattened fields, attempt to reconstruct them from remaining keys by decoding - for (const field of fields) { - if (out[field.name] !== undefined) continue; - if (field.flattened && field.type.kind === 'codec' && field.type.codecKey === 'SignedTransaction') { - // Reconstruct from entire object map - out[field.name] = this.applyCodec(src, 'SignedTransaction', ctx); + // Reconstruct flattened fields from unmatched entries + if (hasFlattenedField) { + for (const field of fields) { + if (out[field.name] !== undefined) continue; + if (field.flattened) { + if (field.type.kind === 'codec') { + // Reconstruct codec from entire object map + out[field.name] = this.applyEncodeableTypeConversion(value, field.type.codecKey, ctx); + } else if (field.type.kind === 'model') { + const modelMeta = typeof field.type.meta === 'function' ? field.type.meta() : field.type.meta; + + // Check if this flattened model contains nested flattened codecs + const hasNestedCodec = this.hasNestedFlattenedCodec(modelMeta); + + let decoded: ApiData; + if (hasNestedCodec) { + // If the model has nested flattened codecs, we need to pass the original value + // so the nested model can reconstruct its flattened codec fields + decoded = this.transform(value, modelMeta, ctx); + } else { + // Filter the wire data to only include keys belonging to this flattened model + const modelWireKeys = flattenedFieldWireKeys.get(field); + if (modelWireKeys) { + const filteredData: Record = {}; + for (const [k, v] of unmatchedEntries.entries()) { + if (modelWireKeys.has(k)) { + filteredData[k] = v; + } + } + // Also check if the original value is a Map and filter it + if (value instanceof Map) { + const filteredMap = new Map(); + for (const [k, v] of value.entries()) { + const keyStr = k instanceof Uint8Array ? Buffer.from(k).toString('utf-8') : String(k); + if (typeof keyStr === 'string' && modelWireKeys.has(keyStr)) { + filteredMap.set(k as string | Uint8Array, v); + } + } + decoded = this.transform(filteredMap, modelMeta, ctx); + } else { + decoded = this.transform(filteredData, modelMeta, ctx); + } + } else { + decoded = undefined; + } + } + + // If the field is optional and the decoded object is empty, set it to undefined + if (field.optional && decoded !== undefined && this.isEmptyObject(decoded)) { + out[field.name] = undefined; + } else { + out[field.name] = decoded; + } + } + } + } + } + + // Add any remaining unmatched entries if there are no flattened fields + if (!hasFlattenedField) { + for (const [k, v] of unmatchedEntries.entries()) { + out[k] = v; } } return out; } - private static transformType(value: unknown, type: FieldType, ctx: TransformContext): unknown { + private static collectWireKeys(meta: ModelMetadata): Set { + const wireKeys = new Set(); + if (meta.kind !== 'object' || !meta.fields) return wireKeys; + + for (const field of meta.fields) { + if (field.wireKey) { + wireKeys.add(field.wireKey); + } + if (field.flattened && field.type.kind === 'model') { + const childMeta = typeof field.type.meta === 'function' ? field.type.meta() : field.type.meta; + const childKeys = this.collectWireKeys(childMeta); + for (const key of childKeys) { + wireKeys.add(key); + } + } + // Note: flattened codec fields don't have predictable wire keys, + // so they need to be handled differently during reconstruction + } + + return wireKeys; + } + + private static hasNestedFlattenedCodec(meta: ModelMetadata): boolean { + if (meta.kind !== 'object' || !meta.fields) return false; + + for (const field of meta.fields) { + if (field.flattened) { + if (field.type.kind === 'codec') { + return true; + } + if (field.type.kind === 'model') { + const childMeta = typeof field.type.meta === 'function' ? field.type.meta() : field.type.meta; + if (this.hasNestedFlattenedCodec(childMeta)) { + return true; + } + } + } + } + + return false; + } + + private static isEmptyObject(value: ApiData): boolean { + if (value === null || value === undefined) return true; + if (typeof value !== 'object') return false; + if (Array.isArray(value)) return false; + if (value instanceof Uint8Array) return false; + if (value instanceof Map) return value.size === 0; + + // Check if it's a plain object with no own properties (excluding undefined values) + const keys = Object.keys(value); + if (keys.length === 0) return true; + + // Check if all properties are undefined + return keys.every((key) => (value as Record)[key] === undefined); + } + + private static transformType(value: ApiData, type: FieldType, ctx: TransformContext): ApiData { if (value === undefined || value === null) return value; switch (type.kind) { case 'scalar': return this.transformScalar(value, type, ctx); case 'codec': - return this.applyCodec(value, type.codecKey, ctx); + return this.applyEncodeableTypeConversion(value, type.codecKey, ctx); case 'model': return this.transform(value, typeof type.meta === 'function' ? type.meta() : type.meta, ctx); case 'array': if (!Array.isArray(value)) return value; return value.map((item) => this.transformType(item, type.item, ctx)); - case 'record': - if (typeof value !== 'object' || value === null) return value; + case 'record': { + if ((!(value instanceof Map) && typeof value !== 'object') || value === null) return value + const entries = value instanceof Map ? Array.from(value.entries()) : Object.entries(value as Record); return Object.fromEntries( - Object.entries(value as Record).map(([k, v]) => [k, this.transformType(v, type.value, ctx)]), + entries.map(([k, v]) => { + const key = k instanceof Uint8Array ? Buffer.from(k).toString('utf-8') : k; + return [key, this.transformType(v, type.value, ctx)]; + }), ); + } + case 'map': + return this.transformMap(value, type, ctx); default: return value; } } - private static transformScalar(value: unknown, meta: ScalarFieldType, ctx: TransformContext): unknown { + private static transformScalar(value: ApiData, meta: ScalarFieldType, ctx: TransformContext): ApiData { if (ctx.direction === 'encode') { if (meta.isBytes && ctx.format === 'json') { - if (value instanceof Uint8Array) return toBase64(value); + if (value instanceof Uint8Array) return Buffer.from(value).toString('base64'); } if (meta.isBigint && ctx.format === 'json') { if (typeof value === 'bigint') return value.toString(); @@ -239,7 +371,17 @@ export class AlgorandSerializer { } if (meta.isBytes && ctx.format === 'json' && typeof value === 'string') { - return fromBase64(value); + return new Uint8Array(Buffer.from(value, 'base64')); + } + + if (value instanceof Uint8Array) { + if (meta.isAddress) { + // TODO: NC - Fix all the address models to have this on it. + return addressFromPublicKey(value); + } else if (!meta.isBytes) { + return Buffer.from(value).toString('utf-8'); + } + return value; } if (meta.isBigint) { @@ -255,20 +397,61 @@ export class AlgorandSerializer { } } + if (value instanceof Map) { + const out: Record = {}; + for (const [k, v] of value.entries()) { + const key = k instanceof Uint8Array ? Buffer.from(k).toString('utf-8') : k.toString(); + out[key] = this.transformType(v, { kind: 'scalar', isBytes: v instanceof Uint8Array }, ctx); + } + return out; + } + + if (Array.isArray(value)) { + return value.map((item) => this.transformType(item, { kind: 'scalar', isBytes: item instanceof Uint8Array }, ctx)); + } + return value; } - private static applyCodec(value: unknown, codecKey: string, ctx: TransformContext): unknown { - const codec = codecRegistry.get(codecKey); + private static applyEncodeableTypeConversion(value: ApiData, typeKey: string, ctx: TransformContext): ApiData { + const codec = encodeableTypeConverterRegistry.get(typeKey); if (!codec) { - throw new Error(`Codec for "${codecKey}" is not registered`); + throw new Error(`Type converter for "${typeKey}" is not registered`); } - return ctx.direction === 'encode' - ? codec.encode(value, ctx.format) - : codec.decode(value, ctx.format); + + // TODO: NC - Need to properly guard against these conditions + if (ctx.direction === 'encode') { + if (value instanceof Map) { + throw new Error(`Cannot encode Map with type converter "${typeKey}"`); + } + return codec.beforeEncoding(value as Parameters[0], ctx.format); + } + + return codec.afterDecoding(value as Parameters[0], ctx.format); } - private static convertToNestedMaps(value: unknown): Map | unknown[] | unknown { + private static transformMap(value: ApiData, meta: MapFieldType, ctx: TransformContext): ApiData { + if (ctx.direction === 'encode') { + if (!(value instanceof Map)) return value; + const result = new Map() + for (const [k, v] of value.entries()) { + const transformedValue = this.transformType(v, meta.value, ctx); + result.set(k, transformedValue) + } + return result; + } + // Decoding + if ((!(value instanceof Map) && typeof value !== 'object') || value === null) return value; + const entries = value instanceof Map ? Array.from(value.entries()) : Object.entries(value as Record); + const result = new Map(); + for (const [k, v] of entries) { + const transformedValue = this.transformType(v, meta.value, ctx); + result.set(k, transformedValue); + } + return result; + } + + private static convertToNestedMaps(value: ApiData): Map | ApiData[] | ApiData { if (value === null || value === undefined) { return value; } @@ -286,8 +469,8 @@ export class AlgorandSerializer { } if (typeof value === 'object' && value !== null && !(value instanceof Uint8Array)) { - const map = new Map(); - Object.entries(value as Record).forEach(([key, val]) => { + const map = new Map(); + Object.entries(value as Record).forEach(([key, val]) => { map.set(key, this.convertToNestedMaps(val)); }); return map; @@ -305,42 +488,23 @@ interface TransformContext { readonly format: BodyFormat; } -const encodeSignedTransactionImpl = (value: unknown): Uint8Array => - transactEncodeSignedTransaction(value as SignedTransaction); -const decodeSignedTransactionImpl = (value: Uint8Array): SignedTransaction => - transactDecodeSignedTransaction(value); - -class SignedTransactionCodec implements TypeCodec { - encode(value: unknown, format: BodyFormat): unknown { - if (value == null) return value; +class SignedTransactionConverter implements EncodeableTypeConverter { + beforeEncoding(value: SignedTransaction, format: BodyFormat): Record { if (format === 'json') { - if (value instanceof Uint8Array) return toBase64(value); - return toBase64(encodeSignedTransactionImpl(value)); + throw new Error('JSON format not supported for SignedTransaction encoding'); } - if (value instanceof Uint8Array) { - // Already canonical bytes; decode to structured map so parent encoding keeps map semantics - return decodeMsgPack(value); - } - // Convert signed transaction object into canonical map representation - return decodeMsgPack(encodeSignedTransactionImpl(value)); + return toSignedTransactionDto(value); } - - decode(value: unknown, format: BodyFormat): unknown { - if (value == null) return value; - if (format === 'json') { - if (typeof value === 'string') return decodeSignedTransactionImpl(fromBase64(value)); - if (value instanceof Uint8Array) return decodeSignedTransactionImpl(value); - return value; + afterDecoding(value: Record | Map, format: BodyFormat): SignedTransaction { + if (format === 'json' || !(value instanceof Map)) { + throw new Error('JSON format not supported for SignedTransaction decoding'); } - if (value instanceof Uint8Array) return decodeSignedTransactionImpl(value); - // Value is a decoded map; re-encode to bytes before handing to transact decoder - try { - return decodeSignedTransactionImpl(encodeMsgPack(value)); - } catch { - return value; + if (!(value instanceof Map)) { + throw new Error('Invalid decoded msgpack format for SignedTransaction'); } + const stxnDto = decodedTransactionMapToObject(value) as Parameters[0]; + return fromSignedTransactionDto(stxnDto); } } -registerCodec('SignedTransaction', new SignedTransactionCodec()); - +registerEncodeableTypeConverter('SignedTransaction', new SignedTransactionConverter()); diff --git a/oas-generator/src/oas_generator/templates/base/src/core/request.ts.j2 b/oas-generator/src/oas_generator/templates/base/src/core/request.ts.j2 index 88aef710..a13e481d 100644 --- a/oas-generator/src/oas_generator/templates/base/src/core/request.ts.j2 +++ b/oas-generator/src/oas_generator/templates/base/src/core/request.ts.j2 @@ -88,7 +88,11 @@ export async function request(config: ClientConfig, options: { try { const ct = response.headers.get('content-type') ?? ''; if (ct.includes('application/msgpack')) { - errorBody = decodeMsgPack(new Uint8Array(await response.arrayBuffer())); + errorBody = decodeMsgPack(new Uint8Array(await response.arrayBuffer()), { + useMap: false, + rawBinaryStringKeys: false, + rawBinaryStringValues: false, + }); } else if (ct.includes('application/json')) { errorBody = JSON.parse(await response.text()); } else { diff --git a/oas-generator/src/oas_generator/templates/base/src/core/serialization.ts.j2 b/oas-generator/src/oas_generator/templates/base/src/core/serialization.ts.j2 deleted file mode 100644 index 411a8bb6..00000000 --- a/oas-generator/src/oas_generator/templates/base/src/core/serialization.ts.j2 +++ /dev/null @@ -1,26 +0,0 @@ -export function toBase64(bytes: Uint8Array): string { - if (typeof Buffer !== 'undefined') { - return Buffer.from(bytes).toString('base64'); - } - const globalRef: Record = globalThis as unknown as Record; - const btoaFn = globalRef.btoa as ((value: string) => string) | undefined; - if (typeof btoaFn === 'function') { - return btoaFn(String.fromCharCode(...bytes)); - } - throw new Error('Base64 encoding not supported in this environment'); -} - -export function fromBase64(s: string): Uint8Array { - if (typeof Buffer !== 'undefined') { - return new Uint8Array(Buffer.from(s, 'base64')); - } - const globalRef: Record = globalThis as unknown as Record; - const atobFn = globalRef.atob as ((value: string) => string) | undefined; - if (typeof atobFn === 'function') { - const bin = atobFn(s); - const out = new Uint8Array(bin.length); - for (let i = 0; i < bin.length; i += 1) out[i] = bin.charCodeAt(i); - return out; - } - throw new Error('Base64 decoding not supported in this environment'); -} diff --git a/oas-generator/src/oas_generator/templates/base/src/index.ts.j2 b/oas-generator/src/oas_generator/templates/base/src/index.ts.j2 index 6eb10e70..1dd63e72 100644 --- a/oas-generator/src/oas_generator/templates/base/src/index.ts.j2 +++ b/oas-generator/src/oas_generator/templates/base/src/index.ts.j2 @@ -2,7 +2,6 @@ export * from './core/client-config'; export * from './core/base-http-request'; export * from './core/fetch-http-request'; export * from './core/api-error'; -export * from './core/serialization'; export * from './core/codecs'; export * from './core/model-runtime'; diff --git a/oas-generator/src/oas_generator/templates/models/block/application-eval-delta.ts.j2 b/oas-generator/src/oas_generator/templates/models/block/application-eval-delta.ts.j2 deleted file mode 100644 index 849ec0f2..00000000 --- a/oas-generator/src/oas_generator/templates/models/block/application-eval-delta.ts.j2 +++ /dev/null @@ -1,37 +0,0 @@ -import type { ModelMetadata } from '../core/model-runtime'; -import { getModelMeta, registerModelMeta } from '../core/model-runtime'; -import type { SignedTxnInBlock } from './signed-txn-in-block'; -import type { BlockStateDelta } from './block-state-delta'; -import { BlockStateDeltaMeta } from './block-state-delta'; - -/** - * State changes from application execution, including inner transactions and logs. - */ -export interface BlockAppEvalDelta { - /** [gd] Global state delta for the application. */ - globalDelta?: BlockStateDelta; - /** [ld] Local state deltas keyed by address index. */ - localDeltas?: Record; - /** [itx] Inner transactions produced by this application execution. */ - innerTxns?: SignedTxnInBlock[]; - /** [sa] Shared accounts referenced by local deltas. */ - sharedAccounts?: Uint8Array[]; - /** [lg] Application log outputs. */ - logs?: Uint8Array[]; -} - -export const BlockAppEvalDeltaMeta: ModelMetadata = { - name: 'BlockAppEvalDelta', - kind: 'object', - fields: [ - { name: 'globalDelta', wireKey: 'gd', optional: true, nullable: false, type: { kind: 'model', meta: () => BlockStateDeltaMeta } }, - { name: 'localDeltas', wireKey: 'ld', optional: true, nullable: false, type: { kind: 'record', value: { kind: 'model', meta: () => BlockStateDeltaMeta } } }, - { name: 'innerTxns', wireKey: 'itx', optional: true, nullable: false, type: { kind: 'array', item: { kind: 'model', meta: () => getModelMeta('SignedTxnInBlock') } } }, - { name: 'sharedAccounts', wireKey: 'sa', optional: true, nullable: false, type: { kind: 'array', item: { kind: 'scalar', isBytes: true } } }, - { name: 'logs', wireKey: 'lg', optional: true, nullable: false, type: { kind: 'array', item: { kind: 'scalar', isBytes: true } } }, - ], -}; - -registerModelMeta('BlockAppEvalDelta', BlockAppEvalDeltaMeta); - - diff --git a/oas-generator/src/oas_generator/templates/models/block/block-account-state-delta.ts.j2 b/oas-generator/src/oas_generator/templates/models/block/block-account-state-delta.ts.j2 deleted file mode 100644 index d49bb97a..00000000 --- a/oas-generator/src/oas_generator/templates/models/block/block-account-state-delta.ts.j2 +++ /dev/null @@ -1,22 +0,0 @@ -import type { ModelMetadata } from '../core/model-runtime'; -import { registerModelMeta } from '../core/model-runtime'; -import { BlockStateDeltaMeta } from './block-state-delta'; - -/** BlockAccountStateDelta pairs an address with a BlockStateDelta map. */ -export interface BlockAccountStateDelta { - address: string; - delta: import('./block-state-delta').BlockStateDelta; -} - -export const BlockAccountStateDeltaMeta: ModelMetadata = { - name: 'BlockAccountStateDelta', - kind: 'object', - fields: [ - { name: 'address', wireKey: 'address', optional: false, nullable: false, type: { kind: 'scalar' } }, - { name: 'delta', wireKey: 'delta', optional: false, nullable: false, type: { kind: 'model', meta: () => BlockStateDeltaMeta } }, - ], -}; - -registerModelMeta('BlockAccountStateDelta', BlockAccountStateDeltaMeta); - - diff --git a/oas-generator/src/oas_generator/templates/models/block/block-eval-delta.ts.j2 b/oas-generator/src/oas_generator/templates/models/block/block-eval-delta.ts.j2 deleted file mode 100644 index 93d9eb02..00000000 --- a/oas-generator/src/oas_generator/templates/models/block/block-eval-delta.ts.j2 +++ /dev/null @@ -1,26 +0,0 @@ -import type { ModelMetadata } from '../core/model-runtime'; -import { registerModelMeta } from '../core/model-runtime'; - -/** BlockEvalDelta represents a TEAL value delta (block/msgpack wire keys). */ -export interface BlockEvalDelta { - /** [at] delta action. */ - action: number; - /** [bs] bytes value. */ - bytes?: string; - /** [ui] uint value. */ - uint?: bigint; -} - -export const BlockEvalDeltaMeta: ModelMetadata = { - name: 'BlockEvalDelta', - kind: 'object', - fields: [ - { name: 'action', wireKey: 'at', optional: false, nullable: false, type: { kind: 'scalar' } }, - { name: 'bytes', wireKey: 'bs', optional: true, nullable: false, type: { kind: 'scalar' } }, - { name: 'uint', wireKey: 'ui', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, - ], -}; - -registerModelMeta('BlockEvalDelta', BlockEvalDeltaMeta); - - diff --git a/oas-generator/src/oas_generator/templates/models/block/block-state-delta.ts.j2 b/oas-generator/src/oas_generator/templates/models/block/block-state-delta.ts.j2 deleted file mode 100644 index 945a2f89..00000000 --- a/oas-generator/src/oas_generator/templates/models/block/block-state-delta.ts.j2 +++ /dev/null @@ -1,16 +0,0 @@ -import type { ModelMetadata } from '../core/model-runtime'; -import { registerModelMeta } from '../core/model-runtime'; -import { BlockEvalDeltaMeta } from './block-eval-delta'; - -/** BlockStateDelta is a map keyed by state key to BlockEvalDelta. */ -export type BlockStateDelta = Record; - -export const BlockStateDeltaMeta: ModelMetadata = { - name: 'BlockStateDelta', - kind: 'object', - additionalProperties: { kind: 'model', meta: () => BlockEvalDeltaMeta }, -}; - -registerModelMeta('BlockStateDelta', BlockStateDeltaMeta); - - diff --git a/oas-generator/src/oas_generator/templates/models/block/block-state-proof-tracking-data.ts.j2 b/oas-generator/src/oas_generator/templates/models/block/block-state-proof-tracking-data.ts.j2 deleted file mode 100644 index 6306e924..00000000 --- a/oas-generator/src/oas_generator/templates/models/block/block-state-proof-tracking-data.ts.j2 +++ /dev/null @@ -1,26 +0,0 @@ -import type { ModelMetadata } from '../core/model-runtime'; -import { registerModelMeta } from '../core/model-runtime'; - -/** Tracking metadata for a specific StateProofType. */ -export interface BlockStateProofTrackingData { - /** [v] Vector commitment root of state proof voters. */ - stateProofVotersCommitment?: Uint8Array; - /** [t] Online total weight during state proof round. */ - stateProofOnlineTotalWeight?: bigint; - /** [n] Next round for which state proofs are accepted. */ - stateProofNextRound?: bigint; -} - -export const BlockStateProofTrackingDataMeta: ModelMetadata = { - name: 'BlockStateProofTrackingData', - kind: 'object', - fields: [ - { name: 'stateProofVotersCommitment', wireKey: 'v', optional: true, nullable: false, type: { kind: 'scalar', isBytes: true } }, - { name: 'stateProofOnlineTotalWeight', wireKey: 't', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, - { name: 'stateProofNextRound', wireKey: 'n', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, - ], -}; - -registerModelMeta('BlockStateProofTrackingData', BlockStateProofTrackingDataMeta); - - diff --git a/oas-generator/src/oas_generator/templates/models/block/block-state-proof-tracking.ts.j2 b/oas-generator/src/oas_generator/templates/models/block/block-state-proof-tracking.ts.j2 deleted file mode 100644 index c2ccaef9..00000000 --- a/oas-generator/src/oas_generator/templates/models/block/block-state-proof-tracking.ts.j2 +++ /dev/null @@ -1,17 +0,0 @@ -import type { ModelMetadata } from '../core/model-runtime'; -import { registerModelMeta } from '../core/model-runtime'; -import type { BlockStateProofTrackingData } from './block_state_proof_tracking_data'; -import { BlockStateProofTrackingDataMeta } from './block_state_proof_tracking_data'; - -/** Tracks state proof metadata by state proof type. */ -export type BlockStateProofTracking = Record; - -export const BlockStateProofTrackingMeta: ModelMetadata = { - name: 'BlockStateProofTracking', - kind: 'object', - additionalProperties: { kind: 'model', meta: () => BlockStateProofTrackingDataMeta }, -}; - -registerModelMeta('BlockStateProofTracking', BlockStateProofTrackingMeta); - - diff --git a/oas-generator/src/oas_generator/templates/models/block/block.ts.j2 b/oas-generator/src/oas_generator/templates/models/block/block.ts.j2 deleted file mode 100644 index 465ebd0d..00000000 --- a/oas-generator/src/oas_generator/templates/models/block/block.ts.j2 +++ /dev/null @@ -1,120 +0,0 @@ -import type { ModelMetadata } from '../core/model-runtime'; -import type { SignedTxnInBlock } from './signed-txn-in-block'; -import { SignedTxnInBlockMeta } from './signed-txn-in-block'; -import type { BlockStateProofTracking } from './block_state_proof_tracking'; -import { BlockStateProofTrackingMeta } from './block_state_proof_tracking'; - -/** - * Block contains the BlockHeader and the list of transactions (Payset). - */ -export interface Block { - /** [rnd] Round number. */ - round?: bigint; - /** [prev] Previous block hash. */ - previousBlockHash?: Uint8Array; - /** [prev512] Previous block hash using SHA-512. */ - previousBlockHash512?: Uint8Array; - /** [seed] Sortition seed. */ - seed?: Uint8Array; - /** [txn] Root of transaction merkle tree using SHA512_256. */ - transactionsRoot?: Uint8Array; - /** [txn256] Root of transaction vector commitment using SHA256. */ - transactionsRootSha256?: Uint8Array; - /** [txn512] Root of transaction vector commitment using SHA512. */ - transactionsRootSha512?: Uint8Array; - /** [ts] Block timestamp in seconds since epoch. */ - timestamp?: bigint; - /** [gen] Genesis ID. */ - genesisId?: string; - /** [gh] Genesis hash. */ - genesisHash?: Uint8Array; - /** [prp] Proposer address. */ - proposer?: Uint8Array; - /** [fc] Fees collected in this block. */ - feesCollected?: bigint; - /** [bi] Bonus incentive for block proposal. */ - bonus?: bigint; - /** [pp] Proposer payout. */ - proposerPayout?: bigint; - /** [fees] FeeSink address. */ - feeSink?: Uint8Array; - /** [rwd] RewardsPool address. */ - rewardsPool?: Uint8Array; - /** [earn] Rewards level. */ - rewardsLevel?: bigint; - /** [rate] Rewards rate. */ - rewardsRate?: bigint; - /** [frac] Rewards residue. */ - rewardsResidue?: bigint; - /** [rwcalr] Rewards recalculation round. */ - rewardsRecalculationRound?: bigint; - /** [proto] Current consensus protocol. */ - currentProtocol?: string; - /** [nextproto] Next proposed protocol. */ - nextProtocol?: string; - /** [nextyes] Next protocol approvals. */ - nextProtocolApprovals?: bigint; - /** [nextbefore] Next protocol vote deadline. */ - nextProtocolVoteBefore?: bigint; - /** [nextswitch] Next protocol switch round. */ - nextProtocolSwitchOn?: bigint; - /** [upgradeprop] Upgrade proposal. */ - upgradePropose?: string; - /** [upgradedelay] Upgrade delay in rounds. */ - upgradeDelay?: bigint; - /** [upgradeyes] Upgrade approval flag. */ - upgradeApprove?: boolean; - /** [tc] Transaction counter. */ - txnCounter?: bigint; - /** [spt] State proof tracking data keyed by state proof type. */ - stateProofTracking?: BlockStateProofTracking; - /** [partupdrmv] Expired participation accounts. */ - expiredParticipationAccounts?: Uint8Array[]; - /** [partupdabs] Absent participation accounts. */ - absentParticipationAccounts?: Uint8Array[]; - /** [txns] Block transactions (Payset). */ - transactions?: SignedTxnInBlock[]; -} - -export const BlockMeta: ModelMetadata = { - name: 'Block', - kind: 'object', - fields: [ - { name: 'round', wireKey: 'rnd', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, - { name: 'previousBlockHash', wireKey: 'prev', optional: true, nullable: false, type: { kind: 'scalar', isBytes: true } }, - { name: 'previousBlockHash512', wireKey: 'prev512', optional: true, nullable: false, type: { kind: 'scalar', isBytes: true } }, - { name: 'seed', wireKey: 'seed', optional: true, nullable: false, type: { kind: 'scalar', isBytes: true } }, - { name: 'transactionsRoot', wireKey: 'txn', optional: true, nullable: false, type: { kind: 'scalar', isBytes: true } }, - { name: 'transactionsRootSha256', wireKey: 'txn256', optional: true, nullable: false, type: { kind: 'scalar', isBytes: true } }, - { name: 'transactionsRootSha512', wireKey: 'txn512', optional: true, nullable: false, type: { kind: 'scalar', isBytes: true } }, - { name: 'timestamp', wireKey: 'ts', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, - { name: 'genesisId', wireKey: 'gen', optional: true, nullable: false, type: { kind: 'scalar' } }, - { name: 'genesisHash', wireKey: 'gh', optional: true, nullable: false, type: { kind: 'scalar', isBytes: true } }, - { name: 'proposer', wireKey: 'prp', optional: true, nullable: false, type: { kind: 'scalar', isBytes: true } }, - { name: 'feesCollected', wireKey: 'fc', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, - { name: 'bonus', wireKey: 'bi', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, - { name: 'proposerPayout', wireKey: 'pp', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, - { name: 'feeSink', wireKey: 'fees', optional: true, nullable: false, type: { kind: 'scalar', isBytes: true } }, - { name: 'rewardsPool', wireKey: 'rwd', optional: true, nullable: false, type: { kind: 'scalar', isBytes: true } }, - { name: 'rewardsLevel', wireKey: 'earn', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, - { name: 'rewardsRate', wireKey: 'rate', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, - { name: 'rewardsResidue', wireKey: 'frac', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, - { name: 'rewardsRecalculationRound', wireKey: 'rwcalr', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, - { name: 'currentProtocol', wireKey: 'proto', optional: true, nullable: false, type: { kind: 'scalar' } }, - { name: 'nextProtocol', wireKey: 'nextproto', optional: true, nullable: false, type: { kind: 'scalar' } }, - { name: 'nextProtocolApprovals', wireKey: 'nextyes', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, - { name: 'nextProtocolVoteBefore', wireKey: 'nextbefore', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, - { name: 'nextProtocolSwitchOn', wireKey: 'nextswitch', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, - { name: 'upgradePropose', wireKey: 'upgradeprop', optional: true, nullable: false, type: { kind: 'scalar' } }, - { name: 'upgradeDelay', wireKey: 'upgradedelay', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, - { name: 'upgradeApprove', wireKey: 'upgradeyes', optional: true, nullable: false, type: { kind: 'scalar' } }, - { name: 'txnCounter', wireKey: 'tc', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, - { name: 'stateProofTracking', wireKey: 'spt', optional: true, nullable: false, type: { kind: 'model', meta: () => BlockStateProofTrackingMeta } }, - { name: 'expiredParticipationAccounts', wireKey: 'partupdrmv', optional: true, nullable: false, type: { kind: 'array', item: { kind: 'scalar', isBytes: true } } }, - { name: 'absentParticipationAccounts', wireKey: 'partupdabs', optional: true, nullable: false, type: { kind: 'array', item: { kind: 'scalar', isBytes: true } } }, - { name: 'transactions', wireKey: 'txns', optional: true, nullable: false, type: { kind: 'array', item: { kind: 'model', meta: () => SignedTxnInBlockMeta } } }, - ], -}; - - - diff --git a/oas-generator/src/oas_generator/templates/models/block/signed-txn-in-block.ts.j2 b/oas-generator/src/oas_generator/templates/models/block/signed-txn-in-block.ts.j2 deleted file mode 100644 index cabf849d..00000000 --- a/oas-generator/src/oas_generator/templates/models/block/signed-txn-in-block.ts.j2 +++ /dev/null @@ -1,63 +0,0 @@ -/* - * {{ spec.info.title }} - * - * {{ spec.info.description or "API client generated from OpenAPI specification" }} - * - * The version of the OpenAPI document: {{ spec.info.version }} - {% if spec.info.contact and spec.info.contact.email %} * Contact: {{ spec.info.contact.email }} - {% endif %} * Generated by: Rust OpenAPI Generator - */ - -import type { ModelMetadata } from '../core/model-runtime'; -import type { SignedTransaction } from '@algorandfoundation/algokit-transact'; -import type { BlockAppEvalDelta } from './block-app-eval-delta'; -import { getModelMeta, registerModelMeta } from '../core/model-runtime'; - -/** - * SignedTxnInBlock is a SignedTransaction with additional ApplyData and block-specific metadata. - */ -export interface SignedTxnInBlock { - signedTransaction: SignedTransaction; - logicSignature?: Record; - closingAmount?: bigint; - assetClosingAmount?: bigint; - senderRewards?: bigint; - receiverRewards?: bigint; - closeRewards?: bigint; - evalDelta?: BlockAppEvalDelta; - configAsset?: bigint; - applicationId?: bigint; - hasGenesisId?: boolean; - hasGenesisHash?: boolean; -} - -export const SignedTxnInBlockMeta: ModelMetadata = { - name: 'SignedTxnInBlock', - kind: 'object', - fields: [ - { - name: 'signedTransaction', - // flatten signed transaction fields into parent - flattened: true, - optional: false, - nullable: false, - type: { kind: 'codec', codecKey: 'SignedTransaction' }, - }, - { name: 'logicSignature', wireKey: 'lsig', optional: true, nullable: false, type: { kind: 'scalar' } }, - { name: 'closingAmount', wireKey: 'ca', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, - { name: 'assetClosingAmount', wireKey: 'aca', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, - { name: 'senderRewards', wireKey: 'rs', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, - { name: 'receiverRewards', wireKey: 'rr', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, - { name: 'closeRewards', wireKey: 'rc', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, - { name: 'evalDelta', wireKey: 'dt', optional: true, nullable: false, type: { kind: 'model', meta: () => getModelMeta('BlockAppEvalDelta') } }, - { name: 'configAsset', wireKey: 'caid', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, - { name: 'applicationId', wireKey: 'apid', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, - { name: 'hasGenesisId', wireKey: 'hgi', optional: true, nullable: false, type: { kind: 'scalar' } }, - { name: 'hasGenesisHash', wireKey: 'hgh', optional: true, nullable: false, type: { kind: 'scalar' } }, - ], -}; - -registerModelMeta('SignedTxnInBlock', SignedTxnInBlockMeta); - - - diff --git a/oas-generator/src/oas_generator/templates/models/custom/block.ts.j2 b/oas-generator/src/oas_generator/templates/models/custom/block.ts.j2 new file mode 100644 index 00000000..1e59f5e9 --- /dev/null +++ b/oas-generator/src/oas_generator/templates/models/custom/block.ts.j2 @@ -0,0 +1,349 @@ +import { SignedTransaction } from '@algorandfoundation/algokit-transact' +import type { ModelMetadata } from '../core/model-runtime' + +/** BlockEvalDelta represents a TEAL value delta (block/msgpack wire keys). */ +export type BlockEvalDelta = { + /** [at] delta action. */ + action: number + /** [bs] bytes value. */ + bytes?: string + /** [ui] uint value. */ + uint?: bigint +} + +export const BlockEvalDeltaMeta: ModelMetadata = { + name: 'BlockEvalDelta', + kind: 'object', + fields: [ + { name: 'action', wireKey: 'at', optional: false, nullable: false, type: { kind: 'scalar' } }, + { name: 'bytes', wireKey: 'bs', optional: true, nullable: false, type: { kind: 'scalar' } }, + { name: 'uint', wireKey: 'ui', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + ], +} + +/** + * State changes from application execution, including inner transactions and logs. + */ +export type BlockAppEvalDelta = { + /** [gd] Global state delta for the application. */ + globalDelta?: Map + /** [ld] Local state deltas keyed by address index. */ + localDeltas?: Map> + /** [itx] Inner transactions produced by this application execution. */ + innerTxns?: SignedTxnInBlock[] + /** [sa] Shared accounts referenced by local deltas. */ + sharedAccounts?: string[] + /** [lg] Application log outputs. */ + logs?: Uint8Array[] +} + +export const BlockAppEvalDeltaMeta: ModelMetadata = { + name: 'BlockAppEvalDelta', + kind: 'object', + fields: [ + { + name: 'globalDelta', + wireKey: 'gd', + optional: true, + nullable: false, + type: { kind: 'map', keyType: 'bytes', value: { kind: 'model', meta: BlockEvalDeltaMeta } }, + }, + { + name: 'localDeltas', + wireKey: 'ld', + optional: true, + nullable: false, + type: { + kind: 'map', + keyType: 'number', + value: { kind: 'map', keyType: 'bytes', value: { kind: 'model', meta: BlockEvalDeltaMeta } }, + }, + }, + { + name: 'innerTxns', + wireKey: 'itx', + optional: true, + nullable: false, + type: { kind: 'array', item: { kind: 'model', meta: () => SignedTxnInBlockMeta } }, + }, + { + name: 'sharedAccounts', + wireKey: 'sa', + optional: true, + nullable: false, + type: { kind: 'array', item: { kind: 'scalar', isAddress: true } }, + }, + { name: 'logs', wireKey: 'lg', optional: true, nullable: false, type: { kind: 'array', item: { kind: 'scalar', isBytes: true } } }, + ], +} + +/** Tracking metadata for a specific StateProofType. */ +export type BlockStateProofTrackingData = { + /** [v] Vector commitment root of state proof voters. */ + stateProofVotersCommitment?: Uint8Array + /** [t] Online total weight during state proof round. */ + stateProofOnlineTotalWeight?: bigint + /** [n] Next round for which state proofs are accepted. */ + stateProofNextRound?: bigint +} + +export const BlockStateProofTrackingDataMeta: ModelMetadata = { + name: 'BlockStateProofTrackingData', + kind: 'object', + fields: [ + { name: 'stateProofVotersCommitment', wireKey: 'v', optional: true, nullable: false, type: { kind: 'scalar', isBytes: true } }, + { name: 'stateProofOnlineTotalWeight', wireKey: 't', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'stateProofNextRound', wireKey: 'n', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + ], +} + +export type ApplyData = { + closingAmount?: bigint + assetClosingAmount?: bigint + senderRewards?: bigint + receiverRewards?: bigint + closeRewards?: bigint + evalDelta?: BlockAppEvalDelta + configAsset?: bigint + applicationId?: bigint +} + +export const ApplyDataMeta: ModelMetadata = { + name: 'SignedTxnInBlock', + kind: 'object', + fields: [ + { name: 'closingAmount', wireKey: 'ca', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'assetClosingAmount', wireKey: 'aca', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'senderRewards', wireKey: 'rs', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'receiverRewards', wireKey: 'rr', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'closeRewards', wireKey: 'rc', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'evalDelta', wireKey: 'dt', optional: true, nullable: false, type: { kind: 'model', meta: BlockAppEvalDeltaMeta } }, + { name: 'configAsset', wireKey: 'caid', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'applicationId', wireKey: 'apid', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + ], +} + +/** + * SignedTxnWithAD is a SignedTransaction with additional ApplyData. + */ +export type SignedTxnWithAD = { + /** The signed transaction. */ + signedTxn: SignedTransaction + /** Apply data containing transaction execution information. */ + applyData: ApplyData +} + +export const SignedTxnWithADMeta: ModelMetadata = { + name: 'SignedTxnWithAD', + kind: 'object', + fields: [ + { + name: 'signedTransaction', + flattened: true, + optional: false, + nullable: false, + type: { kind: 'codec', codecKey: 'SignedTransaction' }, + }, + { + name: 'applyData', + flattened: true, + optional: true, + nullable: false, + type: { kind: 'model', meta: ApplyDataMeta }, + }, + ], +} + +/** + * SignedTxnInBlock is a SignedTransaction with additional ApplyData and block-specific metadata. + */ +export type SignedTxnInBlock = { + signedTransaction: SignedTxnWithAD + hasGenesisId?: boolean + hasGenesisHash?: boolean +} + +export const SignedTxnInBlockMeta: ModelMetadata = { + name: 'SignedTxnInBlock', + kind: 'object', + fields: [ + { + name: 'signedTransaction', + flattened: true, + optional: false, + nullable: false, + type: { kind: 'model', meta: SignedTxnWithADMeta }, + }, + { name: 'hasGenesisId', wireKey: 'hgi', optional: true, nullable: false, type: { kind: 'scalar' } }, + { name: 'hasGenesisHash', wireKey: 'hgh', optional: true, nullable: false, type: { kind: 'scalar' } }, + ], +} + +export type ParticipationUpdates = { + /** [partupdrmv] Expired participation accounts. */ + expiredParticipationAccounts?: string[] + /** [partupdabs] Absent participation accounts. */ + absentParticipationAccounts?: string[] +} + +export const ParticipationUpdatesMeta: ModelMetadata = { + name: 'ParticipationUpdates', + kind: 'object', + fields: [ + { + name: 'expiredParticipationAccounts', + wireKey: 'partupdrmv', + optional: true, + nullable: false, + type: { kind: 'array', item: { kind: 'scalar', isAddress: true } }, + }, + { + name: 'absentParticipationAccounts', + wireKey: 'partupdabs', + optional: true, + nullable: false, + type: { kind: 'array', item: { kind: 'scalar', isAddress: true } }, + }, + ], +} + +export type BlockHeader = { + /** [rnd] Round number. */ + round?: bigint + /** [prev] Previous block hash. */ + previousBlockHash?: Uint8Array + /** [prev512] Previous block hash using SHA-512. */ + previousBlockHash512?: Uint8Array + /** [seed] Sortition seed. */ + seed?: Uint8Array + /** [txn] Root of transaction merkle tree using SHA512_256. */ + transactionsRoot?: Uint8Array + /** [txn256] Root of transaction vector commitment using SHA256. */ + transactionsRootSha256?: Uint8Array + /** [txn512] Root of transaction vector commitment using SHA512. */ + transactionsRootSha512?: Uint8Array + /** [ts] Block timestamp in seconds since epoch. */ + timestamp?: bigint + /** [gen] Genesis ID. */ + genesisId?: string + /** [gh] Genesis hash. */ + genesisHash?: Uint8Array + /** [prp] Proposer address. */ + proposer?: string + /** [fc] Fees collected in this block. */ + feesCollected?: bigint + /** [bi] Bonus incentive for block proposal. */ + bonus?: bigint + /** [pp] Proposer payout. */ + proposerPayout?: bigint + /** [fees] FeeSink address. */ + feeSink?: string + /** [rwd] RewardsPool address. */ + rewardsPool?: string + /** [earn] Rewards level. */ + rewardsLevel?: bigint + /** [rate] Rewards rate. */ + rewardsRate?: bigint + /** [frac] Rewards residue. */ + rewardsResidue?: bigint + /** [rwcalr] Rewards recalculation round. */ + rewardsRecalculationRound?: bigint + /** [proto] Current consensus protocol. */ + currentProtocol?: string + /** [nextproto] Next proposed protocol. */ + nextProtocol?: string + /** [nextyes] Next protocol approvals. */ + nextProtocolApprovals?: bigint + /** [nextbefore] Next protocol vote deadline. */ + nextProtocolVoteBefore?: bigint + /** [nextswitch] Next protocol switch round. */ + nextProtocolSwitchOn?: bigint + /** [upgradeprop] Upgrade proposal. */ + upgradePropose?: string + /** [upgradedelay] Upgrade delay in rounds. */ + upgradeDelay?: bigint + /** [upgradeyes] Upgrade approval flag. */ + upgradeApprove?: boolean + /** [tc] Transaction counter. */ + txnCounter?: bigint + /** [spt] State proof tracking data keyed by state proof type. */ + stateProofTracking?: Map + /** Represents participation account data that needs to be checked/acted on by the network */ + participationUpdates?: ParticipationUpdates +} + +export const BlockHeaderMeta: ModelMetadata = { + name: 'BlockHeader', + kind: 'object', + fields: [ + { name: 'round', wireKey: 'rnd', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'previousBlockHash', wireKey: 'prev', optional: true, nullable: false, type: { kind: 'scalar', isBytes: true } }, + { name: 'previousBlockHash512', wireKey: 'prev512', optional: true, nullable: false, type: { kind: 'scalar', isBytes: true } }, + { name: 'seed', wireKey: 'seed', optional: true, nullable: false, type: { kind: 'scalar', isBytes: true } }, + { name: 'transactionsRoot', wireKey: 'txn', optional: false, nullable: false, type: { kind: 'scalar', isBytes: true } }, + { name: 'transactionsRootSha256', wireKey: 'txn256', optional: true, nullable: false, type: { kind: 'scalar', isBytes: true } }, + { name: 'transactionsRootSha512', wireKey: 'txn512', optional: true, nullable: false, type: { kind: 'scalar', isBytes: true } }, + { name: 'timestamp', wireKey: 'ts', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'genesisId', wireKey: 'gen', optional: true, nullable: false, type: { kind: 'scalar' } }, + { name: 'genesisHash', wireKey: 'gh', optional: true, nullable: false, type: { kind: 'scalar', isBytes: true } }, + { name: 'proposer', wireKey: 'prp', optional: true, nullable: false, type: { kind: 'scalar', isAddress: true } }, + { name: 'feesCollected', wireKey: 'fc', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'bonus', wireKey: 'bi', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'proposerPayout', wireKey: 'pp', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'feeSink', wireKey: 'fees', optional: true, nullable: false, type: { kind: 'scalar', isAddress: true } }, + { name: 'rewardsPool', wireKey: 'rwd', optional: true, nullable: false, type: { kind: 'scalar', isAddress: true } }, + { name: 'rewardsLevel', wireKey: 'earn', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'rewardsRate', wireKey: 'rate', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'rewardsResidue', wireKey: 'frac', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'rewardsRecalculationRound', wireKey: 'rwcalr', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'currentProtocol', wireKey: 'proto', optional: true, nullable: false, type: { kind: 'scalar' } }, + { name: 'nextProtocol', wireKey: 'nextproto', optional: true, nullable: false, type: { kind: 'scalar' } }, + { name: 'nextProtocolApprovals', wireKey: 'nextyes', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'nextProtocolVoteBefore', wireKey: 'nextbefore', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'nextProtocolSwitchOn', wireKey: 'nextswitch', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'upgradePropose', wireKey: 'upgradeprop', optional: true, nullable: false, type: { kind: 'scalar' } }, + { name: 'upgradeDelay', wireKey: 'upgradedelay', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'upgradeApprove', wireKey: 'upgradeyes', optional: true, nullable: false, type: { kind: 'scalar' } }, + { name: 'txnCounter', wireKey: 'tc', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { + name: 'stateProofTracking', + wireKey: 'spt', + optional: true, + nullable: false, + type: { kind: 'map', keyType: 'number', value: { kind: 'model', meta: BlockStateProofTrackingDataMeta } }, + }, + { + name: 'participationUpdates', + flattened: true, + optional: true, + nullable: false, + type: { kind: 'model', meta: ParticipationUpdatesMeta }, + }, + ], +} + +/** + * Block contains the BlockHeader and the list of transactions (Payset). + */ +export type Block = { + /** The block information (Header) */ + header: BlockHeader + + /** [txns] Block transactions (Payset). */ + payset?: SignedTxnInBlock[] +} + +export const BlockMeta: ModelMetadata = { + name: 'Block', + kind: 'object', + fields: [ + { name: 'header', flattened: true, optional: false, nullable: false, type: { kind: 'model', meta: BlockHeaderMeta } }, + { + name: 'payset', + wireKey: 'txns', + optional: true, + nullable: false, + type: { kind: 'array', item: { kind: 'model', meta: SignedTxnInBlockMeta } }, + }, + ], +} diff --git a/oas-generator/src/oas_generator/templates/models/block/get-block.ts.j2 b/oas-generator/src/oas_generator/templates/models/custom/get-block.ts.j2 similarity index 83% rename from oas-generator/src/oas_generator/templates/models/block/get-block.ts.j2 rename to oas-generator/src/oas_generator/templates/models/custom/get-block.ts.j2 index 04816e65..f0cb9d5f 100644 --- a/oas-generator/src/oas_generator/templates/models/block/get-block.ts.j2 +++ b/oas-generator/src/oas_generator/templates/models/custom/get-block.ts.j2 @@ -5,7 +5,7 @@ import { BlockMeta } from './block'; export type GetBlock = { /** Block data including header and transactions. */ block: Block; - /** Block certificate (msgpack only). */ + /** Block certificate. */ cert?: Record; }; @@ -13,10 +13,7 @@ export const GetBlockMeta: ModelMetadata = { name: 'GetBlock', kind: 'object', fields: [ - { name: 'block', wireKey: 'block', optional: false, nullable: false, type: { kind: 'model', meta: () => BlockMeta } }, + { name: 'block', wireKey: 'block', optional: false, nullable: false, type: { kind: 'model', meta: BlockMeta } }, { name: 'cert', wireKey: 'cert', optional: true, nullable: false, type: { kind: 'scalar' } }, ], }; - - - diff --git a/oas-generator/src/oas_generator/templates/models/custom/ledger-state-delta.ts.j2 b/oas-generator/src/oas_generator/templates/models/custom/ledger-state-delta.ts.j2 new file mode 100644 index 00000000..9bb0e6da --- /dev/null +++ b/oas-generator/src/oas_generator/templates/models/custom/ledger-state-delta.ts.j2 @@ -0,0 +1,696 @@ +import type { ModelMetadata } from '../core/model-runtime' +import type { Block } from './block' +import { BlockMeta } from './block' + +/** + * Contains type information and a value, representing a value in a TEAL program. + */ +export type LedgerTealValue = { + /** + * Type determines the type of the value. + * * 1 represents the type of a byte slice in a TEAL program + * * 2 represents the type of an unsigned integer in a TEAL program + */ + type: number + /** bytes value. */ + bytes?: Uint8Array + /** uint value. */ + uint?: bigint +} + +export const LedgerTealValueMeta: ModelMetadata = { + name: 'LedgerTealValue', + kind: 'object', + fields: [ + { name: 'type', wireKey: 'tt', optional: false, nullable: false, type: { kind: 'scalar' } }, + { name: 'bytes', wireKey: 'tb', optional: true, nullable: false, type: { kind: 'scalar', isBytes: true } }, + { name: 'uint', wireKey: 'ui', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + ], +} + +/** + * Sets maximums on the number of each type that may be stored. + */ +export type LedgerStateSchema = { + /** Number of uints in state. */ + numUints?: bigint + /** Number of byte slices in state. */ + numByteSlices?: bigint +} + +export const LedgerStateSchemaMeta: ModelMetadata = { + name: 'LedgerStateSchema', + kind: 'object', + fields: [ + { name: 'numUints', wireKey: 'nui', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'numByteSlices', wireKey: 'nbs', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + ], +} + +/** + * Stores the global information associated with an application. + */ +export type LedgerAppParams = { + approvalProgram: Uint8Array + clearStateProgram: Uint8Array + localStateSchema: LedgerStateSchema + globalStateSchema: LedgerStateSchema + extraProgramPages: number + version?: number + sizeSponsor?: string + globalState?: Map +} + +export const LedgerAppParamsMeta: ModelMetadata = { + name: 'LedgerAppParams', + kind: 'object', + fields: [ + { name: 'approvalProgram', wireKey: 'approv', optional: false, nullable: false, type: { kind: 'scalar', isBytes: true } }, + { name: 'clearStateProgram', wireKey: 'clearp', optional: false, nullable: false, type: { kind: 'scalar', isBytes: true } }, + { name: 'localStateSchema', wireKey: 'lsch', optional: false, nullable: false, type: { kind: 'model', meta: LedgerStateSchemaMeta } }, + { name: 'globalStateSchema', wireKey: 'gsch', optional: false, nullable: false, type: { kind: 'model', meta: LedgerStateSchemaMeta } }, + { name: 'extraProgramPages', wireKey: 'epp', optional: false, nullable: false, type: { kind: 'scalar' } }, + { name: 'version', wireKey: 'v', optional: true, nullable: false, type: { kind: 'scalar' } }, + { name: 'sizeSponsor', wireKey: 'ss', optional: true, nullable: false, type: { kind: 'scalar', isAddress: true } }, + { + name: 'globalState', + wireKey: 'gs', + optional: true, + nullable: false, + type: { kind: 'map', keyType: 'bytes', value: { kind: 'model', meta: LedgerTealValueMeta } }, + }, + ], +} + +/** + * Stores the LocalState associated with an application. + */ +export type LedgerAppLocalState = { + schema: LedgerStateSchema + keyValue?: Map +} + +export const LedgerAppLocalStateMeta: ModelMetadata = { + name: 'LedgerAppLocalState', + kind: 'object', + fields: [ + { name: 'schema', wireKey: 'hsch', optional: false, nullable: false, type: { kind: 'model', meta: LedgerStateSchemaMeta } }, + { + name: 'keyValue', + wireKey: 'tkv', + optional: true, + nullable: false, + type: { kind: 'map', keyType: 'bytes', value: { kind: 'model', meta: LedgerTealValueMeta } }, + }, + ], +} + +/** + * Tracks a changed AppLocalState, and whether it was deleted. + */ +export type LedgerAppLocalStateDelta = { + deleted: boolean + localState?: LedgerAppLocalState +} + +export const LedgerAppLocalStateDeltaMeta: ModelMetadata = { + name: 'LedgerAppLocalStateDelta', + kind: 'object', + fields: [ + { name: 'deleted', wireKey: 'Deleted', optional: false, nullable: false, type: { kind: 'scalar' } }, + { name: 'localState', wireKey: 'LocalState', optional: true, nullable: false, type: { kind: 'model', meta: LedgerAppLocalStateMeta } }, + ], +} + +/** + * Tracks a changed AppParams, and whether it was deleted. + */ +export type LedgerAppParamsDelta = { + deleted: boolean + params?: LedgerAppParams +} + +export const LedgerAppParamsDeltaMeta: ModelMetadata = { + name: 'LedgerAppParamsDelta', + kind: 'object', + fields: [ + { name: 'deleted', wireKey: 'Deleted', optional: false, nullable: false, type: { kind: 'scalar' } }, + { name: 'params', wireKey: 'Params', optional: true, nullable: false, type: { kind: 'model', meta: LedgerAppParamsMeta } }, + ], +} + +/** + * Represents AppParams and AppLocalState in deltas. + */ +export type LedgerAppResourceRecord = { + appId: bigint + address: string + params: LedgerAppParamsDelta + state: LedgerAppLocalStateDelta +} + +export const LedgerAppResourceRecordMeta: ModelMetadata = { + name: 'LedgerAppResourceRecord', + kind: 'object', + fields: [ + { name: 'appId', wireKey: 'Aidx', optional: false, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'address', wireKey: 'Addr', optional: false, nullable: false, type: { kind: 'scalar', isAddress: true } }, + { name: 'params', wireKey: 'Params', optional: false, nullable: false, type: { kind: 'model', meta: LedgerAppParamsDeltaMeta } }, + { name: 'state', wireKey: 'State', optional: false, nullable: false, type: { kind: 'model', meta: LedgerAppLocalStateDeltaMeta } }, + ], +} + +/** + * Describes an asset held by an account. + */ +export type LedgerAssetHolding = { + amount: bigint + frozen: boolean +} + +export const LedgerAssetHoldingMeta: ModelMetadata = { + name: 'LedgerAssetHolding', + kind: 'object', + fields: [ + { name: 'amount', wireKey: 'a', optional: false, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'frozen', wireKey: 'f', optional: false, nullable: false, type: { kind: 'scalar' } }, + ], +} + +/** + * Records a changed AssetHolding, and whether it was deleted. + */ +export type LedgerAssetHoldingDelta = { + deleted: boolean + holding?: LedgerAssetHolding +} + +export const LedgerAssetHoldingDeltaMeta: ModelMetadata = { + name: 'LedgerAssetHoldingDelta', + kind: 'object', + fields: [ + { name: 'deleted', wireKey: 'Deleted', optional: false, nullable: false, type: { kind: 'scalar' } }, + { name: 'holding', wireKey: 'Holding', optional: true, nullable: false, type: { kind: 'model', meta: LedgerAssetHoldingMeta } }, + ], +} + +/** + * Describes the parameters of an asset. + */ +export type LedgerAssetParams = { + /** + * Specifies the total number of units of this asset created. + */ + total: bigint + /** + * Specifies the number of digits to display after the decimal place when displaying this asset. + * A value of 0 represents an asset that is not divisible, a value of 1 represents an asset divisible into tenths, and so on. + * This value must be between 0 and 19 (inclusive). + */ + decimals: number + /** + * Specifies whether slots for this asset in user accounts are frozen by default or not. + */ + defaultFrozen: boolean + /** + * Specifies a hint for the name of a unit of this asset. + */ + unitName?: string + /** + * Specifies a hint for the name of the asset. + */ + assetName?: string + /** + * Specifies a URL where more information about the asset can be retrieved. + */ + url?: string + /** + * Specifies a commitment to some unspecified asset metadata. The format of this + * metadata is up to the application. + */ + metadataHash?: Uint8Array + /** + * Manager specifies an account that is allowed to change the non-zero addresses in this AssetParams. + */ + manager?: string + /** + * Specifies an account whose holdings of this asset should be reported as "not minted". + */ + reserve?: string + /** + * Specifies an account that is allowed to change the frozen state of holdings of this asset. + */ + freeze?: string + /** + * Specifies an account that is allowed to take units of this asset from any account. + */ + clawback?: string +} + +export const LedgerAssetParamsMeta: ModelMetadata = { + name: 'LedgerAssetParams', + kind: 'object', + fields: [ + { name: 'total', wireKey: 't', optional: false, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'decimals', wireKey: 'dc', optional: false, nullable: false, type: { kind: 'scalar' } }, + { name: 'defaultFrozen', wireKey: 'df', optional: false, nullable: false, type: { kind: 'scalar' } }, + { name: 'unitName', wireKey: 'un', optional: true, nullable: false, type: { kind: 'scalar' } }, + { name: 'assetName', wireKey: 'an', optional: true, nullable: false, type: { kind: 'scalar' } }, + { name: 'url', wireKey: 'au', optional: true, nullable: false, type: { kind: 'scalar' } }, + { name: 'metadataHash', wireKey: 'am', optional: true, nullable: false, type: { kind: 'scalar', isBytes: true } }, + { name: 'manager', wireKey: 'm', optional: true, nullable: false, type: { kind: 'scalar', isAddress: true } }, + { name: 'reserve', wireKey: 'r', optional: true, nullable: false, type: { kind: 'scalar', isAddress: true } }, + { name: 'freeze', wireKey: 'f', optional: true, nullable: false, type: { kind: 'scalar', isAddress: true } }, + { name: 'clawback', wireKey: 'c', optional: true, nullable: false, type: { kind: 'scalar', isAddress: true } }, + ], +} + +/** + * Tracks a changed asset params, and whether it was deleted. + */ +export type LedgerAssetParamsDelta = { + deleted: boolean + params?: LedgerAssetParams +} + +export const LedgerAssetParamsDeltaMeta: ModelMetadata = { + name: 'LedgerAssetParamsDelta', + kind: 'object', + fields: [ + { name: 'deleted', wireKey: 'Deleted', optional: false, nullable: false, type: { kind: 'scalar' } }, + { name: 'params', wireKey: 'Params', optional: true, nullable: false, type: { kind: 'model', meta: LedgerAssetParamsMeta } }, + ], +} + +/** + * Represents asset params and asset holding in deltas. + */ +export type LedgerAssetResourceRecord = { + assetId: bigint + address: string + params: LedgerAssetParamsDelta + holding: LedgerAssetHoldingDelta +} + +export const LedgerAssetResourceRecordMeta: ModelMetadata = { + name: 'LedgerAssetResourceRecord', + kind: 'object', + fields: [ + { name: 'assetId', wireKey: 'Aidx', optional: false, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'address', wireKey: 'Addr', optional: false, nullable: false, type: { kind: 'scalar', isAddress: true } }, + { name: 'params', wireKey: 'Params', optional: false, nullable: false, type: { kind: 'model', meta: LedgerAssetParamsDeltaMeta } }, + { name: 'holding', wireKey: 'Holding', optional: false, nullable: false, type: { kind: 'model', meta: LedgerAssetHoldingDeltaMeta } }, + ], +} + +/** + * Holds participation information. + */ +export type LedgerVotingData = { + voteId: Uint8Array + selectionId: Uint8Array + stateProofId: Uint8Array + voteFirstValid: bigint + voteLastValid: bigint + voteKeyDilution: bigint +} + +export const LedgerVotingDataMeta: ModelMetadata = { + name: 'LedgerVotingData', + kind: 'object', + fields: [ + { name: 'voteId', wireKey: 'VoteID', optional: false, nullable: false, type: { kind: 'scalar', isBytes: true } }, + { name: 'selectionId', wireKey: 'SelectionID', optional: false, nullable: false, type: { kind: 'scalar', isBytes: true } }, + { name: 'stateProofId', wireKey: 'StateProofID', optional: false, nullable: false, type: { kind: 'scalar', isBytes: true } }, + { name: 'voteFirstValid', wireKey: 'VoteFirstValid', optional: false, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'voteLastValid', wireKey: 'VoteLastValid', optional: false, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'voteKeyDilution', wireKey: 'VoteKeyDilution', optional: false, nullable: false, type: { kind: 'scalar', isBigint: true } }, + ], +} + +/** + * Contains base account info like balance, status and total number of resources. + */ +export type LedgerAccountBaseData = { + /** + * Account status. Values are: + * * 0: Offline + * * 1: Online + * * 2: NotParticipating + */ + status: number + microAlgos: bigint + rewardsBase: bigint + rewardedMicroAlgos: bigint + authAddress: string + incentiveEligible: boolean + /** + * Totals across created globals, and opted in locals. + */ + totalAppSchema: LedgerStateSchema + /** + * Total number of extra pages across all created apps. + */ + totalExtraAppPages: number + /** + * Total number of apps this account has created. + */ + totalAppParams: number + /** + * Total number of apps this account is opted into. + */ + totalAppLocalStates: number + /** + * Total number of assets created by this account. + */ + totalAssetParams: number + /** + * Total of asset creations and optins (i.e. number of holdings). + */ + totalAssets: number + /** + * Total number of boxes associated to this account. + */ + totalBoxes: bigint + /** + * Total bytes for this account's boxes. keys and values count. + */ + totalBoxBytes: bigint + /** + * The last round that this account proposed the winning block. + */ + lastProposed: bigint + /** + * The last round that this account sent a heartbeat to show it was online. + */ + lastHeartbeat: bigint +} + +export const LedgerAccountBaseDataMeta: ModelMetadata = { + name: 'LedgerAccountBaseData', + kind: 'object', + fields: [ + { name: 'status', wireKey: 'Status', optional: false, nullable: false, type: { kind: 'scalar' } }, + { name: 'microAlgos', wireKey: 'MicroAlgos', optional: false, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'rewardsBase', wireKey: 'RewardsBase', optional: false, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { + name: 'rewardedMicroAlgos', + wireKey: 'RewardedMicroAlgos', + optional: false, + nullable: false, + type: { kind: 'scalar', isBigint: true }, + }, + { name: 'authAddress', wireKey: 'AuthAddr', optional: false, nullable: false, type: { kind: 'scalar', isAddress: true } }, + { name: 'incentiveEligible', wireKey: 'IncentiveEligible', optional: false, nullable: false, type: { kind: 'scalar' } }, + { + name: 'totalAppSchema', + wireKey: 'TotalAppSchema', + optional: false, + nullable: false, + type: { kind: 'model', meta: LedgerStateSchemaMeta }, + }, + { name: 'totalExtraAppPages', wireKey: 'TotalExtraAppPages', optional: false, nullable: false, type: { kind: 'scalar' } }, + { name: 'totalAppParams', wireKey: 'TotalAppParams', optional: false, nullable: false, type: { kind: 'scalar' } }, + { name: 'totalAppLocalStates', wireKey: 'TotalAppLocalStates', optional: false, nullable: false, type: { kind: 'scalar' } }, + { name: 'totalAssetParams', wireKey: 'TotalAssetParams', optional: false, nullable: false, type: { kind: 'scalar' } }, + { name: 'totalAssets', wireKey: 'TotalAssets', optional: false, nullable: false, type: { kind: 'scalar' } }, + { name: 'totalBoxes', wireKey: 'TotalBoxes', optional: false, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'totalBoxBytes', wireKey: 'TotalBoxBytes', optional: false, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'lastProposed', wireKey: 'LastProposed', optional: false, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'lastHeartbeat', wireKey: 'LastHeartbeat', optional: false, nullable: false, type: { kind: 'scalar', isBigint: true } }, + ], +} + +/** + * Provides per-account data. + */ +export type LedgerAccountData = { + accountBaseData: LedgerAccountBaseData + votingData: LedgerVotingData +} + +export const LedgerAccountDataMeta: ModelMetadata = { + name: 'LedgerAccountData', + kind: 'object', + fields: [ + { + name: 'accountBaseData', + flattened: true, + optional: false, + nullable: false, + type: { kind: 'model', meta: LedgerAccountBaseDataMeta }, + }, + { name: 'votingData', flattened: true, optional: false, nullable: false, type: { kind: 'model', meta: LedgerVotingDataMeta } }, + ], +} + +export type LedgerBalanceRecord = { + address: string + accountData: LedgerAccountData +} + +export const LedgerBalanceRecordMeta: ModelMetadata = { + name: 'LedgerBalanceRecord', + kind: 'object', + fields: [ + { name: 'address', wireKey: 'Addr', optional: false, nullable: false, type: { kind: 'scalar', isAddress: true } }, + { name: 'accountData', flattened: true, optional: false, nullable: false, type: { kind: 'model', meta: LedgerAccountDataMeta } }, + ], +} + +export type LedgerAccountDeltas = { + accounts?: LedgerBalanceRecord[] + appResources?: LedgerAppResourceRecord[] + assetResources?: LedgerAssetResourceRecord[] +} + +export const LedgerAccountDeltasMeta: ModelMetadata = { + name: 'LedgerAccountDeltas', + kind: 'object', + fields: [ + { + name: 'accounts', + wireKey: 'Accts', + optional: true, + nullable: false, + type: { kind: 'array', item: { kind: 'model', meta: LedgerBalanceRecordMeta } }, + }, + { + name: 'appResources', + wireKey: 'AppResources', + optional: true, + nullable: false, + type: { kind: 'array', item: { kind: 'model', meta: LedgerAppResourceRecordMeta } }, + }, + { + name: 'assetResources', + wireKey: 'AssetResources', + optional: true, + nullable: false, + type: { kind: 'array', item: { kind: 'model', meta: LedgerAssetResourceRecordMeta } }, + }, + ], +} + +/** + * Shows how the data associated with a key in the kvstore has changed. + */ +export type LedgerKvValueDelta = { + /** + * Stores the most recent value (undefined means deleted). + */ + data?: Uint8Array + /** + * Stores the previous value (undefined means didn't exist). + */ + oldData?: Uint8Array +} + +export const LedgerKvValueDeltaMeta: ModelMetadata = { + name: 'LedgerKvValueDelta', + kind: 'object', + fields: [ + { name: 'data', wireKey: 'Data', optional: true, nullable: false, type: { kind: 'scalar', isBytes: true } }, + { name: 'oldData', wireKey: 'OldData', optional: true, nullable: false, type: { kind: 'scalar', isBytes: true } }, + ], +} + +/** + * Defines the transactions included in a block, their index and last valid round. + */ +export type LedgerIncludedTransactions = { + lastValid: bigint + /** + * The index of the transaction in the block. + */ + intra: number +} + +export const LedgerIncludedTransactionsMeta: ModelMetadata = { + name: 'LedgerIncludedTransactions', + kind: 'object', + fields: [ + { name: 'lastValid', wireKey: 'LastValid', optional: false, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'intra', wireKey: 'Intra', optional: false, nullable: false, type: { kind: 'scalar' } }, + ], +} + +/** + * Represents a change to a single creatable state. + */ +export type LedgerModifiedCreatable = { + /** + * Type of the creatable. The values are: + * * 0: Asset + * * 1: Application + */ + creatableType: number + /** + * Created if true, deleted if false. + */ + created: boolean + /** + * Creator of the app/asset. + */ + creator: string + /** + * Keeps track of how many times this app/asset appears in accountUpdates.creatableDeltas. + */ + nDeltas: number +} + +export const LedgerModifiedCreatableMeta: ModelMetadata = { + name: 'LedgerModifiedCreatable', + kind: 'object', + fields: [ + { name: 'creatableType', wireKey: 'Ctype', optional: false, nullable: false, type: { kind: 'scalar' } }, + { name: 'created', wireKey: 'Created', optional: false, nullable: false, type: { kind: 'scalar' } }, + { name: 'creator', wireKey: 'Creator', optional: false, nullable: false, type: { kind: 'scalar', isAddress: true } }, + { name: 'ndeltas', wireKey: 'Ndeltas', optional: false, nullable: false, type: { kind: 'scalar' } }, + ], +} + +/** + * Represents a total of algos of a certain class of accounts (split up by their Status value). + */ +export type LedgerAlgoCount = { + /** + * Sum of algos of all accounts in this scope. + */ + money: bigint + /** + * Total number of whole reward units in accounts. + */ + rewardUnits: bigint +} + +export const LedgerAlgoCountMeta: ModelMetadata = { + name: 'LedgerAlgoCount', + kind: 'object', + fields: [ + { name: 'money', wireKey: 'mon', optional: false, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'rewardUnits', wireKey: 'rwd', optional: false, nullable: false, type: { kind: 'scalar', isBigint: true } }, + ], +} + +/** + * Represents the totals of algos in the system grouped by different account status values. + */ +export type LedgerAccountTotals = { + online: LedgerAlgoCount + offline: LedgerAlgoCount + notParticipating: LedgerAlgoCount + /** + * Total number of algos received per reward unit since genesis. + */ + rewardsLevel: bigint +} + +export const LedgerAccountTotalsMeta: ModelMetadata = { + name: 'LedgerAccountTotals', + kind: 'object', + fields: [ + { name: 'online', wireKey: 'online', optional: false, nullable: false, type: { kind: 'model', meta: LedgerAlgoCountMeta } }, + { name: 'offline', wireKey: 'offline', optional: false, nullable: false, type: { kind: 'model', meta: LedgerAlgoCountMeta } }, + { name: 'notParticipating', wireKey: 'notpart', optional: false, nullable: false, type: { kind: 'model', meta: LedgerAlgoCountMeta } }, + { name: 'rewardsLevel', wireKey: 'rwdlvl', optional: false, nullable: false, type: { kind: 'scalar', isBigint: true } }, + ], +} + +/** + * Describes the delta between a given round to the previous round. + */ +export type LedgerStateDelta = { + /** + * Modified new accounts. + */ + accounts: LedgerAccountDeltas + /** + * Block header. + */ + block: Block + /** + * Represents modification on StateProofNextRound field in the block header. If the block contains + * a valid state proof transaction, this field will contain the next round for state proof. + * otherwise it will be set to 0. + */ + stateProofNext: bigint + /** + * Previous block timestamp + */ + prevTimestamp: bigint + /** + * The account totals reflecting the changes in this StateDelta object. + */ + totals: LedgerAccountTotals + /** + * Modified kv pairs. + */ + kvMods?: Map + /** + * New Txids for the txtail and TxnCounter, mapped to txn.LastValid. + */ + txIds?: Map + /** + * New txleases for the txtail mapped to expiration. + */ + txLeases?: Record + /** + * New creatables creator lookup table. + */ + creatables?: Map +} + +export const LedgerStateDeltaMeta: ModelMetadata = { + name: 'LedgerStateDelta', + kind: 'object', + fields: [ + { name: 'accounts', wireKey: 'Accts', optional: false, nullable: false, type: { kind: 'model', meta: LedgerAccountDeltasMeta } }, + { name: 'block', wireKey: 'Hdr', optional: false, nullable: false, type: { kind: 'model', meta: BlockMeta } }, + { name: 'stateProofNext', wireKey: 'StateProofNext', optional: false, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'prevTimestamp', wireKey: 'PrevTimestamp', optional: false, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'totals', wireKey: 'Totals', optional: false, nullable: false, type: { kind: 'model', meta: LedgerAccountTotalsMeta } }, + { + name: 'kvMods', + wireKey: 'KvMods', + optional: true, + nullable: false, + type: { kind: 'map', keyType: 'bytes', value: { kind: 'model', meta: LedgerKvValueDeltaMeta } }, + }, + { + name: 'txIds', + wireKey: 'Txids', + optional: true, + nullable: false, + type: { kind: 'map', keyType: 'bytes', value: { kind: 'model', meta: LedgerIncludedTransactionsMeta } }, + }, + { name: 'txLeases', wireKey: 'Txleases', optional: true, nullable: false, type: { kind: 'scalar' } }, + { + name: 'creatables', + wireKey: 'Creatables', + optional: true, + nullable: false, + type: { kind: 'map', keyType: 'number', value: { kind: 'model', meta: LedgerModifiedCreatableMeta } }, + }, + ], +} diff --git a/oas-generator/src/oas_generator/templates/models/transaction-params/suggested-params.ts.j2 b/oas-generator/src/oas_generator/templates/models/custom/suggested-params.ts.j2 similarity index 100% rename from oas-generator/src/oas_generator/templates/models/transaction-params/suggested-params.ts.j2 rename to oas-generator/src/oas_generator/templates/models/custom/suggested-params.ts.j2 diff --git a/oas-generator/src/oas_generator/templates/models/model.ts.j2 b/oas-generator/src/oas_generator/templates/models/model.ts.j2 index f6680f2a..eee3fbb1 100644 --- a/oas-generator/src/oas_generator/templates/models/model.ts.j2 +++ b/oas-generator/src/oas_generator/templates/models/model.ts.j2 @@ -12,11 +12,13 @@ { kind: 'scalar'{% if is_bytes %}, isBytes: true{% endif %}{% if is_bigint %}, isBigint: true{% endif %} } {%- endmacro %} -{% macro base_type(ref_model, is_signed_txn, is_bytes, is_bigint) -%} +{% macro base_type(ref_model, is_signed_txn, is_bytes, is_bigint, inline_meta_name) -%} {%- if is_signed_txn -%} { kind: 'codec', codecKey: 'SignedTransaction' } {%- elif ref_model -%} -{ kind: 'model', meta: () => {{ ref_model }}Meta } +{ kind: 'model', meta: {% if modelName == ref_model %}() => {% endif %}{{ ref_model }}Meta } +{%- elif inline_meta_name -%} +{ kind: 'model', meta: {{ inline_meta_name }} } {%- else -%} {{ scalar_meta(is_bytes, is_bigint) }} {%- endif -%} @@ -24,9 +26,9 @@ {% macro field_type(field) -%} {%- if field.is_array -%} -{ kind: 'array', item: {{ base_type(field.ref_model, field.is_signed_txn, field.is_bytes, field.is_bigint) }} } +{ kind: 'array', item: {{ base_type(field.ref_model, field.is_signed_txn, field.is_bytes, field.is_bigint, none) }} } {%- else -%} -{{ base_type(field.ref_model, field.is_signed_txn, field.is_bytes, field.is_bigint) }} +{{ base_type(field.ref_model, field.is_signed_txn, field.is_bytes, field.is_bigint, field.inline_meta_name) }} {%- endif -%} {%- endmacro %} @@ -58,6 +60,29 @@ import { {{ r }}Meta } from './{{ r | ts_kebab_case }}'; {% endif %} {% endfor %} +{% macro inline_object_meta(inline_schema, required_fields, meta_name) -%} +{ name: '{{ meta_name }}', kind: 'object', fields: [ +{%- for prop_name, prop_schema in inline_schema.get('properties', {}).items() %} + { + name: '{{ prop_name | ts_camel_case }}', + wireKey: '{{ prop_name }}', + optional: {{ 'false' if prop_name in required_fields else 'true' }}, + nullable: {{ 'true' if prop_schema.get('nullable') else 'false' }}, + type: {{ scalar_meta(prop_schema.get('format') == 'byte' or prop_schema.get('x-algokit-bytes-base64'), prop_schema.get('x-algokit-bigint')) }}, + }, +{%- endfor %} + ] } +{%- endmacro %} + +{% if descriptor.is_object %} +{% for f in descriptor.fields %} +{% if f.inline_object_schema %} +const {{ f.inline_meta_name }}: ModelMetadata = {{ inline_object_meta(f.inline_object_schema, f.inline_object_schema.get('required', []), f.inline_meta_name) }}; + +{% endif %} +{% endfor %} +{% endif %} + {{ schema.description | ts_doc_comment }} {% if isObject and schema.get('allOf') is not defined and schema.get('oneOf') is not defined and schema.get('anyOf') is not defined %} export interface {{ modelName }} { diff --git a/packages/algod_client/package.json b/packages/algod_client/package.json index de108cfd..5d3ce75f 100644 --- a/packages/algod_client/package.json +++ b/packages/algod_client/package.json @@ -26,4 +26,4 @@ "dependencies": {}, "peerDependencies": {}, "devDependencies": {} -} +} \ No newline at end of file diff --git a/packages/algod_client/src/apis/api.service.ts b/packages/algod_client/src/apis/api.service.ts index 21678eac..de104837 100644 --- a/packages/algod_client/src/apis/api.service.ts +++ b/packages/algod_client/src/apis/api.service.ts @@ -94,7 +94,7 @@ export class AlgodApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = AlgodApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/accounts/{address}/applications/{application-id}', path: { address: address, 'application-id': typeof applicationId === 'bigint' ? applicationId.toString() : applicationId }, @@ -104,11 +104,7 @@ export class AlgodApi { mediaType: undefined, }) - const responseMeta = AccountApplicationInformationMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as AccountApplicationInformation + return AlgorandSerializer.decode(payload, AccountApplicationInformationMeta, responseFormat) } /** @@ -119,7 +115,7 @@ export class AlgodApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = AlgodApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/accounts/{address}/assets/{asset-id}', path: { address: address, 'asset-id': typeof assetId === 'bigint' ? assetId.toString() : assetId }, @@ -129,11 +125,7 @@ export class AlgodApi { mediaType: undefined, }) - const responseMeta = AccountAssetInformationMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as AccountAssetInformation + return AlgorandSerializer.decode(payload, AccountAssetInformationMeta, responseFormat) } /** @@ -144,7 +136,7 @@ export class AlgodApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = AlgodApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/accounts/{address}', path: { address: address }, @@ -154,11 +146,7 @@ export class AlgodApi { mediaType: undefined, }) - const responseMeta = AccountMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as Account + return AlgorandSerializer.decode(payload, AccountMeta, responseFormat) } /** @@ -169,7 +157,7 @@ export class AlgodApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = AlgodApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/applications/{application-id}/box', path: { 'application-id': typeof applicationId === 'bigint' ? applicationId.toString() : applicationId }, @@ -179,11 +167,7 @@ export class AlgodApi { mediaType: undefined, }) - const responseMeta = BoxMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as Box + return AlgorandSerializer.decode(payload, BoxMeta, responseFormat) } /** @@ -194,7 +178,7 @@ export class AlgodApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = AlgodApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/applications/{application-id}/boxes', path: { 'application-id': typeof applicationId === 'bigint' ? applicationId.toString() : applicationId }, @@ -204,11 +188,7 @@ export class AlgodApi { mediaType: undefined, }) - const responseMeta = GetApplicationBoxesMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as GetApplicationBoxes + return AlgorandSerializer.decode(payload, GetApplicationBoxesMeta, responseFormat) } /** @@ -219,7 +199,7 @@ export class AlgodApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = AlgodApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/applications/{application-id}', path: { 'application-id': typeof applicationId === 'bigint' ? applicationId.toString() : applicationId }, @@ -229,11 +209,7 @@ export class AlgodApi { mediaType: undefined, }) - const responseMeta = ApplicationMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as Application + return AlgorandSerializer.decode(payload, ApplicationMeta, responseFormat) } /** @@ -244,7 +220,7 @@ export class AlgodApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = AlgodApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/assets/{asset-id}', path: { 'asset-id': typeof assetId === 'bigint' ? assetId.toString() : assetId }, @@ -254,11 +230,7 @@ export class AlgodApi { mediaType: undefined, }) - const responseMeta = AssetMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as Asset + return AlgorandSerializer.decode(payload, AssetMeta, responseFormat) } async getBlock(round: number | bigint, params?: { headerOnly?: boolean }): Promise { @@ -266,7 +238,7 @@ export class AlgodApi { const responseFormat: BodyFormat = 'msgpack' headers['Accept'] = AlgodApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/blocks/{round}', path: { round: typeof round === 'bigint' ? round.toString() : round }, @@ -276,11 +248,7 @@ export class AlgodApi { mediaType: undefined, }) - const responseMeta = GetBlockMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as GetBlock + return AlgorandSerializer.decode(payload, GetBlockMeta, responseFormat) } async getBlockHash(round: number | bigint): Promise { @@ -288,7 +256,7 @@ export class AlgodApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = AlgodApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/blocks/{round}/hash', path: { round: typeof round === 'bigint' ? round.toString() : round }, @@ -298,11 +266,7 @@ export class AlgodApi { mediaType: undefined, }) - const responseMeta = GetBlockHashMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as GetBlockHash + return AlgorandSerializer.decode(payload, GetBlockHashMeta, responseFormat) } /** @@ -313,7 +277,7 @@ export class AlgodApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = AlgodApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/devmode/blocks/offset', path: {}, @@ -323,11 +287,7 @@ export class AlgodApi { mediaType: undefined, }) - const responseMeta = GetBlockTimeStampOffsetMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as GetBlockTimeStampOffset + return AlgorandSerializer.decode(payload, GetBlockTimeStampOffsetMeta, responseFormat) } async getBlockTxIds(round: number | bigint): Promise { @@ -335,7 +295,7 @@ export class AlgodApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = AlgodApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/blocks/{round}/txids', path: { round: typeof round === 'bigint' ? round.toString() : round }, @@ -345,11 +305,7 @@ export class AlgodApi { mediaType: undefined, }) - const responseMeta = GetBlockTxIdsMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as GetBlockTxIds + return AlgorandSerializer.decode(payload, GetBlockTxIdsMeta, responseFormat) } /** @@ -360,7 +316,7 @@ export class AlgodApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = AlgodApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/genesis', path: {}, @@ -370,11 +326,7 @@ export class AlgodApi { mediaType: undefined, }) - const responseMeta = GenesisMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as Genesis + return AlgorandSerializer.decode(payload, GenesisMeta, responseFormat) } /** @@ -385,7 +337,7 @@ export class AlgodApi { const responseFormat: BodyFormat = 'msgpack' headers['Accept'] = AlgodApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/deltas/{round}', path: { round: typeof round === 'bigint' ? round.toString() : round }, @@ -395,11 +347,7 @@ export class AlgodApi { mediaType: undefined, }) - const responseMeta = LedgerStateDeltaMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as LedgerStateDelta + return AlgorandSerializer.decode(payload, LedgerStateDeltaMeta, responseFormat) } /** @@ -410,7 +358,7 @@ export class AlgodApi { const responseFormat: BodyFormat = 'msgpack' headers['Accept'] = AlgodApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/deltas/txn/group/{id}', path: { id: id }, @@ -420,11 +368,7 @@ export class AlgodApi { mediaType: undefined, }) - const responseMeta = LedgerStateDeltaMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as LedgerStateDelta + return AlgorandSerializer.decode(payload, LedgerStateDeltaMeta, responseFormat) } async getLightBlockHeaderProof(round: number | bigint): Promise { @@ -432,7 +376,7 @@ export class AlgodApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = AlgodApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/blocks/{round}/lightheader/proof', path: { round: typeof round === 'bigint' ? round.toString() : round }, @@ -442,11 +386,7 @@ export class AlgodApi { mediaType: undefined, }) - const responseMeta = LightBlockHeaderProofMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as LightBlockHeaderProof + return AlgorandSerializer.decode(payload, LightBlockHeaderProofMeta, responseFormat) } /** @@ -457,7 +397,7 @@ export class AlgodApi { const responseFormat: BodyFormat = 'msgpack' headers['Accept'] = AlgodApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/transactions/pending', path: {}, @@ -467,11 +407,7 @@ export class AlgodApi { mediaType: undefined, }) - const responseMeta = GetPendingTransactionsMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as GetPendingTransactions + return AlgorandSerializer.decode(payload, GetPendingTransactionsMeta, responseFormat) } /** @@ -482,7 +418,7 @@ export class AlgodApi { const responseFormat: BodyFormat = 'msgpack' headers['Accept'] = AlgodApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/accounts/{address}/transactions/pending', path: { address: address }, @@ -492,11 +428,7 @@ export class AlgodApi { mediaType: undefined, }) - const responseMeta = GetPendingTransactionsByAddressMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as GetPendingTransactionsByAddress + return AlgorandSerializer.decode(payload, GetPendingTransactionsByAddressMeta, responseFormat) } async getReady(): Promise { @@ -504,7 +436,7 @@ export class AlgodApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = AlgodApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + await this.httpRequest.request({ method: 'GET', url: '/ready', path: {}, @@ -513,12 +445,6 @@ export class AlgodApi { body: undefined, mediaType: undefined, }) - - const responseMeta = undefined - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as void } async getStateProof(round: number | bigint): Promise { @@ -526,7 +452,7 @@ export class AlgodApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = AlgodApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/stateproofs/{round}', path: { round: typeof round === 'bigint' ? round.toString() : round }, @@ -536,11 +462,7 @@ export class AlgodApi { mediaType: undefined, }) - const responseMeta = StateProofMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as StateProof + return AlgorandSerializer.decode(payload, StateProofMeta, responseFormat) } async getStatus(): Promise { @@ -548,7 +470,7 @@ export class AlgodApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = AlgodApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/status', path: {}, @@ -558,11 +480,7 @@ export class AlgodApi { mediaType: undefined, }) - const responseMeta = GetStatusMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as GetStatus + return AlgorandSerializer.decode(payload, GetStatusMeta, responseFormat) } async getSupply(): Promise { @@ -570,7 +488,7 @@ export class AlgodApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = AlgodApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/ledger/supply', path: {}, @@ -580,11 +498,7 @@ export class AlgodApi { mediaType: undefined, }) - const responseMeta = GetSupplyMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as GetSupply + return AlgorandSerializer.decode(payload, GetSupplyMeta, responseFormat) } /** @@ -595,7 +509,7 @@ export class AlgodApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = AlgodApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/ledger/sync', path: {}, @@ -605,11 +519,7 @@ export class AlgodApi { mediaType: undefined, }) - const responseMeta = GetSyncRoundMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as GetSyncRound + return AlgorandSerializer.decode(payload, GetSyncRoundMeta, responseFormat) } /** @@ -620,7 +530,7 @@ export class AlgodApi { const responseFormat: BodyFormat = 'msgpack' headers['Accept'] = AlgodApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/deltas/{round}/txn/group', path: { round: typeof round === 'bigint' ? round.toString() : round }, @@ -630,11 +540,7 @@ export class AlgodApi { mediaType: undefined, }) - const responseMeta = GetTransactionGroupLedgerStateDeltasForRoundMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as GetTransactionGroupLedgerStateDeltasForRound + return AlgorandSerializer.decode(payload, GetTransactionGroupLedgerStateDeltasForRoundMeta, responseFormat) } async getTransactionProof( @@ -646,7 +552,7 @@ export class AlgodApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = AlgodApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/blocks/{round}/transactions/{txid}/proof', path: { round: typeof round === 'bigint' ? round.toString() : round, txid: txid }, @@ -656,11 +562,7 @@ export class AlgodApi { mediaType: undefined, }) - const responseMeta = TransactionProofMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as TransactionProof + return AlgorandSerializer.decode(payload, TransactionProofMeta, responseFormat) } /** @@ -671,7 +573,7 @@ export class AlgodApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = AlgodApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/versions', path: {}, @@ -681,11 +583,7 @@ export class AlgodApi { mediaType: undefined, }) - const responseMeta = VersionMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as Version + return AlgorandSerializer.decode(payload, VersionMeta, responseFormat) } async healthCheck(): Promise { @@ -693,7 +591,7 @@ export class AlgodApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = AlgodApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + await this.httpRequest.request({ method: 'GET', url: '/health', path: {}, @@ -702,12 +600,6 @@ export class AlgodApi { body: undefined, mediaType: undefined, }) - - const responseMeta = undefined - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as void } /** @@ -722,7 +614,7 @@ export class AlgodApi { const responseFormat: BodyFormat = 'msgpack' headers['Accept'] = AlgodApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/transactions/pending/{txid}', path: { txid: txid }, @@ -732,11 +624,7 @@ export class AlgodApi { mediaType: undefined, }) - const responseMeta = PendingTransactionResponseMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as PendingTransactionResponse + return AlgorandSerializer.decode(payload, PendingTransactionResponseMeta, responseFormat) } private async _rawTransaction(body: Uint8Array): Promise { @@ -748,7 +636,7 @@ export class AlgodApi { const mediaType = 'application/msgpack' headers['Content-Type'] = mediaType - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'POST', url: '/v2/transactions', path: {}, @@ -758,11 +646,7 @@ export class AlgodApi { mediaType: mediaType, }) - const responseMeta = RawTransactionMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as RawTransaction + return AlgorandSerializer.decode(payload, RawTransactionMeta, responseFormat) } /** @@ -773,7 +657,7 @@ export class AlgodApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = AlgodApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + await this.httpRequest.request({ method: 'POST', url: '/v2/devmode/blocks/offset/{offset}', path: { offset: offset }, @@ -782,12 +666,6 @@ export class AlgodApi { body: undefined, mediaType: undefined, }) - - const responseMeta = undefined - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as void } /** @@ -798,7 +676,7 @@ export class AlgodApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = AlgodApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + await this.httpRequest.request({ method: 'POST', url: '/v2/ledger/sync/{round}', path: { round: typeof round === 'bigint' ? round.toString() : round }, @@ -807,12 +685,6 @@ export class AlgodApi { body: undefined, mediaType: undefined, }) - - const responseMeta = undefined - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as void } async simulateTransaction(body: SimulateRequest): Promise { @@ -823,9 +695,9 @@ export class AlgodApi { const bodyMeta = SimulateRequestMeta const mediaType = bodyMeta ? AlgodApi.mediaFor(responseFormat) : undefined if (mediaType) headers['Content-Type'] = mediaType - const serializedBody = bodyMeta && body !== undefined ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : body + const serializedBody = body ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : undefined - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'POST', url: '/v2/transactions/simulate', path: {}, @@ -835,11 +707,7 @@ export class AlgodApi { mediaType: mediaType, }) - const responseMeta = SimulateTransactionMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as SimulateTransaction + return AlgorandSerializer.decode(payload, SimulateTransactionMeta, responseFormat) } /** @@ -853,9 +721,9 @@ export class AlgodApi { const bodyMeta = undefined const mediaType = bodyMeta ? AlgodApi.mediaFor(responseFormat) : undefined if (mediaType) headers['Content-Type'] = mediaType - const serializedBody = bodyMeta && body !== undefined ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : body + const serializedBody = body - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'POST', url: '/v2/teal/compile', path: {}, @@ -865,11 +733,7 @@ export class AlgodApi { mediaType: mediaType, }) - const responseMeta = TealCompileMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as TealCompile + return AlgorandSerializer.decode(payload, TealCompileMeta, responseFormat) } /** @@ -884,7 +748,7 @@ export class AlgodApi { const mediaType = 'application/msgpack' headers['Content-Type'] = mediaType - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'POST', url: '/v2/teal/disassemble', path: {}, @@ -894,11 +758,7 @@ export class AlgodApi { mediaType: mediaType, }) - const responseMeta = TealDisassembleMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as TealDisassemble + return AlgorandSerializer.decode(payload, TealDisassembleMeta, responseFormat) } /** @@ -912,9 +772,9 @@ export class AlgodApi { const bodyMeta = DryrunRequestMeta const mediaType = bodyMeta ? AlgodApi.mediaFor(responseFormat) : undefined if (mediaType) headers['Content-Type'] = mediaType - const serializedBody = bodyMeta && body !== undefined ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : body + const serializedBody = body ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : undefined - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'POST', url: '/v2/teal/dryrun', path: {}, @@ -924,11 +784,7 @@ export class AlgodApi { mediaType: mediaType, }) - const responseMeta = TealDryrunMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as TealDryrun + return AlgorandSerializer.decode(payload, TealDryrunMeta, responseFormat) } private async _transactionParams(): Promise { @@ -936,7 +792,7 @@ export class AlgodApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = AlgodApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/transactions/params', path: {}, @@ -946,11 +802,7 @@ export class AlgodApi { mediaType: undefined, }) - const responseMeta = TransactionParamsMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as TransactionParams + return AlgorandSerializer.decode(payload, TransactionParamsMeta, responseFormat) } /** @@ -961,7 +813,7 @@ export class AlgodApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = AlgodApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + await this.httpRequest.request({ method: 'DELETE', url: '/v2/ledger/sync', path: {}, @@ -970,12 +822,6 @@ export class AlgodApi { body: undefined, mediaType: undefined, }) - - const responseMeta = undefined - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as void } /** @@ -986,7 +832,7 @@ export class AlgodApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = AlgodApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/status/wait-for-block-after/{round}', path: { round: typeof round === 'bigint' ? round.toString() : round }, @@ -996,11 +842,7 @@ export class AlgodApi { mediaType: undefined, }) - const responseMeta = WaitForBlockMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as WaitForBlock + return AlgorandSerializer.decode(payload, WaitForBlockMeta, responseFormat) } /** diff --git a/packages/algod_client/src/core/codecs.ts b/packages/algod_client/src/core/codecs.ts index 829dcd7b..214a543d 100644 --- a/packages/algod_client/src/core/codecs.ts +++ b/packages/algod_client/src/core/codecs.ts @@ -1,42 +1,28 @@ import { decode as msgpackDecode, encode as msgpackEncode } from 'algorand-msgpack' -export function encodeMsgPack(data: T): Uint8Array { +export function encodeMsgPack(data: ApiData): Uint8Array { return new Uint8Array(msgpackEncode(data, { sortKeys: true, ignoreUndefined: true })) } -export function decodeMsgPack(buffer: Uint8Array): T { - const map = msgpackDecode(buffer, { useMap: true }) as unknown - return mapToObject(map) as T +type MsgPackDecodeOptions = { + useMap: boolean + rawBinaryStringKeys: boolean + rawBinaryStringValues: boolean } -/** - * Converts a Map structure from msgpack decoding to a plain object structure. - * Maps are converted to objects recursively, except for the special case - * where the field name is "r" which remains as a Map. - */ -function mapToObject(value: unknown, fieldName?: string): unknown { - // Preserve Uint8Array as-is - if (value instanceof Uint8Array) { - return value - } else if (value instanceof Map) { - // Special case: keep "r" field as Map - if (fieldName === 'r') { - const newMap = new Map() - for (const [k, v] of value.entries()) { - newMap.set(k, mapToObject(v)) - } - return newMap - } - - // Convert Map to object - const obj: Record = {} - for (const [k, v] of value.entries()) { - obj[k] = mapToObject(v, k) - } - return obj - } else if (Array.isArray(value)) { - return value.map((item) => mapToObject(item)) - } - - return value +export function decodeMsgPack( + buffer: Uint8Array, + options: MsgPackDecodeOptions = { useMap: true, rawBinaryStringKeys: true, rawBinaryStringValues: true }, +): Map { + return msgpackDecode(buffer, options) as Map } +export type ApiData = + | null + | undefined + | string + | number + | bigint + | boolean + | Uint8Array + | object + | Map // TODO: NC - Do we ever have a string key? diff --git a/packages/algod_client/src/core/model-runtime.ts b/packages/algod_client/src/core/model-runtime.ts index ed41c188..07f6d681 100644 --- a/packages/algod_client/src/core/model-runtime.ts +++ b/packages/algod_client/src/core/model-runtime.ts @@ -1,19 +1,24 @@ import { - encodeSignedTransaction as transactEncodeSignedTransaction, - decodeSignedTransaction as transactDecodeSignedTransaction, + addressFromPublicKey, + decodedTransactionMapToObject, + fromSignedTransactionDto, + toSignedTransactionDto, type SignedTransaction, } from '@algorandfoundation/algokit-transact' -import { encodeMsgPack, decodeMsgPack } from './codecs' -import { toBase64, fromBase64 } from './serialization' +import { Buffer } from 'buffer' +import { ApiData, decodeMsgPack, encodeMsgPack } from './codecs' export type BodyFormat = 'json' | 'msgpack' | 'map' export interface ScalarFieldType { readonly kind: 'scalar' + // TODO: NC - Make this a type field readonly isBytes?: boolean readonly isBigint?: boolean + readonly isAddress?: boolean } +// TODO: NC - Needs to be renamed export interface CodecFieldType { readonly kind: 'codec' readonly codecKey: string @@ -34,7 +39,13 @@ export interface RecordFieldType { readonly value: FieldType } -export type FieldType = ScalarFieldType | CodecFieldType | ModelFieldType | ArrayFieldType | RecordFieldType +export interface MapFieldType { + readonly kind: 'map' + readonly keyType: 'number' | 'bigint' | 'bytes' + readonly value: FieldType +} + +export type FieldType = ScalarFieldType | CodecFieldType | ModelFieldType | ArrayFieldType | RecordFieldType | MapFieldType export interface FieldMetadata { readonly name: string @@ -61,39 +72,26 @@ export interface ModelMetadata { readonly passThrough?: FieldType } -// Registry for model metadata to avoid direct circular imports between model files -const modelMetaRegistry = new Map() - -export function registerModelMeta(name: string, meta: ModelMetadata): void { - modelMetaRegistry.set(name, meta) -} - -export function getModelMeta(name: string): ModelMetadata { - const meta = modelMetaRegistry.get(name) - if (!meta) throw new Error(`Model metadata not registered: ${name}`) - return meta -} - -export interface TypeCodec { - encode(value: TValue, format: BodyFormat): unknown - decode(value: unknown, format: BodyFormat): TValue +export interface EncodeableTypeConverter> { + beforeEncoding(value: T, format: BodyFormat): Record + afterDecoding(decoded: Record | Map, format: BodyFormat): T } -const codecRegistry = new Map>() - -export function registerCodec(key: string, codec: TypeCodec): void { - codecRegistry.set(key, codec as TypeCodec) -} +const encodeableTypeConverterRegistry = new Map>>() -export function getCodec(key: string): TypeCodec | undefined { - return codecRegistry.get(key) as TypeCodec | undefined +export function registerEncodeableTypeConverter(key: string, codec: EncodeableTypeConverter>): void { + encodeableTypeConverterRegistry.set(key, codec) } export class AlgorandSerializer { - static encode(value: unknown, meta: ModelMetadata, format: 'map'): Map - static encode(value: unknown, meta: ModelMetadata, format: 'json'): string - static encode(value: unknown, meta: ModelMetadata, format?: 'msgpack'): Uint8Array - static encode(value: unknown, meta: ModelMetadata, format: BodyFormat = 'msgpack'): Uint8Array | string | Map { + static encode(value: Record, meta: ModelMetadata, format: 'map'): Map + static encode(value: Record, meta: ModelMetadata, format: 'json'): string + static encode(value: Record, meta: ModelMetadata, format?: 'msgpack'): Uint8Array + static encode( + value: Record, + meta: ModelMetadata, + format: BodyFormat = 'msgpack', + ): Uint8Array | string | Map { if (format === 'map') { // For map format, use msgpack transformation to preserve types like bigint, then convert to nested Maps const wire = this.transform(value, meta, { direction: 'encode', format: 'msgpack' }) @@ -107,25 +105,25 @@ export class AlgorandSerializer { return typeof wire === 'string' ? wire : JSON.stringify(wire) } - static decode(payload: unknown, meta: ModelMetadata, format: BodyFormat = 'msgpack'): T { - let wire: unknown = payload + static decode(value: Uint8Array | string, meta: ModelMetadata, format: BodyFormat = 'msgpack'): T { + let wire: ApiData = value if (format === 'msgpack') { - if (payload instanceof Uint8Array) { - wire = decodeMsgPack(payload) + if (value instanceof Uint8Array) { + wire = decodeMsgPack(value) } - } else if (typeof payload === 'string') { - wire = JSON.parse(payload) + } else if (typeof value === 'string') { + wire = JSON.parse(value) } return this.transform(wire, meta, { direction: 'decode', format }) as T } - private static transform(value: unknown, meta: ModelMetadata, ctx: TransformContext): unknown { + private static transform(value: ApiData, meta: ModelMetadata, ctx: TransformContext): ApiData { if (value === undefined || value === null) { return value } if (meta.codecKey) { - return this.applyCodec(value, meta.codecKey, ctx) + return this.applyEncodeableTypeConversion(value, meta.codecKey, ctx) } switch (meta.kind) { @@ -139,20 +137,20 @@ export class AlgorandSerializer { } } - private static transformObject(value: unknown, meta: ModelMetadata, ctx: TransformContext): unknown { + private static transformObject(value: ApiData, meta: ModelMetadata, ctx: TransformContext): ApiData { const fields = meta.fields ?? [] - const hasFlattenedSignedTxn = fields.some((f) => f.flattened && f.type.kind === 'codec' && f.type.codecKey === 'SignedTransaction') + const hasFlattenedField = fields.some((f) => f.flattened) if (ctx.direction === 'encode') { - const src = value as Record - const out: Record = {} + const src = value as Record + const out: Record = {} for (const field of fields) { const fieldValue = src[field.name] if (fieldValue === undefined) continue const encoded = this.transformType(fieldValue, field.type, ctx) if (encoded === undefined && fieldValue === undefined) continue - if (field.flattened && field.type.kind === 'codec' && field.type.codecKey === 'SignedTransaction') { - // Merge signed transaction map into parent - const mapValue = encoded as Record + if (field.flattened) { + // Merge flattened field into parent + const mapValue = encoded as Record for (const [k, v] of Object.entries(mapValue ?? {})) out[k] = v continue } @@ -167,66 +165,206 @@ export class AlgorandSerializer { return out } - const src = value as Record - const out: Record = {} + // Decoding + const out: Record = {} const fieldByWire = new Map(fields.filter((f) => !!f.wireKey).map((field) => [field.wireKey as string, field])) - for (const [wireKey, wireValue] of Object.entries(src)) { - const field = fieldByWire.get(wireKey) + // Build a map of wire keys for each flattened field + const flattenedFieldWireKeys = new Map>() + if (hasFlattenedField) { + for (const field of fields) { + if (field.flattened && field.type.kind === 'model') { + const modelMeta = typeof field.type.meta === 'function' ? field.type.meta() : field.type.meta + const wireKeys = this.collectWireKeys(modelMeta) + flattenedFieldWireKeys.set(field, wireKeys) + } + } + } + + const entries = value instanceof Map ? Array.from(value.entries()) : Object.entries(value as Record) + const unmatchedEntries = new Map() + + for (const [key, wireValue] of entries) { + const wireKey = key instanceof Uint8Array ? Buffer.from(key).toString('utf-8') : key + const isStringKey = typeof wireKey === 'string' + const field = isStringKey ? fieldByWire.get(wireKey) : undefined + if (field) { const decoded = this.transformType(wireValue, field.type, ctx) - out[field.name] = decoded + out[field.name] = decoded === null && !field.nullable ? undefined : decoded continue } - if (meta.additionalProperties) { + + if (isStringKey && meta.additionalProperties) { out[wireKey] = this.transformType(wireValue, meta.additionalProperties, ctx) continue } - // If we have a flattened SignedTransaction, skip unknown keys (e.g., 'sig', 'txn') - if (!hasFlattenedSignedTxn) { - out[wireKey] = wireValue + + // Store unmatched entries for potential flattened field reconstruction + if (isStringKey) { + unmatchedEntries.set(wireKey, wireValue) + } + } + + // Reconstruct flattened fields from unmatched entries + if (hasFlattenedField) { + for (const field of fields) { + if (out[field.name] !== undefined) continue + if (field.flattened) { + if (field.type.kind === 'codec') { + // Reconstruct codec from entire object map + out[field.name] = this.applyEncodeableTypeConversion(value, field.type.codecKey, ctx) + } else if (field.type.kind === 'model') { + const modelMeta = typeof field.type.meta === 'function' ? field.type.meta() : field.type.meta + + // Check if this flattened model contains nested flattened codecs + const hasNestedCodec = this.hasNestedFlattenedCodec(modelMeta) + + let decoded: ApiData + if (hasNestedCodec) { + // If the model has nested flattened codecs, we need to pass the original value + // so the nested model can reconstruct its flattened codec fields + decoded = this.transform(value, modelMeta, ctx) + } else { + // Filter the wire data to only include keys belonging to this flattened model + const modelWireKeys = flattenedFieldWireKeys.get(field) + if (modelWireKeys) { + const filteredData: Record = {} + for (const [k, v] of unmatchedEntries.entries()) { + if (modelWireKeys.has(k)) { + filteredData[k] = v + } + } + // Also check if the original value is a Map and filter it + if (value instanceof Map) { + const filteredMap = new Map() + for (const [k, v] of value.entries()) { + const keyStr = k instanceof Uint8Array ? Buffer.from(k).toString('utf-8') : String(k) + if (typeof keyStr === 'string' && modelWireKeys.has(keyStr)) { + filteredMap.set(k as string | Uint8Array, v) + } + } + decoded = this.transform(filteredMap, modelMeta, ctx) + } else { + decoded = this.transform(filteredData, modelMeta, ctx) + } + } else { + decoded = undefined + } + } + + // If the field is optional and the decoded object is empty, set it to undefined + if (field.optional && decoded !== undefined && this.isEmptyObject(decoded)) { + out[field.name] = undefined + } else { + out[field.name] = decoded + } + } + } } } - // If there are flattened fields, attempt to reconstruct them from remaining keys by decoding - for (const field of fields) { - if (out[field.name] !== undefined) continue - if (field.flattened && field.type.kind === 'codec' && field.type.codecKey === 'SignedTransaction') { - // Reconstruct from entire object map - out[field.name] = this.applyCodec(src, 'SignedTransaction', ctx) + // Add any remaining unmatched entries if there are no flattened fields + if (!hasFlattenedField) { + for (const [k, v] of unmatchedEntries.entries()) { + out[k] = v } } return out } - private static transformType(value: unknown, type: FieldType, ctx: TransformContext): unknown { + private static collectWireKeys(meta: ModelMetadata): Set { + const wireKeys = new Set() + if (meta.kind !== 'object' || !meta.fields) return wireKeys + + for (const field of meta.fields) { + if (field.wireKey) { + wireKeys.add(field.wireKey) + } + if (field.flattened && field.type.kind === 'model') { + const childMeta = typeof field.type.meta === 'function' ? field.type.meta() : field.type.meta + const childKeys = this.collectWireKeys(childMeta) + for (const key of childKeys) { + wireKeys.add(key) + } + } + // Note: flattened codec fields don't have predictable wire keys, + // so they need to be handled differently during reconstruction + } + + return wireKeys + } + + private static hasNestedFlattenedCodec(meta: ModelMetadata): boolean { + if (meta.kind !== 'object' || !meta.fields) return false + + for (const field of meta.fields) { + if (field.flattened) { + if (field.type.kind === 'codec') { + return true + } + if (field.type.kind === 'model') { + const childMeta = typeof field.type.meta === 'function' ? field.type.meta() : field.type.meta + if (this.hasNestedFlattenedCodec(childMeta)) { + return true + } + } + } + } + + return false + } + + private static isEmptyObject(value: ApiData): boolean { + if (value === null || value === undefined) return true + if (typeof value !== 'object') return false + if (Array.isArray(value)) return false + if (value instanceof Uint8Array) return false + if (value instanceof Map) return value.size === 0 + + // Check if it's a plain object with no own properties (excluding undefined values) + const keys = Object.keys(value) + if (keys.length === 0) return true + + // Check if all properties are undefined + return keys.every((key) => (value as Record)[key] === undefined) + } + + private static transformType(value: ApiData, type: FieldType, ctx: TransformContext): ApiData { if (value === undefined || value === null) return value switch (type.kind) { case 'scalar': return this.transformScalar(value, type, ctx) case 'codec': - return this.applyCodec(value, type.codecKey, ctx) + return this.applyEncodeableTypeConversion(value, type.codecKey, ctx) case 'model': return this.transform(value, typeof type.meta === 'function' ? type.meta() : type.meta, ctx) case 'array': if (!Array.isArray(value)) return value return value.map((item) => this.transformType(item, type.item, ctx)) - case 'record': - if (typeof value !== 'object' || value === null) return value + case 'record': { + if ((!(value instanceof Map) && typeof value !== 'object') || value === null) return value + const entries = value instanceof Map ? Array.from(value.entries()) : Object.entries(value as Record) return Object.fromEntries( - Object.entries(value as Record).map(([k, v]) => [k, this.transformType(v, type.value, ctx)]), + entries.map(([k, v]) => { + const key = k instanceof Uint8Array ? Buffer.from(k).toString('utf-8') : k + return [key, this.transformType(v, type.value, ctx)] + }), ) + } + case 'map': + return this.transformMap(value, type, ctx) default: return value } } - private static transformScalar(value: unknown, meta: ScalarFieldType, ctx: TransformContext): unknown { + private static transformScalar(value: ApiData, meta: ScalarFieldType, ctx: TransformContext): ApiData { if (ctx.direction === 'encode') { if (meta.isBytes && ctx.format === 'json') { - if (value instanceof Uint8Array) return toBase64(value) + if (value instanceof Uint8Array) return Buffer.from(value).toString('base64') } if (meta.isBigint && ctx.format === 'json') { if (typeof value === 'bigint') return value.toString() @@ -237,7 +375,17 @@ export class AlgorandSerializer { } if (meta.isBytes && ctx.format === 'json' && typeof value === 'string') { - return fromBase64(value) + return new Uint8Array(Buffer.from(value, 'base64')) + } + + if (value instanceof Uint8Array) { + if (meta.isAddress) { + // TODO: NC - Fix all the address models to have this on it. + return addressFromPublicKey(value) + } else if (!meta.isBytes) { + return Buffer.from(value).toString('utf-8') + } + return value } if (meta.isBigint) { @@ -253,18 +401,61 @@ export class AlgorandSerializer { } } + if (value instanceof Map) { + const out: Record = {} + for (const [k, v] of value.entries()) { + const key = k instanceof Uint8Array ? Buffer.from(k).toString('utf-8') : k.toString() + out[key] = this.transformType(v, { kind: 'scalar', isBytes: v instanceof Uint8Array }, ctx) + } + return out + } + + if (Array.isArray(value)) { + return value.map((item) => this.transformType(item, { kind: 'scalar', isBytes: item instanceof Uint8Array }, ctx)) + } + return value } - private static applyCodec(value: unknown, codecKey: string, ctx: TransformContext): unknown { - const codec = codecRegistry.get(codecKey) + private static applyEncodeableTypeConversion(value: ApiData, typeKey: string, ctx: TransformContext): ApiData { + const codec = encodeableTypeConverterRegistry.get(typeKey) if (!codec) { - throw new Error(`Codec for "${codecKey}" is not registered`) + throw new Error(`Type converter for "${typeKey}" is not registered`) + } + + // TODO: NC - Need to properly guard against these conditions + if (ctx.direction === 'encode') { + if (value instanceof Map) { + throw new Error(`Cannot encode Map with type converter "${typeKey}"`) + } + return codec.beforeEncoding(value as Parameters[0], ctx.format) } - return ctx.direction === 'encode' ? codec.encode(value, ctx.format) : codec.decode(value, ctx.format) + + return codec.afterDecoding(value as Parameters[0], ctx.format) } - private static convertToNestedMaps(value: unknown): Map | unknown[] | unknown { + private static transformMap(value: ApiData, meta: MapFieldType, ctx: TransformContext): ApiData { + if (ctx.direction === 'encode') { + if (!(value instanceof Map)) return value + const result = new Map() + for (const [k, v] of value.entries()) { + const transformedValue = this.transformType(v, meta.value, ctx) + result.set(k, transformedValue) + } + return result + } + // Decoding + if ((!(value instanceof Map) && typeof value !== 'object') || value === null) return value + const entries = value instanceof Map ? Array.from(value.entries()) : Object.entries(value as Record) + const result = new Map() + for (const [k, v] of entries) { + const transformedValue = this.transformType(v, meta.value, ctx) + result.set(k, transformedValue) + } + return result + } + + private static convertToNestedMaps(value: ApiData): Map | ApiData[] | ApiData { if (value === null || value === undefined) { return value } @@ -282,8 +473,8 @@ export class AlgorandSerializer { } if (typeof value === 'object' && value !== null && !(value instanceof Uint8Array)) { - const map = new Map() - Object.entries(value as Record).forEach(([key, val]) => { + const map = new Map() + Object.entries(value as Record).forEach(([key, val]) => { map.set(key, this.convertToNestedMaps(val)) }) return map @@ -301,39 +492,23 @@ interface TransformContext { readonly format: BodyFormat } -const encodeSignedTransactionImpl = (value: unknown): Uint8Array => transactEncodeSignedTransaction(value as SignedTransaction) -const decodeSignedTransactionImpl = (value: Uint8Array): SignedTransaction => transactDecodeSignedTransaction(value) - -class SignedTransactionCodec implements TypeCodec { - encode(value: unknown, format: BodyFormat): unknown { - if (value == null) return value +class SignedTransactionConverter implements EncodeableTypeConverter { + beforeEncoding(value: SignedTransaction, format: BodyFormat): Record { if (format === 'json') { - if (value instanceof Uint8Array) return toBase64(value) - return toBase64(encodeSignedTransactionImpl(value)) - } - if (value instanceof Uint8Array) { - // Already canonical bytes; decode to structured map so parent encoding keeps map semantics - return decodeMsgPack(value) + throw new Error('JSON format not supported for SignedTransaction encoding') } - // Convert signed transaction object into canonical map representation - return decodeMsgPack(encodeSignedTransactionImpl(value)) + return toSignedTransactionDto(value) } - - decode(value: unknown, format: BodyFormat): unknown { - if (value == null) return value - if (format === 'json') { - if (typeof value === 'string') return decodeSignedTransactionImpl(fromBase64(value)) - if (value instanceof Uint8Array) return decodeSignedTransactionImpl(value) - return value + afterDecoding(value: Record | Map, format: BodyFormat): SignedTransaction { + if (format === 'json' || !(value instanceof Map)) { + throw new Error('JSON format not supported for SignedTransaction decoding') } - if (value instanceof Uint8Array) return decodeSignedTransactionImpl(value) - // Value is a decoded map; re-encode to bytes before handing to transact decoder - try { - return decodeSignedTransactionImpl(encodeMsgPack(value)) - } catch { - return value + if (!(value instanceof Map)) { + throw new Error('Invalid decoded msgpack format for SignedTransaction') } + const stxnDto = decodedTransactionMapToObject(value) as Parameters[0] + return fromSignedTransactionDto(stxnDto) } } -registerCodec('SignedTransaction', new SignedTransactionCodec()) +registerEncodeableTypeConverter('SignedTransaction', new SignedTransactionConverter()) diff --git a/packages/algod_client/src/core/request.ts b/packages/algod_client/src/core/request.ts index 112098a7..2f8f4d27 100644 --- a/packages/algod_client/src/core/request.ts +++ b/packages/algod_client/src/core/request.ts @@ -85,7 +85,11 @@ export async function request( try { const ct = response.headers.get('content-type') ?? '' if (ct.includes('application/msgpack')) { - errorBody = decodeMsgPack(new Uint8Array(await response.arrayBuffer())) + errorBody = decodeMsgPack(new Uint8Array(await response.arrayBuffer()), { + useMap: false, + rawBinaryStringKeys: false, + rawBinaryStringValues: false, + }) } else if (ct.includes('application/json')) { errorBody = JSON.parse(await response.text()) } else { diff --git a/packages/algod_client/src/core/serialization.ts b/packages/algod_client/src/core/serialization.ts deleted file mode 100644 index 6be05428..00000000 --- a/packages/algod_client/src/core/serialization.ts +++ /dev/null @@ -1,26 +0,0 @@ -export function toBase64(bytes: Uint8Array): string { - if (typeof Buffer !== 'undefined') { - return Buffer.from(bytes).toString('base64') - } - const globalRef: Record = globalThis as unknown as Record - const btoaFn = globalRef.btoa as ((value: string) => string) | undefined - if (typeof btoaFn === 'function') { - return btoaFn(String.fromCharCode(...bytes)) - } - throw new Error('Base64 encoding not supported in this environment') -} - -export function fromBase64(s: string): Uint8Array { - if (typeof Buffer !== 'undefined') { - return new Uint8Array(Buffer.from(s, 'base64')) - } - const globalRef: Record = globalThis as unknown as Record - const atobFn = globalRef.atob as ((value: string) => string) | undefined - if (typeof atobFn === 'function') { - const bin = atobFn(s) - const out = new Uint8Array(bin.length) - for (let i = 0; i < bin.length; i += 1) out[i] = bin.charCodeAt(i) - return out - } - throw new Error('Base64 decoding not supported in this environment') -} diff --git a/packages/algod_client/src/index.ts b/packages/algod_client/src/index.ts index 915506d5..58a6412d 100644 --- a/packages/algod_client/src/index.ts +++ b/packages/algod_client/src/index.ts @@ -2,7 +2,6 @@ export * from './core/client-config' export * from './core/base-http-request' export * from './core/fetch-http-request' export * from './core/api-error' -export * from './core/serialization' export * from './core/codecs' export * from './core/model-runtime' diff --git a/packages/algod_client/src/models/account-application-information.ts b/packages/algod_client/src/models/account-application-information.ts index 0042fb89..d2adbf6e 100644 --- a/packages/algod_client/src/models/account-application-information.ts +++ b/packages/algod_client/src/models/account-application-information.ts @@ -29,14 +29,14 @@ export const AccountApplicationInformationMeta: ModelMetadata = { wireKey: 'app-local-state', optional: true, nullable: false, - type: { kind: 'model', meta: () => ApplicationLocalStateMeta }, + type: { kind: 'model', meta: ApplicationLocalStateMeta }, }, { name: 'createdApp', wireKey: 'created-app', optional: true, nullable: false, - type: { kind: 'model', meta: () => ApplicationParamsMeta }, + type: { kind: 'model', meta: ApplicationParamsMeta }, }, ], } diff --git a/packages/algod_client/src/models/account-asset-information.ts b/packages/algod_client/src/models/account-asset-information.ts index 32b3e36b..09122a02 100644 --- a/packages/algod_client/src/models/account-asset-information.ts +++ b/packages/algod_client/src/models/account-asset-information.ts @@ -29,14 +29,14 @@ export const AccountAssetInformationMeta: ModelMetadata = { wireKey: 'asset-holding', optional: true, nullable: false, - type: { kind: 'model', meta: () => AssetHoldingMeta }, + type: { kind: 'model', meta: AssetHoldingMeta }, }, { name: 'createdAsset', wireKey: 'created-asset', optional: true, nullable: false, - type: { kind: 'model', meta: () => AssetParamsMeta }, + type: { kind: 'model', meta: AssetParamsMeta }, }, ], } diff --git a/packages/algod_client/src/models/account-state-delta.ts b/packages/algod_client/src/models/account-state-delta.ts index ad93395f..d7ddbc6a 100644 --- a/packages/algod_client/src/models/account-state-delta.ts +++ b/packages/algod_client/src/models/account-state-delta.ts @@ -26,7 +26,7 @@ export const AccountStateDeltaMeta: ModelMetadata = { wireKey: 'delta', optional: false, nullable: false, - type: { kind: 'model', meta: () => StateDeltaMeta }, + type: { kind: 'model', meta: StateDeltaMeta }, }, ], } diff --git a/packages/algod_client/src/models/account.ts b/packages/algod_client/src/models/account.ts index 7824c468..c5a45366 100644 --- a/packages/algod_client/src/models/account.ts +++ b/packages/algod_client/src/models/account.ts @@ -200,7 +200,7 @@ export const AccountMeta: ModelMetadata = { wireKey: 'apps-local-state', optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => ApplicationLocalStateMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: ApplicationLocalStateMeta } }, }, { name: 'totalAppsOptedIn', @@ -214,7 +214,7 @@ export const AccountMeta: ModelMetadata = { wireKey: 'apps-total-schema', optional: true, nullable: false, - type: { kind: 'model', meta: () => ApplicationStateSchemaMeta }, + type: { kind: 'model', meta: ApplicationStateSchemaMeta }, }, { name: 'appsTotalExtraPages', @@ -228,7 +228,7 @@ export const AccountMeta: ModelMetadata = { wireKey: 'assets', optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => AssetHoldingMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: AssetHoldingMeta } }, }, { name: 'totalAssetsOptedIn', @@ -242,7 +242,7 @@ export const AccountMeta: ModelMetadata = { wireKey: 'created-apps', optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => ApplicationMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: ApplicationMeta } }, }, { name: 'totalCreatedApps', @@ -256,7 +256,7 @@ export const AccountMeta: ModelMetadata = { wireKey: 'created-assets', optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => AssetMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: AssetMeta } }, }, { name: 'totalCreatedAssets', @@ -284,7 +284,7 @@ export const AccountMeta: ModelMetadata = { wireKey: 'participation', optional: true, nullable: false, - type: { kind: 'model', meta: () => AccountParticipationMeta }, + type: { kind: 'model', meta: AccountParticipationMeta }, }, { name: 'incentiveEligible', diff --git a/packages/algod_client/src/models/application-initial-states.ts b/packages/algod_client/src/models/application-initial-states.ts index 22acf411..e9592880 100644 --- a/packages/algod_client/src/models/application-initial-states.ts +++ b/packages/algod_client/src/models/application-initial-states.ts @@ -35,21 +35,21 @@ export const ApplicationInitialStatesMeta: ModelMetadata = { wireKey: 'app-locals', optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => ApplicationKvStorageMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: ApplicationKvStorageMeta } }, }, { name: 'appGlobals', wireKey: 'app-globals', optional: true, nullable: false, - type: { kind: 'model', meta: () => ApplicationKvStorageMeta }, + type: { kind: 'model', meta: ApplicationKvStorageMeta }, }, { name: 'appBoxes', wireKey: 'app-boxes', optional: true, nullable: false, - type: { kind: 'model', meta: () => ApplicationKvStorageMeta }, + type: { kind: 'model', meta: ApplicationKvStorageMeta }, }, ], } diff --git a/packages/algod_client/src/models/application-kv-storage.ts b/packages/algod_client/src/models/application-kv-storage.ts index c69a95d5..2221bbaf 100644 --- a/packages/algod_client/src/models/application-kv-storage.ts +++ b/packages/algod_client/src/models/application-kv-storage.ts @@ -26,7 +26,7 @@ export const ApplicationKvStorageMeta: ModelMetadata = { wireKey: 'kvs', optional: false, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => AvmKeyValueMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: AvmKeyValueMeta } }, }, { name: 'account', diff --git a/packages/algod_client/src/models/application-local-state.ts b/packages/algod_client/src/models/application-local-state.ts index a04e8a24..9f89eee8 100644 --- a/packages/algod_client/src/models/application-local-state.ts +++ b/packages/algod_client/src/models/application-local-state.ts @@ -32,14 +32,14 @@ export const ApplicationLocalStateMeta: ModelMetadata = { wireKey: 'schema', optional: false, nullable: false, - type: { kind: 'model', meta: () => ApplicationStateSchemaMeta }, + type: { kind: 'model', meta: ApplicationStateSchemaMeta }, }, { name: 'keyValue', wireKey: 'key-value', optional: true, nullable: false, - type: { kind: 'model', meta: () => TealKeyValueStoreMeta }, + type: { kind: 'model', meta: TealKeyValueStoreMeta }, }, ], } diff --git a/packages/algod_client/src/models/application-params.ts b/packages/algod_client/src/models/application-params.ts index 2a045128..8b51a6bf 100644 --- a/packages/algod_client/src/models/application-params.ts +++ b/packages/algod_client/src/models/application-params.ts @@ -74,21 +74,21 @@ export const ApplicationParamsMeta: ModelMetadata = { wireKey: 'local-state-schema', optional: true, nullable: false, - type: { kind: 'model', meta: () => ApplicationStateSchemaMeta }, + type: { kind: 'model', meta: ApplicationStateSchemaMeta }, }, { name: 'globalStateSchema', wireKey: 'global-state-schema', optional: true, nullable: false, - type: { kind: 'model', meta: () => ApplicationStateSchemaMeta }, + type: { kind: 'model', meta: ApplicationStateSchemaMeta }, }, { name: 'globalState', wireKey: 'global-state', optional: true, nullable: false, - type: { kind: 'model', meta: () => TealKeyValueStoreMeta }, + type: { kind: 'model', meta: TealKeyValueStoreMeta }, }, { name: 'version', diff --git a/packages/algod_client/src/models/application-state-operation.ts b/packages/algod_client/src/models/application-state-operation.ts index 00020f19..993fbc44 100644 --- a/packages/algod_client/src/models/application-state-operation.ts +++ b/packages/algod_client/src/models/application-state-operation.ts @@ -58,7 +58,7 @@ export const ApplicationStateOperationMeta: ModelMetadata = { wireKey: 'new-value', optional: true, nullable: false, - type: { kind: 'model', meta: () => AvmValueMeta }, + type: { kind: 'model', meta: AvmValueMeta }, }, { name: 'account', diff --git a/packages/algod_client/src/models/application.ts b/packages/algod_client/src/models/application.ts index c2ae6148..88e19da5 100644 --- a/packages/algod_client/src/models/application.ts +++ b/packages/algod_client/src/models/application.ts @@ -29,7 +29,7 @@ export const ApplicationMeta: ModelMetadata = { wireKey: 'params', optional: false, nullable: false, - type: { kind: 'model', meta: () => ApplicationParamsMeta }, + type: { kind: 'model', meta: ApplicationParamsMeta }, }, ], } diff --git a/packages/algod_client/src/models/asset.ts b/packages/algod_client/src/models/asset.ts index 3c12777b..904c9b99 100644 --- a/packages/algod_client/src/models/asset.ts +++ b/packages/algod_client/src/models/asset.ts @@ -9,7 +9,7 @@ export type Asset = { /** * unique asset identifier */ - index: bigint + id: bigint params: AssetParams } @@ -18,7 +18,7 @@ export const AssetMeta: ModelMetadata = { kind: 'object', fields: [ { - name: 'index', + name: 'id', wireKey: 'index', optional: false, nullable: false, @@ -29,7 +29,7 @@ export const AssetMeta: ModelMetadata = { wireKey: 'params', optional: false, nullable: false, - type: { kind: 'model', meta: () => AssetParamsMeta }, + type: { kind: 'model', meta: AssetParamsMeta }, }, ], } diff --git a/packages/algod_client/src/models/avm-key-value.ts b/packages/algod_client/src/models/avm-key-value.ts index 5d0ef4ce..8385c46a 100644 --- a/packages/algod_client/src/models/avm-key-value.ts +++ b/packages/algod_client/src/models/avm-key-value.ts @@ -26,7 +26,7 @@ export const AvmKeyValueMeta: ModelMetadata = { wireKey: 'value', optional: false, nullable: false, - type: { kind: 'model', meta: () => AvmValueMeta }, + type: { kind: 'model', meta: AvmValueMeta }, }, ], } diff --git a/packages/algod_client/src/models/block-account-state-delta.ts b/packages/algod_client/src/models/block-account-state-delta.ts deleted file mode 100644 index f40192ca..00000000 --- a/packages/algod_client/src/models/block-account-state-delta.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { ModelMetadata } from '../core/model-runtime' -import { registerModelMeta } from '../core/model-runtime' -import { BlockStateDeltaMeta } from './block-state-delta' - -/** BlockAccountStateDelta pairs an address with a BlockStateDelta map. */ -export interface BlockAccountStateDelta { - address: string - delta: import('./block-state-delta').BlockStateDelta -} - -export const BlockAccountStateDeltaMeta: ModelMetadata = { - name: 'BlockAccountStateDelta', - kind: 'object', - fields: [ - { name: 'address', wireKey: 'address', optional: false, nullable: false, type: { kind: 'scalar' } }, - { name: 'delta', wireKey: 'delta', optional: false, nullable: false, type: { kind: 'model', meta: () => BlockStateDeltaMeta } }, - ], -} - -registerModelMeta('BlockAccountStateDelta', BlockAccountStateDeltaMeta) diff --git a/packages/algod_client/src/models/block-app-eval-delta.ts b/packages/algod_client/src/models/block-app-eval-delta.ts deleted file mode 100644 index bc3b0d80..00000000 --- a/packages/algod_client/src/models/block-app-eval-delta.ts +++ /dev/null @@ -1,53 +0,0 @@ -import type { ModelMetadata } from '../core/model-runtime' -import { getModelMeta, registerModelMeta } from '../core/model-runtime' -import type { SignedTxnInBlock } from './signed-txn-in-block' -import type { BlockStateDelta } from './block-state-delta' -import { BlockStateDeltaMeta } from './block-state-delta' - -/** - * State changes from application execution, including inner transactions and logs. - */ -export interface BlockAppEvalDelta { - /** [gd] Global state delta for the application. */ - globalDelta?: BlockStateDelta - /** [ld] Local state deltas keyed by address index. */ - localDeltas?: Record - /** [itx] Inner transactions produced by this application execution. */ - innerTxns?: SignedTxnInBlock[] - /** [sa] Shared accounts referenced by local deltas. */ - sharedAccounts?: Uint8Array[] - /** [lg] Application log outputs. */ - logs?: Uint8Array[] -} - -export const BlockAppEvalDeltaMeta: ModelMetadata = { - name: 'BlockAppEvalDelta', - kind: 'object', - fields: [ - { name: 'globalDelta', wireKey: 'gd', optional: true, nullable: false, type: { kind: 'model', meta: () => BlockStateDeltaMeta } }, - { - name: 'localDeltas', - wireKey: 'ld', - optional: true, - nullable: false, - type: { kind: 'record', value: { kind: 'model', meta: () => BlockStateDeltaMeta } }, - }, - { - name: 'innerTxns', - wireKey: 'itx', - optional: true, - nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => getModelMeta('SignedTxnInBlock') } }, - }, - { - name: 'sharedAccounts', - wireKey: 'sa', - optional: true, - nullable: false, - type: { kind: 'array', item: { kind: 'scalar', isBytes: true } }, - }, - { name: 'logs', wireKey: 'lg', optional: true, nullable: false, type: { kind: 'array', item: { kind: 'scalar', isBytes: true } } }, - ], -} - -registerModelMeta('BlockAppEvalDelta', BlockAppEvalDeltaMeta) diff --git a/packages/algod_client/src/models/block-eval-delta.ts b/packages/algod_client/src/models/block-eval-delta.ts deleted file mode 100644 index faab05dd..00000000 --- a/packages/algod_client/src/models/block-eval-delta.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { ModelMetadata } from '../core/model-runtime' -import { registerModelMeta } from '../core/model-runtime' - -/** BlockEvalDelta represents a TEAL value delta (block/msgpack wire keys). */ -export interface BlockEvalDelta { - /** [at] delta action. */ - action: number - /** [bs] bytes value. */ - bytes?: string - /** [ui] uint value. */ - uint?: bigint -} - -export const BlockEvalDeltaMeta: ModelMetadata = { - name: 'BlockEvalDelta', - kind: 'object', - fields: [ - { name: 'action', wireKey: 'at', optional: false, nullable: false, type: { kind: 'scalar' } }, - { name: 'bytes', wireKey: 'bs', optional: true, nullable: false, type: { kind: 'scalar' } }, - { name: 'uint', wireKey: 'ui', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, - ], -} - -registerModelMeta('BlockEvalDelta', BlockEvalDeltaMeta) diff --git a/packages/algod_client/src/models/block-state-delta.ts b/packages/algod_client/src/models/block-state-delta.ts deleted file mode 100644 index b3ebdc36..00000000 --- a/packages/algod_client/src/models/block-state-delta.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { ModelMetadata } from '../core/model-runtime' -import { registerModelMeta } from '../core/model-runtime' -import { BlockEvalDeltaMeta } from './block-eval-delta' - -/** BlockStateDelta is a map keyed by state key to BlockEvalDelta. */ -export type BlockStateDelta = Record - -export const BlockStateDeltaMeta: ModelMetadata = { - name: 'BlockStateDelta', - kind: 'object', - additionalProperties: { kind: 'model', meta: () => BlockEvalDeltaMeta }, -} - -registerModelMeta('BlockStateDelta', BlockStateDeltaMeta) diff --git a/packages/algod_client/src/models/block.ts b/packages/algod_client/src/models/block.ts index e64b8a25..1e59f5e9 100644 --- a/packages/algod_client/src/models/block.ts +++ b/packages/algod_client/src/models/block.ts @@ -1,13 +1,213 @@ +import { SignedTransaction } from '@algorandfoundation/algokit-transact' import type { ModelMetadata } from '../core/model-runtime' -import type { SignedTxnInBlock } from './signed-txn-in-block' -import { SignedTxnInBlockMeta } from './signed-txn-in-block' -import type { BlockStateProofTracking } from './block_state_proof_tracking' -import { BlockStateProofTrackingMeta } from './block_state_proof_tracking' + +/** BlockEvalDelta represents a TEAL value delta (block/msgpack wire keys). */ +export type BlockEvalDelta = { + /** [at] delta action. */ + action: number + /** [bs] bytes value. */ + bytes?: string + /** [ui] uint value. */ + uint?: bigint +} + +export const BlockEvalDeltaMeta: ModelMetadata = { + name: 'BlockEvalDelta', + kind: 'object', + fields: [ + { name: 'action', wireKey: 'at', optional: false, nullable: false, type: { kind: 'scalar' } }, + { name: 'bytes', wireKey: 'bs', optional: true, nullable: false, type: { kind: 'scalar' } }, + { name: 'uint', wireKey: 'ui', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + ], +} /** - * Block contains the BlockHeader and the list of transactions (Payset). + * State changes from application execution, including inner transactions and logs. + */ +export type BlockAppEvalDelta = { + /** [gd] Global state delta for the application. */ + globalDelta?: Map + /** [ld] Local state deltas keyed by address index. */ + localDeltas?: Map> + /** [itx] Inner transactions produced by this application execution. */ + innerTxns?: SignedTxnInBlock[] + /** [sa] Shared accounts referenced by local deltas. */ + sharedAccounts?: string[] + /** [lg] Application log outputs. */ + logs?: Uint8Array[] +} + +export const BlockAppEvalDeltaMeta: ModelMetadata = { + name: 'BlockAppEvalDelta', + kind: 'object', + fields: [ + { + name: 'globalDelta', + wireKey: 'gd', + optional: true, + nullable: false, + type: { kind: 'map', keyType: 'bytes', value: { kind: 'model', meta: BlockEvalDeltaMeta } }, + }, + { + name: 'localDeltas', + wireKey: 'ld', + optional: true, + nullable: false, + type: { + kind: 'map', + keyType: 'number', + value: { kind: 'map', keyType: 'bytes', value: { kind: 'model', meta: BlockEvalDeltaMeta } }, + }, + }, + { + name: 'innerTxns', + wireKey: 'itx', + optional: true, + nullable: false, + type: { kind: 'array', item: { kind: 'model', meta: () => SignedTxnInBlockMeta } }, + }, + { + name: 'sharedAccounts', + wireKey: 'sa', + optional: true, + nullable: false, + type: { kind: 'array', item: { kind: 'scalar', isAddress: true } }, + }, + { name: 'logs', wireKey: 'lg', optional: true, nullable: false, type: { kind: 'array', item: { kind: 'scalar', isBytes: true } } }, + ], +} + +/** Tracking metadata for a specific StateProofType. */ +export type BlockStateProofTrackingData = { + /** [v] Vector commitment root of state proof voters. */ + stateProofVotersCommitment?: Uint8Array + /** [t] Online total weight during state proof round. */ + stateProofOnlineTotalWeight?: bigint + /** [n] Next round for which state proofs are accepted. */ + stateProofNextRound?: bigint +} + +export const BlockStateProofTrackingDataMeta: ModelMetadata = { + name: 'BlockStateProofTrackingData', + kind: 'object', + fields: [ + { name: 'stateProofVotersCommitment', wireKey: 'v', optional: true, nullable: false, type: { kind: 'scalar', isBytes: true } }, + { name: 'stateProofOnlineTotalWeight', wireKey: 't', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'stateProofNextRound', wireKey: 'n', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + ], +} + +export type ApplyData = { + closingAmount?: bigint + assetClosingAmount?: bigint + senderRewards?: bigint + receiverRewards?: bigint + closeRewards?: bigint + evalDelta?: BlockAppEvalDelta + configAsset?: bigint + applicationId?: bigint +} + +export const ApplyDataMeta: ModelMetadata = { + name: 'SignedTxnInBlock', + kind: 'object', + fields: [ + { name: 'closingAmount', wireKey: 'ca', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'assetClosingAmount', wireKey: 'aca', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'senderRewards', wireKey: 'rs', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'receiverRewards', wireKey: 'rr', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'closeRewards', wireKey: 'rc', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'evalDelta', wireKey: 'dt', optional: true, nullable: false, type: { kind: 'model', meta: BlockAppEvalDeltaMeta } }, + { name: 'configAsset', wireKey: 'caid', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'applicationId', wireKey: 'apid', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + ], +} + +/** + * SignedTxnWithAD is a SignedTransaction with additional ApplyData. */ -export interface Block { +export type SignedTxnWithAD = { + /** The signed transaction. */ + signedTxn: SignedTransaction + /** Apply data containing transaction execution information. */ + applyData: ApplyData +} + +export const SignedTxnWithADMeta: ModelMetadata = { + name: 'SignedTxnWithAD', + kind: 'object', + fields: [ + { + name: 'signedTransaction', + flattened: true, + optional: false, + nullable: false, + type: { kind: 'codec', codecKey: 'SignedTransaction' }, + }, + { + name: 'applyData', + flattened: true, + optional: true, + nullable: false, + type: { kind: 'model', meta: ApplyDataMeta }, + }, + ], +} + +/** + * SignedTxnInBlock is a SignedTransaction with additional ApplyData and block-specific metadata. + */ +export type SignedTxnInBlock = { + signedTransaction: SignedTxnWithAD + hasGenesisId?: boolean + hasGenesisHash?: boolean +} + +export const SignedTxnInBlockMeta: ModelMetadata = { + name: 'SignedTxnInBlock', + kind: 'object', + fields: [ + { + name: 'signedTransaction', + flattened: true, + optional: false, + nullable: false, + type: { kind: 'model', meta: SignedTxnWithADMeta }, + }, + { name: 'hasGenesisId', wireKey: 'hgi', optional: true, nullable: false, type: { kind: 'scalar' } }, + { name: 'hasGenesisHash', wireKey: 'hgh', optional: true, nullable: false, type: { kind: 'scalar' } }, + ], +} + +export type ParticipationUpdates = { + /** [partupdrmv] Expired participation accounts. */ + expiredParticipationAccounts?: string[] + /** [partupdabs] Absent participation accounts. */ + absentParticipationAccounts?: string[] +} + +export const ParticipationUpdatesMeta: ModelMetadata = { + name: 'ParticipationUpdates', + kind: 'object', + fields: [ + { + name: 'expiredParticipationAccounts', + wireKey: 'partupdrmv', + optional: true, + nullable: false, + type: { kind: 'array', item: { kind: 'scalar', isAddress: true } }, + }, + { + name: 'absentParticipationAccounts', + wireKey: 'partupdabs', + optional: true, + nullable: false, + type: { kind: 'array', item: { kind: 'scalar', isAddress: true } }, + }, + ], +} + +export type BlockHeader = { /** [rnd] Round number. */ round?: bigint /** [prev] Previous block hash. */ @@ -29,7 +229,7 @@ export interface Block { /** [gh] Genesis hash. */ genesisHash?: Uint8Array /** [prp] Proposer address. */ - proposer?: Uint8Array + proposer?: string /** [fc] Fees collected in this block. */ feesCollected?: bigint /** [bi] Bonus incentive for block proposal. */ @@ -37,9 +237,9 @@ export interface Block { /** [pp] Proposer payout. */ proposerPayout?: bigint /** [fees] FeeSink address. */ - feeSink?: Uint8Array + feeSink?: string /** [rwd] RewardsPool address. */ - rewardsPool?: Uint8Array + rewardsPool?: string /** [earn] Rewards level. */ rewardsLevel?: bigint /** [rate] Rewards rate. */ @@ -67,35 +267,31 @@ export interface Block { /** [tc] Transaction counter. */ txnCounter?: bigint /** [spt] State proof tracking data keyed by state proof type. */ - stateProofTracking?: BlockStateProofTracking - /** [partupdrmv] Expired participation accounts. */ - expiredParticipationAccounts?: Uint8Array[] - /** [partupdabs] Absent participation accounts. */ - absentParticipationAccounts?: Uint8Array[] - /** [txns] Block transactions (Payset). */ - transactions?: SignedTxnInBlock[] + stateProofTracking?: Map + /** Represents participation account data that needs to be checked/acted on by the network */ + participationUpdates?: ParticipationUpdates } -export const BlockMeta: ModelMetadata = { - name: 'Block', +export const BlockHeaderMeta: ModelMetadata = { + name: 'BlockHeader', kind: 'object', fields: [ { name: 'round', wireKey: 'rnd', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, { name: 'previousBlockHash', wireKey: 'prev', optional: true, nullable: false, type: { kind: 'scalar', isBytes: true } }, { name: 'previousBlockHash512', wireKey: 'prev512', optional: true, nullable: false, type: { kind: 'scalar', isBytes: true } }, { name: 'seed', wireKey: 'seed', optional: true, nullable: false, type: { kind: 'scalar', isBytes: true } }, - { name: 'transactionsRoot', wireKey: 'txn', optional: true, nullable: false, type: { kind: 'scalar', isBytes: true } }, + { name: 'transactionsRoot', wireKey: 'txn', optional: false, nullable: false, type: { kind: 'scalar', isBytes: true } }, { name: 'transactionsRootSha256', wireKey: 'txn256', optional: true, nullable: false, type: { kind: 'scalar', isBytes: true } }, { name: 'transactionsRootSha512', wireKey: 'txn512', optional: true, nullable: false, type: { kind: 'scalar', isBytes: true } }, { name: 'timestamp', wireKey: 'ts', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, { name: 'genesisId', wireKey: 'gen', optional: true, nullable: false, type: { kind: 'scalar' } }, { name: 'genesisHash', wireKey: 'gh', optional: true, nullable: false, type: { kind: 'scalar', isBytes: true } }, - { name: 'proposer', wireKey: 'prp', optional: true, nullable: false, type: { kind: 'scalar', isBytes: true } }, + { name: 'proposer', wireKey: 'prp', optional: true, nullable: false, type: { kind: 'scalar', isAddress: true } }, { name: 'feesCollected', wireKey: 'fc', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, { name: 'bonus', wireKey: 'bi', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, { name: 'proposerPayout', wireKey: 'pp', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, - { name: 'feeSink', wireKey: 'fees', optional: true, nullable: false, type: { kind: 'scalar', isBytes: true } }, - { name: 'rewardsPool', wireKey: 'rwd', optional: true, nullable: false, type: { kind: 'scalar', isBytes: true } }, + { name: 'feeSink', wireKey: 'fees', optional: true, nullable: false, type: { kind: 'scalar', isAddress: true } }, + { name: 'rewardsPool', wireKey: 'rwd', optional: true, nullable: false, type: { kind: 'scalar', isAddress: true } }, { name: 'rewardsLevel', wireKey: 'earn', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, { name: 'rewardsRate', wireKey: 'rate', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, { name: 'rewardsResidue', wireKey: 'frac', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, @@ -114,28 +310,40 @@ export const BlockMeta: ModelMetadata = { wireKey: 'spt', optional: true, nullable: false, - type: { kind: 'model', meta: () => BlockStateProofTrackingMeta }, + type: { kind: 'map', keyType: 'number', value: { kind: 'model', meta: BlockStateProofTrackingDataMeta } }, }, { - name: 'expiredParticipationAccounts', - wireKey: 'partupdrmv', - optional: true, - nullable: false, - type: { kind: 'array', item: { kind: 'scalar', isBytes: true } }, - }, - { - name: 'absentParticipationAccounts', - wireKey: 'partupdabs', + name: 'participationUpdates', + flattened: true, optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'scalar', isBytes: true } }, + type: { kind: 'model', meta: ParticipationUpdatesMeta }, }, + ], +} + +/** + * Block contains the BlockHeader and the list of transactions (Payset). + */ +export type Block = { + /** The block information (Header) */ + header: BlockHeader + + /** [txns] Block transactions (Payset). */ + payset?: SignedTxnInBlock[] +} + +export const BlockMeta: ModelMetadata = { + name: 'Block', + kind: 'object', + fields: [ + { name: 'header', flattened: true, optional: false, nullable: false, type: { kind: 'model', meta: BlockHeaderMeta } }, { - name: 'transactions', + name: 'payset', wireKey: 'txns', optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => SignedTxnInBlockMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: SignedTxnInBlockMeta } }, }, ], } diff --git a/packages/algod_client/src/models/block_state_proof_tracking.ts b/packages/algod_client/src/models/block_state_proof_tracking.ts deleted file mode 100644 index 8fba4555..00000000 --- a/packages/algod_client/src/models/block_state_proof_tracking.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { ModelMetadata } from '../core/model-runtime' -import { registerModelMeta } from '../core/model-runtime' -import type { BlockStateProofTrackingData } from './block_state_proof_tracking_data' -import { BlockStateProofTrackingDataMeta } from './block_state_proof_tracking_data' - -/** Tracks state proof metadata by state proof type. */ -export type BlockStateProofTracking = Record - -export const BlockStateProofTrackingMeta: ModelMetadata = { - name: 'BlockStateProofTracking', - kind: 'object', - additionalProperties: { kind: 'model', meta: () => BlockStateProofTrackingDataMeta }, -} - -registerModelMeta('BlockStateProofTracking', BlockStateProofTrackingMeta) diff --git a/packages/algod_client/src/models/block_state_proof_tracking_data.ts b/packages/algod_client/src/models/block_state_proof_tracking_data.ts deleted file mode 100644 index db995ca2..00000000 --- a/packages/algod_client/src/models/block_state_proof_tracking_data.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { ModelMetadata } from '../core/model-runtime' -import { registerModelMeta } from '../core/model-runtime' - -/** Tracking metadata for a specific StateProofType. */ -export interface BlockStateProofTrackingData { - /** [v] Vector commitment root of state proof voters. */ - stateProofVotersCommitment?: Uint8Array - /** [t] Online total weight during state proof round. */ - stateProofOnlineTotalWeight?: bigint - /** [n] Next round for which state proofs are accepted. */ - stateProofNextRound?: bigint -} - -export const BlockStateProofTrackingDataMeta: ModelMetadata = { - name: 'BlockStateProofTrackingData', - kind: 'object', - fields: [ - { name: 'stateProofVotersCommitment', wireKey: 'v', optional: true, nullable: false, type: { kind: 'scalar', isBytes: true } }, - { name: 'stateProofOnlineTotalWeight', wireKey: 't', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, - { name: 'stateProofNextRound', wireKey: 'n', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, - ], -} - -registerModelMeta('BlockStateProofTrackingData', BlockStateProofTrackingDataMeta) diff --git a/packages/algod_client/src/models/dryrun-request.ts b/packages/algod_client/src/models/dryrun-request.ts index 4786220b..3a23c69c 100644 --- a/packages/algod_client/src/models/dryrun-request.ts +++ b/packages/algod_client/src/models/dryrun-request.ts @@ -48,14 +48,14 @@ export const DryrunRequestMeta: ModelMetadata = { wireKey: 'accounts', optional: false, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => AccountMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: AccountMeta } }, }, { name: 'apps', wireKey: 'apps', optional: false, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => ApplicationMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: ApplicationMeta } }, }, { name: 'protocolVersion', @@ -83,7 +83,7 @@ export const DryrunRequestMeta: ModelMetadata = { wireKey: 'sources', optional: false, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => DryrunSourceMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: DryrunSourceMeta } }, }, ], } diff --git a/packages/algod_client/src/models/dryrun-state.ts b/packages/algod_client/src/models/dryrun-state.ts index 4f10c829..68d9a8d0 100644 --- a/packages/algod_client/src/models/dryrun-state.ts +++ b/packages/algod_client/src/models/dryrun-state.ts @@ -47,14 +47,14 @@ export const DryrunStateMeta: ModelMetadata = { wireKey: 'stack', optional: false, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => TealValueMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: TealValueMeta } }, }, { name: 'scratch', wireKey: 'scratch', optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => TealValueMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: TealValueMeta } }, }, { name: 'error', diff --git a/packages/algod_client/src/models/dryrun-txn-result.ts b/packages/algod_client/src/models/dryrun-txn-result.ts index c87cdf57..cc0b867c 100644 --- a/packages/algod_client/src/models/dryrun-txn-result.ts +++ b/packages/algod_client/src/models/dryrun-txn-result.ts @@ -61,7 +61,7 @@ export const DryrunTxnResultMeta: ModelMetadata = { wireKey: 'logic-sig-trace', optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => DryrunStateMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: DryrunStateMeta } }, }, { name: 'logicSigMessages', @@ -75,7 +75,7 @@ export const DryrunTxnResultMeta: ModelMetadata = { wireKey: 'app-call-trace', optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => DryrunStateMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: DryrunStateMeta } }, }, { name: 'appCallMessages', @@ -89,14 +89,14 @@ export const DryrunTxnResultMeta: ModelMetadata = { wireKey: 'global-delta', optional: true, nullable: false, - type: { kind: 'model', meta: () => StateDeltaMeta }, + type: { kind: 'model', meta: StateDeltaMeta }, }, { name: 'localDeltas', wireKey: 'local-deltas', optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => AccountStateDeltaMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: AccountStateDeltaMeta } }, }, { name: 'logs', diff --git a/packages/algod_client/src/models/eval-delta-key-value.ts b/packages/algod_client/src/models/eval-delta-key-value.ts index 31a0689a..897ff226 100644 --- a/packages/algod_client/src/models/eval-delta-key-value.ts +++ b/packages/algod_client/src/models/eval-delta-key-value.ts @@ -26,7 +26,7 @@ export const EvalDeltaKeyValueMeta: ModelMetadata = { wireKey: 'value', optional: false, nullable: false, - type: { kind: 'model', meta: () => EvalDeltaMeta }, + type: { kind: 'model', meta: EvalDeltaMeta }, }, ], } diff --git a/packages/algod_client/src/models/genesis-allocation.ts b/packages/algod_client/src/models/genesis-allocation.ts index 46feb634..3da033dc 100644 --- a/packages/algod_client/src/models/genesis-allocation.ts +++ b/packages/algod_client/src/models/genesis-allocation.ts @@ -1,5 +1,68 @@ import type { ModelMetadata } from '../core/model-runtime' +const GenesisAllocationStateMeta: ModelMetadata = { + name: 'GenesisAllocationStateMeta', + kind: 'object', + fields: [ + { + name: 'algo', + wireKey: 'algo', + optional: false, + nullable: false, + type: { kind: 'scalar', isBigint: true }, + }, + { + name: 'onl', + wireKey: 'onl', + optional: false, + nullable: false, + type: { kind: 'scalar' }, + }, + { + name: 'sel', + wireKey: 'sel', + optional: true, + nullable: false, + type: { kind: 'scalar' }, + }, + { + name: 'stprf', + wireKey: 'stprf', + optional: true, + nullable: false, + type: { kind: 'scalar' }, + }, + { + name: 'vote', + wireKey: 'vote', + optional: true, + nullable: false, + type: { kind: 'scalar' }, + }, + { + name: 'voteKd', + wireKey: 'voteKD', + optional: true, + nullable: false, + type: { kind: 'scalar', isBigint: true }, + }, + { + name: 'voteFst', + wireKey: 'voteFst', + optional: true, + nullable: false, + type: { kind: 'scalar', isBigint: true }, + }, + { + name: 'voteLst', + wireKey: 'voteLst', + optional: true, + nullable: false, + type: { kind: 'scalar', isBigint: true }, + }, + ], +} + export type GenesisAllocation = { addr: string comment: string @@ -38,7 +101,7 @@ export const GenesisAllocationMeta: ModelMetadata = { wireKey: 'state', optional: false, nullable: false, - type: { kind: 'scalar' }, + type: { kind: 'model', meta: GenesisAllocationStateMeta }, }, ], } diff --git a/packages/algod_client/src/models/genesis.ts b/packages/algod_client/src/models/genesis.ts index ee3d1318..6b8620af 100644 --- a/packages/algod_client/src/models/genesis.ts +++ b/packages/algod_client/src/models/genesis.ts @@ -11,7 +11,7 @@ export type Genesis = { network: string proto: string rwd: string - timestamp: number + timestamp?: number } export const GenesisMeta: ModelMetadata = { @@ -23,7 +23,7 @@ export const GenesisMeta: ModelMetadata = { wireKey: 'alloc', optional: false, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => GenesisAllocationMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: GenesisAllocationMeta } }, }, { name: 'comment', @@ -77,7 +77,7 @@ export const GenesisMeta: ModelMetadata = { { name: 'timestamp', wireKey: 'timestamp', - optional: false, + optional: true, nullable: false, type: { kind: 'scalar' }, }, diff --git a/packages/algod_client/src/models/get-application-boxes.ts b/packages/algod_client/src/models/get-application-boxes.ts index fbb23b78..f812ea95 100644 --- a/packages/algod_client/src/models/get-application-boxes.ts +++ b/packages/algod_client/src/models/get-application-boxes.ts @@ -15,7 +15,7 @@ export const GetApplicationBoxesMeta: ModelMetadata = { wireKey: 'boxes', optional: false, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => BoxDescriptorMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: BoxDescriptorMeta } }, }, ], } diff --git a/packages/algod_client/src/models/get-block.ts b/packages/algod_client/src/models/get-block.ts index cf45466a..72d6ccf7 100644 --- a/packages/algod_client/src/models/get-block.ts +++ b/packages/algod_client/src/models/get-block.ts @@ -5,7 +5,7 @@ import { BlockMeta } from './block' export type GetBlock = { /** Block data including header and transactions. */ block: Block - /** Block certificate (msgpack only). */ + /** Block certificate. */ cert?: Record } @@ -13,7 +13,7 @@ export const GetBlockMeta: ModelMetadata = { name: 'GetBlock', kind: 'object', fields: [ - { name: 'block', wireKey: 'block', optional: false, nullable: false, type: { kind: 'model', meta: () => BlockMeta } }, + { name: 'block', wireKey: 'block', optional: false, nullable: false, type: { kind: 'model', meta: BlockMeta } }, { name: 'cert', wireKey: 'cert', optional: true, nullable: false, type: { kind: 'scalar' } }, ], } diff --git a/packages/algod_client/src/models/get-transaction-group-ledger-state-deltas-for-round.ts b/packages/algod_client/src/models/get-transaction-group-ledger-state-deltas-for-round.ts index e661cf7a..180e601d 100644 --- a/packages/algod_client/src/models/get-transaction-group-ledger-state-deltas-for-round.ts +++ b/packages/algod_client/src/models/get-transaction-group-ledger-state-deltas-for-round.ts @@ -15,7 +15,7 @@ export const GetTransactionGroupLedgerStateDeltasForRoundMeta: ModelMetadata = { wireKey: 'Deltas', optional: false, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => LedgerStateDeltaForTransactionGroupMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: LedgerStateDeltaForTransactionGroupMeta } }, }, ], } diff --git a/packages/algod_client/src/models/index.ts b/packages/algod_client/src/models/index.ts index ee5b69ed..ace6f90d 100644 --- a/packages/algod_client/src/models/index.ts +++ b/packages/algod_client/src/models/index.ts @@ -102,6 +102,8 @@ export type { SimulateInitialStates } from './simulate-initial-states' export { SimulateInitialStatesMeta } from './simulate-initial-states' export type { TransactionProof } from './transaction-proof' export { TransactionProofMeta } from './transaction-proof' +export type { SourceMap } from './source-map' +export { SourceMapMeta } from './source-map' export type { AccountAssetInformation } from './account-asset-information' export { AccountAssetInformationMeta } from './account-asset-information' export type { AccountApplicationInformation } from './account-application-information' @@ -144,19 +146,5 @@ export type { GetBlockTimeStampOffset } from './get-block-time-stamp-offset' export { GetBlockTimeStampOffsetMeta } from './get-block-time-stamp-offset' export type { SuggestedParams, SuggestedParamsMeta } from './suggested-params' -export type { BlockEvalDelta } from './block-eval-delta' -export { BlockEvalDeltaMeta } from './block-eval-delta' -export type { BlockStateDelta } from './block-state-delta' -export { BlockStateDeltaMeta } from './block-state-delta' -export type { BlockAccountStateDelta } from './block-account-state-delta' -export { BlockAccountStateDeltaMeta } from './block-account-state-delta' -export type { BlockAppEvalDelta } from './block-app-eval-delta' -export { BlockAppEvalDeltaMeta } from './block-app-eval-delta' -export type { BlockStateProofTrackingData } from './block_state_proof_tracking_data' -export { BlockStateProofTrackingDataMeta } from './block_state_proof_tracking_data' -export type { BlockStateProofTracking } from './block_state_proof_tracking' -export { BlockStateProofTrackingMeta } from './block_state_proof_tracking' export type { Block } from './block' export { BlockMeta } from './block' -export type { SignedTxnInBlock } from './signed-txn-in-block' -export { SignedTxnInBlockMeta } from './signed-txn-in-block' diff --git a/packages/algod_client/src/models/ledger-state-delta-for-transaction-group.ts b/packages/algod_client/src/models/ledger-state-delta-for-transaction-group.ts index a1693cfa..f27b4aa8 100644 --- a/packages/algod_client/src/models/ledger-state-delta-for-transaction-group.ts +++ b/packages/algod_client/src/models/ledger-state-delta-for-transaction-group.ts @@ -19,7 +19,7 @@ export const LedgerStateDeltaForTransactionGroupMeta: ModelMetadata = { wireKey: 'Delta', optional: false, nullable: false, - type: { kind: 'model', meta: () => LedgerStateDeltaMeta }, + type: { kind: 'model', meta: LedgerStateDeltaMeta }, }, { name: 'ids', diff --git a/packages/algod_client/src/models/ledger-state-delta.ts b/packages/algod_client/src/models/ledger-state-delta.ts index e182e624..9bb0e6da 100644 --- a/packages/algod_client/src/models/ledger-state-delta.ts +++ b/packages/algod_client/src/models/ledger-state-delta.ts @@ -1,12 +1,696 @@ import type { ModelMetadata } from '../core/model-runtime' +import type { Block } from './block' +import { BlockMeta } from './block' /** - * Ledger StateDelta object + * Contains type information and a value, representing a value in a TEAL program. */ -export type LedgerStateDelta = Record +export type LedgerTealValue = { + /** + * Type determines the type of the value. + * * 1 represents the type of a byte slice in a TEAL program + * * 2 represents the type of an unsigned integer in a TEAL program + */ + type: number + /** bytes value. */ + bytes?: Uint8Array + /** uint value. */ + uint?: bigint +} + +export const LedgerTealValueMeta: ModelMetadata = { + name: 'LedgerTealValue', + kind: 'object', + fields: [ + { name: 'type', wireKey: 'tt', optional: false, nullable: false, type: { kind: 'scalar' } }, + { name: 'bytes', wireKey: 'tb', optional: true, nullable: false, type: { kind: 'scalar', isBytes: true } }, + { name: 'uint', wireKey: 'ui', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + ], +} + +/** + * Sets maximums on the number of each type that may be stored. + */ +export type LedgerStateSchema = { + /** Number of uints in state. */ + numUints?: bigint + /** Number of byte slices in state. */ + numByteSlices?: bigint +} + +export const LedgerStateSchemaMeta: ModelMetadata = { + name: 'LedgerStateSchema', + kind: 'object', + fields: [ + { name: 'numUints', wireKey: 'nui', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'numByteSlices', wireKey: 'nbs', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, + ], +} + +/** + * Stores the global information associated with an application. + */ +export type LedgerAppParams = { + approvalProgram: Uint8Array + clearStateProgram: Uint8Array + localStateSchema: LedgerStateSchema + globalStateSchema: LedgerStateSchema + extraProgramPages: number + version?: number + sizeSponsor?: string + globalState?: Map +} + +export const LedgerAppParamsMeta: ModelMetadata = { + name: 'LedgerAppParams', + kind: 'object', + fields: [ + { name: 'approvalProgram', wireKey: 'approv', optional: false, nullable: false, type: { kind: 'scalar', isBytes: true } }, + { name: 'clearStateProgram', wireKey: 'clearp', optional: false, nullable: false, type: { kind: 'scalar', isBytes: true } }, + { name: 'localStateSchema', wireKey: 'lsch', optional: false, nullable: false, type: { kind: 'model', meta: LedgerStateSchemaMeta } }, + { name: 'globalStateSchema', wireKey: 'gsch', optional: false, nullable: false, type: { kind: 'model', meta: LedgerStateSchemaMeta } }, + { name: 'extraProgramPages', wireKey: 'epp', optional: false, nullable: false, type: { kind: 'scalar' } }, + { name: 'version', wireKey: 'v', optional: true, nullable: false, type: { kind: 'scalar' } }, + { name: 'sizeSponsor', wireKey: 'ss', optional: true, nullable: false, type: { kind: 'scalar', isAddress: true } }, + { + name: 'globalState', + wireKey: 'gs', + optional: true, + nullable: false, + type: { kind: 'map', keyType: 'bytes', value: { kind: 'model', meta: LedgerTealValueMeta } }, + }, + ], +} + +/** + * Stores the LocalState associated with an application. + */ +export type LedgerAppLocalState = { + schema: LedgerStateSchema + keyValue?: Map +} + +export const LedgerAppLocalStateMeta: ModelMetadata = { + name: 'LedgerAppLocalState', + kind: 'object', + fields: [ + { name: 'schema', wireKey: 'hsch', optional: false, nullable: false, type: { kind: 'model', meta: LedgerStateSchemaMeta } }, + { + name: 'keyValue', + wireKey: 'tkv', + optional: true, + nullable: false, + type: { kind: 'map', keyType: 'bytes', value: { kind: 'model', meta: LedgerTealValueMeta } }, + }, + ], +} + +/** + * Tracks a changed AppLocalState, and whether it was deleted. + */ +export type LedgerAppLocalStateDelta = { + deleted: boolean + localState?: LedgerAppLocalState +} + +export const LedgerAppLocalStateDeltaMeta: ModelMetadata = { + name: 'LedgerAppLocalStateDelta', + kind: 'object', + fields: [ + { name: 'deleted', wireKey: 'Deleted', optional: false, nullable: false, type: { kind: 'scalar' } }, + { name: 'localState', wireKey: 'LocalState', optional: true, nullable: false, type: { kind: 'model', meta: LedgerAppLocalStateMeta } }, + ], +} + +/** + * Tracks a changed AppParams, and whether it was deleted. + */ +export type LedgerAppParamsDelta = { + deleted: boolean + params?: LedgerAppParams +} + +export const LedgerAppParamsDeltaMeta: ModelMetadata = { + name: 'LedgerAppParamsDelta', + kind: 'object', + fields: [ + { name: 'deleted', wireKey: 'Deleted', optional: false, nullable: false, type: { kind: 'scalar' } }, + { name: 'params', wireKey: 'Params', optional: true, nullable: false, type: { kind: 'model', meta: LedgerAppParamsMeta } }, + ], +} + +/** + * Represents AppParams and AppLocalState in deltas. + */ +export type LedgerAppResourceRecord = { + appId: bigint + address: string + params: LedgerAppParamsDelta + state: LedgerAppLocalStateDelta +} + +export const LedgerAppResourceRecordMeta: ModelMetadata = { + name: 'LedgerAppResourceRecord', + kind: 'object', + fields: [ + { name: 'appId', wireKey: 'Aidx', optional: false, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'address', wireKey: 'Addr', optional: false, nullable: false, type: { kind: 'scalar', isAddress: true } }, + { name: 'params', wireKey: 'Params', optional: false, nullable: false, type: { kind: 'model', meta: LedgerAppParamsDeltaMeta } }, + { name: 'state', wireKey: 'State', optional: false, nullable: false, type: { kind: 'model', meta: LedgerAppLocalStateDeltaMeta } }, + ], +} + +/** + * Describes an asset held by an account. + */ +export type LedgerAssetHolding = { + amount: bigint + frozen: boolean +} + +export const LedgerAssetHoldingMeta: ModelMetadata = { + name: 'LedgerAssetHolding', + kind: 'object', + fields: [ + { name: 'amount', wireKey: 'a', optional: false, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'frozen', wireKey: 'f', optional: false, nullable: false, type: { kind: 'scalar' } }, + ], +} + +/** + * Records a changed AssetHolding, and whether it was deleted. + */ +export type LedgerAssetHoldingDelta = { + deleted: boolean + holding?: LedgerAssetHolding +} + +export const LedgerAssetHoldingDeltaMeta: ModelMetadata = { + name: 'LedgerAssetHoldingDelta', + kind: 'object', + fields: [ + { name: 'deleted', wireKey: 'Deleted', optional: false, nullable: false, type: { kind: 'scalar' } }, + { name: 'holding', wireKey: 'Holding', optional: true, nullable: false, type: { kind: 'model', meta: LedgerAssetHoldingMeta } }, + ], +} + +/** + * Describes the parameters of an asset. + */ +export type LedgerAssetParams = { + /** + * Specifies the total number of units of this asset created. + */ + total: bigint + /** + * Specifies the number of digits to display after the decimal place when displaying this asset. + * A value of 0 represents an asset that is not divisible, a value of 1 represents an asset divisible into tenths, and so on. + * This value must be between 0 and 19 (inclusive). + */ + decimals: number + /** + * Specifies whether slots for this asset in user accounts are frozen by default or not. + */ + defaultFrozen: boolean + /** + * Specifies a hint for the name of a unit of this asset. + */ + unitName?: string + /** + * Specifies a hint for the name of the asset. + */ + assetName?: string + /** + * Specifies a URL where more information about the asset can be retrieved. + */ + url?: string + /** + * Specifies a commitment to some unspecified asset metadata. The format of this + * metadata is up to the application. + */ + metadataHash?: Uint8Array + /** + * Manager specifies an account that is allowed to change the non-zero addresses in this AssetParams. + */ + manager?: string + /** + * Specifies an account whose holdings of this asset should be reported as "not minted". + */ + reserve?: string + /** + * Specifies an account that is allowed to change the frozen state of holdings of this asset. + */ + freeze?: string + /** + * Specifies an account that is allowed to take units of this asset from any account. + */ + clawback?: string +} + +export const LedgerAssetParamsMeta: ModelMetadata = { + name: 'LedgerAssetParams', + kind: 'object', + fields: [ + { name: 'total', wireKey: 't', optional: false, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'decimals', wireKey: 'dc', optional: false, nullable: false, type: { kind: 'scalar' } }, + { name: 'defaultFrozen', wireKey: 'df', optional: false, nullable: false, type: { kind: 'scalar' } }, + { name: 'unitName', wireKey: 'un', optional: true, nullable: false, type: { kind: 'scalar' } }, + { name: 'assetName', wireKey: 'an', optional: true, nullable: false, type: { kind: 'scalar' } }, + { name: 'url', wireKey: 'au', optional: true, nullable: false, type: { kind: 'scalar' } }, + { name: 'metadataHash', wireKey: 'am', optional: true, nullable: false, type: { kind: 'scalar', isBytes: true } }, + { name: 'manager', wireKey: 'm', optional: true, nullable: false, type: { kind: 'scalar', isAddress: true } }, + { name: 'reserve', wireKey: 'r', optional: true, nullable: false, type: { kind: 'scalar', isAddress: true } }, + { name: 'freeze', wireKey: 'f', optional: true, nullable: false, type: { kind: 'scalar', isAddress: true } }, + { name: 'clawback', wireKey: 'c', optional: true, nullable: false, type: { kind: 'scalar', isAddress: true } }, + ], +} + +/** + * Tracks a changed asset params, and whether it was deleted. + */ +export type LedgerAssetParamsDelta = { + deleted: boolean + params?: LedgerAssetParams +} + +export const LedgerAssetParamsDeltaMeta: ModelMetadata = { + name: 'LedgerAssetParamsDelta', + kind: 'object', + fields: [ + { name: 'deleted', wireKey: 'Deleted', optional: false, nullable: false, type: { kind: 'scalar' } }, + { name: 'params', wireKey: 'Params', optional: true, nullable: false, type: { kind: 'model', meta: LedgerAssetParamsMeta } }, + ], +} + +/** + * Represents asset params and asset holding in deltas. + */ +export type LedgerAssetResourceRecord = { + assetId: bigint + address: string + params: LedgerAssetParamsDelta + holding: LedgerAssetHoldingDelta +} + +export const LedgerAssetResourceRecordMeta: ModelMetadata = { + name: 'LedgerAssetResourceRecord', + kind: 'object', + fields: [ + { name: 'assetId', wireKey: 'Aidx', optional: false, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'address', wireKey: 'Addr', optional: false, nullable: false, type: { kind: 'scalar', isAddress: true } }, + { name: 'params', wireKey: 'Params', optional: false, nullable: false, type: { kind: 'model', meta: LedgerAssetParamsDeltaMeta } }, + { name: 'holding', wireKey: 'Holding', optional: false, nullable: false, type: { kind: 'model', meta: LedgerAssetHoldingDeltaMeta } }, + ], +} + +/** + * Holds participation information. + */ +export type LedgerVotingData = { + voteId: Uint8Array + selectionId: Uint8Array + stateProofId: Uint8Array + voteFirstValid: bigint + voteLastValid: bigint + voteKeyDilution: bigint +} + +export const LedgerVotingDataMeta: ModelMetadata = { + name: 'LedgerVotingData', + kind: 'object', + fields: [ + { name: 'voteId', wireKey: 'VoteID', optional: false, nullable: false, type: { kind: 'scalar', isBytes: true } }, + { name: 'selectionId', wireKey: 'SelectionID', optional: false, nullable: false, type: { kind: 'scalar', isBytes: true } }, + { name: 'stateProofId', wireKey: 'StateProofID', optional: false, nullable: false, type: { kind: 'scalar', isBytes: true } }, + { name: 'voteFirstValid', wireKey: 'VoteFirstValid', optional: false, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'voteLastValid', wireKey: 'VoteLastValid', optional: false, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'voteKeyDilution', wireKey: 'VoteKeyDilution', optional: false, nullable: false, type: { kind: 'scalar', isBigint: true } }, + ], +} + +/** + * Contains base account info like balance, status and total number of resources. + */ +export type LedgerAccountBaseData = { + /** + * Account status. Values are: + * * 0: Offline + * * 1: Online + * * 2: NotParticipating + */ + status: number + microAlgos: bigint + rewardsBase: bigint + rewardedMicroAlgos: bigint + authAddress: string + incentiveEligible: boolean + /** + * Totals across created globals, and opted in locals. + */ + totalAppSchema: LedgerStateSchema + /** + * Total number of extra pages across all created apps. + */ + totalExtraAppPages: number + /** + * Total number of apps this account has created. + */ + totalAppParams: number + /** + * Total number of apps this account is opted into. + */ + totalAppLocalStates: number + /** + * Total number of assets created by this account. + */ + totalAssetParams: number + /** + * Total of asset creations and optins (i.e. number of holdings). + */ + totalAssets: number + /** + * Total number of boxes associated to this account. + */ + totalBoxes: bigint + /** + * Total bytes for this account's boxes. keys and values count. + */ + totalBoxBytes: bigint + /** + * The last round that this account proposed the winning block. + */ + lastProposed: bigint + /** + * The last round that this account sent a heartbeat to show it was online. + */ + lastHeartbeat: bigint +} + +export const LedgerAccountBaseDataMeta: ModelMetadata = { + name: 'LedgerAccountBaseData', + kind: 'object', + fields: [ + { name: 'status', wireKey: 'Status', optional: false, nullable: false, type: { kind: 'scalar' } }, + { name: 'microAlgos', wireKey: 'MicroAlgos', optional: false, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'rewardsBase', wireKey: 'RewardsBase', optional: false, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { + name: 'rewardedMicroAlgos', + wireKey: 'RewardedMicroAlgos', + optional: false, + nullable: false, + type: { kind: 'scalar', isBigint: true }, + }, + { name: 'authAddress', wireKey: 'AuthAddr', optional: false, nullable: false, type: { kind: 'scalar', isAddress: true } }, + { name: 'incentiveEligible', wireKey: 'IncentiveEligible', optional: false, nullable: false, type: { kind: 'scalar' } }, + { + name: 'totalAppSchema', + wireKey: 'TotalAppSchema', + optional: false, + nullable: false, + type: { kind: 'model', meta: LedgerStateSchemaMeta }, + }, + { name: 'totalExtraAppPages', wireKey: 'TotalExtraAppPages', optional: false, nullable: false, type: { kind: 'scalar' } }, + { name: 'totalAppParams', wireKey: 'TotalAppParams', optional: false, nullable: false, type: { kind: 'scalar' } }, + { name: 'totalAppLocalStates', wireKey: 'TotalAppLocalStates', optional: false, nullable: false, type: { kind: 'scalar' } }, + { name: 'totalAssetParams', wireKey: 'TotalAssetParams', optional: false, nullable: false, type: { kind: 'scalar' } }, + { name: 'totalAssets', wireKey: 'TotalAssets', optional: false, nullable: false, type: { kind: 'scalar' } }, + { name: 'totalBoxes', wireKey: 'TotalBoxes', optional: false, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'totalBoxBytes', wireKey: 'TotalBoxBytes', optional: false, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'lastProposed', wireKey: 'LastProposed', optional: false, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'lastHeartbeat', wireKey: 'LastHeartbeat', optional: false, nullable: false, type: { kind: 'scalar', isBigint: true } }, + ], +} + +/** + * Provides per-account data. + */ +export type LedgerAccountData = { + accountBaseData: LedgerAccountBaseData + votingData: LedgerVotingData +} + +export const LedgerAccountDataMeta: ModelMetadata = { + name: 'LedgerAccountData', + kind: 'object', + fields: [ + { + name: 'accountBaseData', + flattened: true, + optional: false, + nullable: false, + type: { kind: 'model', meta: LedgerAccountBaseDataMeta }, + }, + { name: 'votingData', flattened: true, optional: false, nullable: false, type: { kind: 'model', meta: LedgerVotingDataMeta } }, + ], +} + +export type LedgerBalanceRecord = { + address: string + accountData: LedgerAccountData +} + +export const LedgerBalanceRecordMeta: ModelMetadata = { + name: 'LedgerBalanceRecord', + kind: 'object', + fields: [ + { name: 'address', wireKey: 'Addr', optional: false, nullable: false, type: { kind: 'scalar', isAddress: true } }, + { name: 'accountData', flattened: true, optional: false, nullable: false, type: { kind: 'model', meta: LedgerAccountDataMeta } }, + ], +} + +export type LedgerAccountDeltas = { + accounts?: LedgerBalanceRecord[] + appResources?: LedgerAppResourceRecord[] + assetResources?: LedgerAssetResourceRecord[] +} + +export const LedgerAccountDeltasMeta: ModelMetadata = { + name: 'LedgerAccountDeltas', + kind: 'object', + fields: [ + { + name: 'accounts', + wireKey: 'Accts', + optional: true, + nullable: false, + type: { kind: 'array', item: { kind: 'model', meta: LedgerBalanceRecordMeta } }, + }, + { + name: 'appResources', + wireKey: 'AppResources', + optional: true, + nullable: false, + type: { kind: 'array', item: { kind: 'model', meta: LedgerAppResourceRecordMeta } }, + }, + { + name: 'assetResources', + wireKey: 'AssetResources', + optional: true, + nullable: false, + type: { kind: 'array', item: { kind: 'model', meta: LedgerAssetResourceRecordMeta } }, + }, + ], +} + +/** + * Shows how the data associated with a key in the kvstore has changed. + */ +export type LedgerKvValueDelta = { + /** + * Stores the most recent value (undefined means deleted). + */ + data?: Uint8Array + /** + * Stores the previous value (undefined means didn't exist). + */ + oldData?: Uint8Array +} + +export const LedgerKvValueDeltaMeta: ModelMetadata = { + name: 'LedgerKvValueDelta', + kind: 'object', + fields: [ + { name: 'data', wireKey: 'Data', optional: true, nullable: false, type: { kind: 'scalar', isBytes: true } }, + { name: 'oldData', wireKey: 'OldData', optional: true, nullable: false, type: { kind: 'scalar', isBytes: true } }, + ], +} + +/** + * Defines the transactions included in a block, their index and last valid round. + */ +export type LedgerIncludedTransactions = { + lastValid: bigint + /** + * The index of the transaction in the block. + */ + intra: number +} + +export const LedgerIncludedTransactionsMeta: ModelMetadata = { + name: 'LedgerIncludedTransactions', + kind: 'object', + fields: [ + { name: 'lastValid', wireKey: 'LastValid', optional: false, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'intra', wireKey: 'Intra', optional: false, nullable: false, type: { kind: 'scalar' } }, + ], +} + +/** + * Represents a change to a single creatable state. + */ +export type LedgerModifiedCreatable = { + /** + * Type of the creatable. The values are: + * * 0: Asset + * * 1: Application + */ + creatableType: number + /** + * Created if true, deleted if false. + */ + created: boolean + /** + * Creator of the app/asset. + */ + creator: string + /** + * Keeps track of how many times this app/asset appears in accountUpdates.creatableDeltas. + */ + nDeltas: number +} + +export const LedgerModifiedCreatableMeta: ModelMetadata = { + name: 'LedgerModifiedCreatable', + kind: 'object', + fields: [ + { name: 'creatableType', wireKey: 'Ctype', optional: false, nullable: false, type: { kind: 'scalar' } }, + { name: 'created', wireKey: 'Created', optional: false, nullable: false, type: { kind: 'scalar' } }, + { name: 'creator', wireKey: 'Creator', optional: false, nullable: false, type: { kind: 'scalar', isAddress: true } }, + { name: 'ndeltas', wireKey: 'Ndeltas', optional: false, nullable: false, type: { kind: 'scalar' } }, + ], +} + +/** + * Represents a total of algos of a certain class of accounts (split up by their Status value). + */ +export type LedgerAlgoCount = { + /** + * Sum of algos of all accounts in this scope. + */ + money: bigint + /** + * Total number of whole reward units in accounts. + */ + rewardUnits: bigint +} + +export const LedgerAlgoCountMeta: ModelMetadata = { + name: 'LedgerAlgoCount', + kind: 'object', + fields: [ + { name: 'money', wireKey: 'mon', optional: false, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'rewardUnits', wireKey: 'rwd', optional: false, nullable: false, type: { kind: 'scalar', isBigint: true } }, + ], +} + +/** + * Represents the totals of algos in the system grouped by different account status values. + */ +export type LedgerAccountTotals = { + online: LedgerAlgoCount + offline: LedgerAlgoCount + notParticipating: LedgerAlgoCount + /** + * Total number of algos received per reward unit since genesis. + */ + rewardsLevel: bigint +} + +export const LedgerAccountTotalsMeta: ModelMetadata = { + name: 'LedgerAccountTotals', + kind: 'object', + fields: [ + { name: 'online', wireKey: 'online', optional: false, nullable: false, type: { kind: 'model', meta: LedgerAlgoCountMeta } }, + { name: 'offline', wireKey: 'offline', optional: false, nullable: false, type: { kind: 'model', meta: LedgerAlgoCountMeta } }, + { name: 'notParticipating', wireKey: 'notpart', optional: false, nullable: false, type: { kind: 'model', meta: LedgerAlgoCountMeta } }, + { name: 'rewardsLevel', wireKey: 'rwdlvl', optional: false, nullable: false, type: { kind: 'scalar', isBigint: true } }, + ], +} + +/** + * Describes the delta between a given round to the previous round. + */ +export type LedgerStateDelta = { + /** + * Modified new accounts. + */ + accounts: LedgerAccountDeltas + /** + * Block header. + */ + block: Block + /** + * Represents modification on StateProofNextRound field in the block header. If the block contains + * a valid state proof transaction, this field will contain the next round for state proof. + * otherwise it will be set to 0. + */ + stateProofNext: bigint + /** + * Previous block timestamp + */ + prevTimestamp: bigint + /** + * The account totals reflecting the changes in this StateDelta object. + */ + totals: LedgerAccountTotals + /** + * Modified kv pairs. + */ + kvMods?: Map + /** + * New Txids for the txtail and TxnCounter, mapped to txn.LastValid. + */ + txIds?: Map + /** + * New txleases for the txtail mapped to expiration. + */ + txLeases?: Record + /** + * New creatables creator lookup table. + */ + creatables?: Map +} export const LedgerStateDeltaMeta: ModelMetadata = { name: 'LedgerStateDelta', kind: 'object', - fields: [], + fields: [ + { name: 'accounts', wireKey: 'Accts', optional: false, nullable: false, type: { kind: 'model', meta: LedgerAccountDeltasMeta } }, + { name: 'block', wireKey: 'Hdr', optional: false, nullable: false, type: { kind: 'model', meta: BlockMeta } }, + { name: 'stateProofNext', wireKey: 'StateProofNext', optional: false, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'prevTimestamp', wireKey: 'PrevTimestamp', optional: false, nullable: false, type: { kind: 'scalar', isBigint: true } }, + { name: 'totals', wireKey: 'Totals', optional: false, nullable: false, type: { kind: 'model', meta: LedgerAccountTotalsMeta } }, + { + name: 'kvMods', + wireKey: 'KvMods', + optional: true, + nullable: false, + type: { kind: 'map', keyType: 'bytes', value: { kind: 'model', meta: LedgerKvValueDeltaMeta } }, + }, + { + name: 'txIds', + wireKey: 'Txids', + optional: true, + nullable: false, + type: { kind: 'map', keyType: 'bytes', value: { kind: 'model', meta: LedgerIncludedTransactionsMeta } }, + }, + { name: 'txLeases', wireKey: 'Txleases', optional: true, nullable: false, type: { kind: 'scalar' } }, + { + name: 'creatables', + wireKey: 'Creatables', + optional: true, + nullable: false, + type: { kind: 'map', keyType: 'number', value: { kind: 'model', meta: LedgerModifiedCreatableMeta } }, + }, + ], } diff --git a/packages/algod_client/src/models/pending-transaction-response.ts b/packages/algod_client/src/models/pending-transaction-response.ts index d968f953..7605f700 100644 --- a/packages/algod_client/src/models/pending-transaction-response.ts +++ b/packages/algod_client/src/models/pending-transaction-response.ts @@ -148,14 +148,14 @@ export const PendingTransactionResponseMeta: ModelMetadata = { wireKey: 'local-state-delta', optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => AccountStateDeltaMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: AccountStateDeltaMeta } }, }, { name: 'globalStateDelta', wireKey: 'global-state-delta', optional: true, nullable: false, - type: { kind: 'model', meta: () => StateDeltaMeta }, + type: { kind: 'model', meta: StateDeltaMeta }, }, { name: 'logs', diff --git a/packages/algod_client/src/models/scratch-change.ts b/packages/algod_client/src/models/scratch-change.ts index b0c906f3..48b979f9 100644 --- a/packages/algod_client/src/models/scratch-change.ts +++ b/packages/algod_client/src/models/scratch-change.ts @@ -29,7 +29,7 @@ export const ScratchChangeMeta: ModelMetadata = { wireKey: 'new-value', optional: false, nullable: false, - type: { kind: 'model', meta: () => AvmValueMeta }, + type: { kind: 'model', meta: AvmValueMeta }, }, ], } diff --git a/packages/algod_client/src/models/signed-txn-in-block.ts b/packages/algod_client/src/models/signed-txn-in-block.ts deleted file mode 100644 index 2ac4b30e..00000000 --- a/packages/algod_client/src/models/signed-txn-in-block.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Algod REST API. - * - * API endpoint for algod operations. - * - * The version of the OpenAPI document: 0.0.1 - * Contact: contact@algorand.com - * Generated by: Rust OpenAPI Generator - */ - -import type { ModelMetadata } from '../core/model-runtime' -import type { SignedTransaction } from '@algorandfoundation/algokit-transact' -import type { BlockAppEvalDelta } from './block-app-eval-delta' -import { getModelMeta, registerModelMeta } from '../core/model-runtime' - -/** - * SignedTxnInBlock is a SignedTransaction with additional ApplyData and block-specific metadata. - */ -export interface SignedTxnInBlock { - signedTransaction: SignedTransaction - logicSignature?: Record - closingAmount?: bigint - assetClosingAmount?: bigint - senderRewards?: bigint - receiverRewards?: bigint - closeRewards?: bigint - evalDelta?: BlockAppEvalDelta - configAsset?: bigint - applicationId?: bigint - hasGenesisId?: boolean - hasGenesisHash?: boolean -} - -export const SignedTxnInBlockMeta: ModelMetadata = { - name: 'SignedTxnInBlock', - kind: 'object', - fields: [ - { - name: 'signedTransaction', - // flatten signed transaction fields into parent - flattened: true, - optional: false, - nullable: false, - type: { kind: 'codec', codecKey: 'SignedTransaction' }, - }, - { name: 'logicSignature', wireKey: 'lsig', optional: true, nullable: false, type: { kind: 'scalar' } }, - { name: 'closingAmount', wireKey: 'ca', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, - { name: 'assetClosingAmount', wireKey: 'aca', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, - { name: 'senderRewards', wireKey: 'rs', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, - { name: 'receiverRewards', wireKey: 'rr', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, - { name: 'closeRewards', wireKey: 'rc', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, - { - name: 'evalDelta', - wireKey: 'dt', - optional: true, - nullable: false, - type: { kind: 'model', meta: () => getModelMeta('BlockAppEvalDelta') }, - }, - { name: 'configAsset', wireKey: 'caid', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, - { name: 'applicationId', wireKey: 'apid', optional: true, nullable: false, type: { kind: 'scalar', isBigint: true } }, - { name: 'hasGenesisId', wireKey: 'hgi', optional: true, nullable: false, type: { kind: 'scalar' } }, - { name: 'hasGenesisHash', wireKey: 'hgh', optional: true, nullable: false, type: { kind: 'scalar' } }, - ], -} - -registerModelMeta('SignedTxnInBlock', SignedTxnInBlockMeta) diff --git a/packages/algod_client/src/models/simulate-initial-states.ts b/packages/algod_client/src/models/simulate-initial-states.ts index 21c948cd..d78284b0 100644 --- a/packages/algod_client/src/models/simulate-initial-states.ts +++ b/packages/algod_client/src/models/simulate-initial-states.ts @@ -21,7 +21,7 @@ export const SimulateInitialStatesMeta: ModelMetadata = { wireKey: 'app-initial-states', optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => ApplicationInitialStatesMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: ApplicationInitialStatesMeta } }, }, ], } diff --git a/packages/algod_client/src/models/simulate-request.ts b/packages/algod_client/src/models/simulate-request.ts index 01043297..577362eb 100644 --- a/packages/algod_client/src/models/simulate-request.ts +++ b/packages/algod_client/src/models/simulate-request.ts @@ -54,7 +54,7 @@ export const SimulateRequestMeta: ModelMetadata = { wireKey: 'txn-groups', optional: false, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => SimulateRequestTransactionGroupMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: SimulateRequestTransactionGroupMeta } }, }, { name: 'round', @@ -96,7 +96,7 @@ export const SimulateRequestMeta: ModelMetadata = { wireKey: 'exec-trace-config', optional: true, nullable: false, - type: { kind: 'model', meta: () => SimulateTraceConfigMeta }, + type: { kind: 'model', meta: SimulateTraceConfigMeta }, }, { name: 'fixSigners', diff --git a/packages/algod_client/src/models/simulate-transaction-group-result.ts b/packages/algod_client/src/models/simulate-transaction-group-result.ts index b091dd10..72fcb214 100644 --- a/packages/algod_client/src/models/simulate-transaction-group-result.ts +++ b/packages/algod_client/src/models/simulate-transaction-group-result.ts @@ -44,7 +44,7 @@ export const SimulateTransactionGroupResultMeta: ModelMetadata = { wireKey: 'txn-results', optional: false, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => SimulateTransactionResultMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: SimulateTransactionResultMeta } }, }, { name: 'failureMessage', @@ -79,7 +79,7 @@ export const SimulateTransactionGroupResultMeta: ModelMetadata = { wireKey: 'unnamed-resources-accessed', optional: true, nullable: false, - type: { kind: 'model', meta: () => SimulateUnnamedResourcesAccessedMeta }, + type: { kind: 'model', meta: SimulateUnnamedResourcesAccessedMeta }, }, ], } diff --git a/packages/algod_client/src/models/simulate-transaction-result.ts b/packages/algod_client/src/models/simulate-transaction-result.ts index 7d9e550e..d9015e32 100644 --- a/packages/algod_client/src/models/simulate-transaction-result.ts +++ b/packages/algod_client/src/models/simulate-transaction-result.ts @@ -39,7 +39,7 @@ export const SimulateTransactionResultMeta: ModelMetadata = { wireKey: 'txn-result', optional: false, nullable: false, - type: { kind: 'model', meta: () => PendingTransactionResponseMeta }, + type: { kind: 'model', meta: PendingTransactionResponseMeta }, }, { name: 'appBudgetConsumed', @@ -60,14 +60,14 @@ export const SimulateTransactionResultMeta: ModelMetadata = { wireKey: 'exec-trace', optional: true, nullable: false, - type: { kind: 'model', meta: () => SimulationTransactionExecTraceMeta }, + type: { kind: 'model', meta: SimulationTransactionExecTraceMeta }, }, { name: 'unnamedResourcesAccessed', wireKey: 'unnamed-resources-accessed', optional: true, nullable: false, - type: { kind: 'model', meta: () => SimulateUnnamedResourcesAccessedMeta }, + type: { kind: 'model', meta: SimulateUnnamedResourcesAccessedMeta }, }, { name: 'fixedSigner', diff --git a/packages/algod_client/src/models/simulate-transaction.ts b/packages/algod_client/src/models/simulate-transaction.ts index b8845dad..a0419f61 100644 --- a/packages/algod_client/src/models/simulate-transaction.ts +++ b/packages/algod_client/src/models/simulate-transaction.ts @@ -51,28 +51,28 @@ export const SimulateTransactionMeta: ModelMetadata = { wireKey: 'txn-groups', optional: false, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => SimulateTransactionGroupResultMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: SimulateTransactionGroupResultMeta } }, }, { name: 'evalOverrides', wireKey: 'eval-overrides', optional: true, nullable: false, - type: { kind: 'model', meta: () => SimulationEvalOverridesMeta }, + type: { kind: 'model', meta: SimulationEvalOverridesMeta }, }, { name: 'execTraceConfig', wireKey: 'exec-trace-config', optional: true, nullable: false, - type: { kind: 'model', meta: () => SimulateTraceConfigMeta }, + type: { kind: 'model', meta: SimulateTraceConfigMeta }, }, { name: 'initialStates', wireKey: 'initial-states', optional: true, nullable: false, - type: { kind: 'model', meta: () => SimulateInitialStatesMeta }, + type: { kind: 'model', meta: SimulateInitialStatesMeta }, }, ], } diff --git a/packages/algod_client/src/models/simulate-unnamed-resources-accessed.ts b/packages/algod_client/src/models/simulate-unnamed-resources-accessed.ts index cd515a0c..fd4e31ec 100644 --- a/packages/algod_client/src/models/simulate-unnamed-resources-accessed.ts +++ b/packages/algod_client/src/models/simulate-unnamed-resources-accessed.ts @@ -76,7 +76,7 @@ export const SimulateUnnamedResourcesAccessedMeta: ModelMetadata = { wireKey: 'boxes', optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => BoxReferenceMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: BoxReferenceMeta } }, }, { name: 'extraBoxRefs', @@ -90,14 +90,14 @@ export const SimulateUnnamedResourcesAccessedMeta: ModelMetadata = { wireKey: 'asset-holdings', optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => AssetHoldingReferenceMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: AssetHoldingReferenceMeta } }, }, { name: 'appLocals', wireKey: 'app-locals', optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => ApplicationLocalReferenceMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: ApplicationLocalReferenceMeta } }, }, ], } diff --git a/packages/algod_client/src/models/simulation-opcode-trace-unit.ts b/packages/algod_client/src/models/simulation-opcode-trace-unit.ts index 4900df9b..7962f271 100644 --- a/packages/algod_client/src/models/simulation-opcode-trace-unit.ts +++ b/packages/algod_client/src/models/simulation-opcode-trace-unit.ts @@ -57,14 +57,14 @@ export const SimulationOpcodeTraceUnitMeta: ModelMetadata = { wireKey: 'scratch-changes', optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => ScratchChangeMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: ScratchChangeMeta } }, }, { name: 'stateChanges', wireKey: 'state-changes', optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => ApplicationStateOperationMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: ApplicationStateOperationMeta } }, }, { name: 'spawnedInners', @@ -85,7 +85,7 @@ export const SimulationOpcodeTraceUnitMeta: ModelMetadata = { wireKey: 'stack-additions', optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => AvmValueMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: AvmValueMeta } }, }, ], } diff --git a/packages/algod_client/src/models/simulation-transaction-exec-trace.ts b/packages/algod_client/src/models/simulation-transaction-exec-trace.ts index b499f9b8..06cdbb97 100644 --- a/packages/algod_client/src/models/simulation-transaction-exec-trace.ts +++ b/packages/algod_client/src/models/simulation-transaction-exec-trace.ts @@ -61,7 +61,7 @@ export const SimulationTransactionExecTraceMeta: ModelMetadata = { wireKey: 'approval-program-trace', optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => SimulationOpcodeTraceUnitMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: SimulationOpcodeTraceUnitMeta } }, }, { name: 'approvalProgramHash', @@ -75,7 +75,7 @@ export const SimulationTransactionExecTraceMeta: ModelMetadata = { wireKey: 'clear-state-program-trace', optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => SimulationOpcodeTraceUnitMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: SimulationOpcodeTraceUnitMeta } }, }, { name: 'clearStateProgramHash', @@ -103,7 +103,7 @@ export const SimulationTransactionExecTraceMeta: ModelMetadata = { wireKey: 'logic-sig-trace', optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => SimulationOpcodeTraceUnitMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: SimulationOpcodeTraceUnitMeta } }, }, { name: 'logicSigHash', diff --git a/packages/algod_client/src/models/source-map.ts b/packages/algod_client/src/models/source-map.ts new file mode 100644 index 00000000..63e23d2f --- /dev/null +++ b/packages/algod_client/src/models/source-map.ts @@ -0,0 +1,58 @@ +import type { ModelMetadata } from '../core/model-runtime' + +/** + * Source map for the program + */ +export type SourceMap = { + version: number + + /** + * A list of original sources used by the "mappings" entry. + */ + sources: string[] + + /** + * A list of symbol names used by the "mappings" entry. + */ + names: string[] + + /** + * A string with the encoded mapping data. + */ + mappings: string +} + +export const SourceMapMeta: ModelMetadata = { + name: 'SourceMap', + kind: 'object', + fields: [ + { + name: 'version', + wireKey: 'version', + optional: false, + nullable: false, + type: { kind: 'scalar' }, + }, + { + name: 'sources', + wireKey: 'sources', + optional: false, + nullable: false, + type: { kind: 'array', item: { kind: 'scalar' } }, + }, + { + name: 'names', + wireKey: 'names', + optional: false, + nullable: false, + type: { kind: 'array', item: { kind: 'scalar' } }, + }, + { + name: 'mappings', + wireKey: 'mappings', + optional: false, + nullable: false, + type: { kind: 'scalar' }, + }, + ], +} diff --git a/packages/algod_client/src/models/state-delta.ts b/packages/algod_client/src/models/state-delta.ts index ef811cfe..4563bbf8 100644 --- a/packages/algod_client/src/models/state-delta.ts +++ b/packages/algod_client/src/models/state-delta.ts @@ -10,5 +10,5 @@ export type StateDelta = EvalDeltaKeyValue[] export const StateDeltaMeta: ModelMetadata = { name: 'StateDelta', kind: 'array', - arrayItems: { kind: 'model', meta: () => EvalDeltaKeyValueMeta }, + arrayItems: { kind: 'model', meta: EvalDeltaKeyValueMeta }, } diff --git a/packages/algod_client/src/models/state-proof.ts b/packages/algod_client/src/models/state-proof.ts index 96dd3bcd..44737b16 100644 --- a/packages/algod_client/src/models/state-proof.ts +++ b/packages/algod_client/src/models/state-proof.ts @@ -23,7 +23,7 @@ export const StateProofMeta: ModelMetadata = { wireKey: 'Message', optional: false, nullable: false, - type: { kind: 'model', meta: () => StateProofMessageMeta }, + type: { kind: 'model', meta: StateProofMessageMeta }, }, { name: 'stateProof', diff --git a/packages/algod_client/src/models/teal-compile.ts b/packages/algod_client/src/models/teal-compile.ts index 97aacb1f..fac98c7f 100644 --- a/packages/algod_client/src/models/teal-compile.ts +++ b/packages/algod_client/src/models/teal-compile.ts @@ -1,4 +1,6 @@ import type { ModelMetadata } from '../core/model-runtime' +import type { SourceMap } from './source-map' +import { SourceMapMeta } from './source-map' export type TealCompile = { /** @@ -10,11 +12,7 @@ export type TealCompile = { * base64 encoded program bytes */ result: string - - /** - * JSON of the source map - */ - sourcemap?: Record + sourcemap?: SourceMap } export const TealCompileMeta: ModelMetadata = { @@ -40,7 +38,7 @@ export const TealCompileMeta: ModelMetadata = { wireKey: 'sourcemap', optional: true, nullable: false, - type: { kind: 'scalar' }, + type: { kind: 'model', meta: SourceMapMeta }, }, ], } diff --git a/packages/algod_client/src/models/teal-dryrun.ts b/packages/algod_client/src/models/teal-dryrun.ts index 7a7899da..4686cbb4 100644 --- a/packages/algod_client/src/models/teal-dryrun.ts +++ b/packages/algod_client/src/models/teal-dryrun.ts @@ -21,7 +21,7 @@ export const TealDryrunMeta: ModelMetadata = { wireKey: 'txns', optional: false, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => DryrunTxnResultMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: DryrunTxnResultMeta } }, }, { name: 'error', diff --git a/packages/algod_client/src/models/teal-key-value-store.ts b/packages/algod_client/src/models/teal-key-value-store.ts index d0ad997b..99dd316d 100644 --- a/packages/algod_client/src/models/teal-key-value-store.ts +++ b/packages/algod_client/src/models/teal-key-value-store.ts @@ -10,5 +10,5 @@ export type TealKeyValueStore = TealKeyValue[] export const TealKeyValueStoreMeta: ModelMetadata = { name: 'TealKeyValueStore', kind: 'array', - arrayItems: { kind: 'model', meta: () => TealKeyValueMeta }, + arrayItems: { kind: 'model', meta: TealKeyValueMeta }, } diff --git a/packages/algod_client/src/models/teal-key-value.ts b/packages/algod_client/src/models/teal-key-value.ts index 1905fe41..2a71a2b2 100644 --- a/packages/algod_client/src/models/teal-key-value.ts +++ b/packages/algod_client/src/models/teal-key-value.ts @@ -26,7 +26,7 @@ export const TealKeyValueMeta: ModelMetadata = { wireKey: 'value', optional: false, nullable: false, - type: { kind: 'model', meta: () => TealValueMeta }, + type: { kind: 'model', meta: TealValueMeta }, }, ], } diff --git a/packages/algod_client/src/models/version.ts b/packages/algod_client/src/models/version.ts index a930fa80..a0904971 100644 --- a/packages/algod_client/src/models/version.ts +++ b/packages/algod_client/src/models/version.ts @@ -21,7 +21,7 @@ export const VersionMeta: ModelMetadata = { wireKey: 'build', optional: false, nullable: false, - type: { kind: 'model', meta: () => BuildVersionMeta }, + type: { kind: 'model', meta: BuildVersionMeta }, }, { name: 'genesisHashB64', diff --git a/packages/algod_client/tests/__snapshots__/get_genesis.test.ts.snap b/packages/algod_client/tests/__snapshots__/get_genesis.test.ts.snap new file mode 100644 index 00000000..296b9944 --- /dev/null +++ b/packages/algod_client/tests/__snapshots__/get_genesis.test.ts.snap @@ -0,0 +1,1258 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`GET genesis > Common Tests > Basic request and response validation 1`] = ` +{ + "alloc": [ + { + "addr": "7777777777777777777777777777777777777777777777777774MSJUVU", + "comment": "RewardsPool", + "state": { + "algo": 125000000000000n, + "onl": 2, + }, + }, + { + "addr": "A7NMWS3NT3IUDMLVO26ULGXGIIOUQ3ND2TXSER6EBGRZNOBOUIQXHIBGDE", + "comment": "FeeSink", + "state": { + "algo": 100000n, + "onl": 2, + }, + }, + { + "addr": "LHHQJ6UMXRGEPXBVFKT7SY26BQOIK64VVPCLVRL3RNQLX5ZMBYG6ZHZMBE", + "comment": "Wallet1", + "state": { + "algo": 320000000000000n, + "onl": 1, + "sel": "h7Ml/mY/PDCPSj33u72quxaMX99n+/VE+wD94/hMdzY=", + "vote": "R9kxsHbji4DlxPOAyLehy8vaiWyLjWdLGWBLnQ5jjY8=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "CQW2QBBUW5AGFDXMURQBRJN2AM3OHHQWXXI4PEJXRCVTEJ3E5VBTNRTEAE", + "comment": "Wallet10", + "state": { + "algo": 320000000000000n, + "onl": 1, + "sel": "p2tiuQ2kqJGG049hHOKNIjid4/u1MqlvgXfbxK4tuEY=", + "vote": "E73cc+KB/LGdDHO1o84440WKCmqvbM4EgROMRyHfjDc=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "HXPCXKQZF4LDL3CE5ERWC5V2BQZTKXUUT3JE6AXXNKLF3OJL4XUAW5WYXM", + "comment": "Wallet11", + "state": { + "algo": 320000000000000n, + "onl": 1, + "sel": "ex32mzy8E94GkHGy+cmkRP5JNqFBKGfHtgyUGNxTiW8=", + "vote": "BtYvtmeEBY2JovHUfePTjo3OtOMrhKp3QMeOYl3JFYM=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "Y3FSHQ43JWDSJG7LL5FBRTXHEGTPSWEQBO4CO2RO7KS2Z4ZGBUI7LSEDHQ", + "comment": "Wallet12", + "state": { + "algo": 320000000000000n, + "onl": 1, + "sel": "+AtsgunCR8dzO9UGUJ6sFtAaX/E+ssK6JNmvAljQG2E=", + "vote": "Rx21vGt6pnixU2g6NS/TknVtAGbf8hWMJiEtNuV5lb4=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "KXILJUKZJEOS4OCPGENS72JWIZOXGZSK4R235EQPGQ3JLG6R2BBT3ODXEI", + "comment": "Wallet13", + "state": { + "algo": 320000000000000n, + "onl": 1, + "sel": "6s09aJVaGfPdbWy5zUSyBJEX/EGVvsn2moUOvakQdBQ=", + "vote": "1oTW6ZpIHhQP6xeNCSqHOZZJYrKiP5D52OHXGzbVz4k=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "R4DCCBODM4L7C6CKVOV5NYDPEYS2G5L7KC7LUYPLUCKBCOIZMYJPFUDTKE", + "comment": "Wallet14", + "state": { + "algo": 320000000000000n, + "onl": 1, + "sel": "XsqeQcLz5nPP316ntIp0X9OfJi5ZSfUNrlRSitWXJRg=", + "vote": "r+e0lAD9FnNqOKoWdYdFko13pm9fk/zCJkxVVCqzjaU=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "VKM6KSCTDHEM6KGEAMSYCNEGIPFJMHDSEMIRAQLK76CJDIRMMDHKAIRMFQ", + "comment": "Wallet15", + "state": { + "algo": 320000000000000n, + "onl": 1, + "sel": "64Xkj7z3rHZT7syihd0OmgNExHfnOLdLojDJZgtB1d8=", + "vote": "um2RrGFmZ5Coned2WSbo/htYMKjW7XFE5h25M2IFsDs=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "YTOO52XR6UWNM6OUUDOGWVTNJYBWR5NJ3VCJTZUSR42JERFJFAG3NFD47U", + "comment": "Wallet16", + "state": { + "algo": 320000000000000n, + "onl": 1, + "sel": "9f9aNsmJxXgMZke5sRYFbfnH5fIFclSosqSl1mK4Vd8=", + "vote": "h8ybeZLDhNG/53oJGAzZ2TFAXDXaslXMzNBOR3Pd+i4=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "EQ5XMOLC2JY5RNFXM725LRVKSTOHWBOQE344ZC6O2K4NW2S3G4XQIJNKAA", + "comment": "Wallet17", + "state": { + "algo": 320000000000000n, + "onl": 1, + "sel": "R2LzBwBOEoMEcN6j2Pq9F1RKgrLrqnTyW/iT/tlIRZg=", + "vote": "FnP52cIaWwqpJ6dE3KuM3WSGaz+TNlb/iM7EO0j7EZQ=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "3PUAOGK2PIEH6K5JTQ55SCV3E52KSLDPUAWDURMUNST6IIFCH347X5SNAI", + "comment": "Wallet18", + "state": { + "algo": 320000000000000n, + "onl": 1, + "sel": "HfTcCIGCoAgUMCHalBv2dSC2L7XCPqPmCmWmxO26Vqo=", + "vote": "knBY5MY9DkIguN41/ZoKvSGAg92/fhw64BLHUw0o1BU=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "DUQR2JOFHCTNRRI546OZDYLCVBIVRYOSWKNR7A43YKVH437QS3XGJWTQ6I", + "comment": "Wallet19", + "state": { + "algo": 320000000000000n, + "onl": 1, + "sel": "DRSm3BAHOXLJLPHwrkKILG/cvHLXuDQYIceHgNPnQds=", + "vote": "9G4AtYrLO26Jc3BsUfNl+0+3IjeHdOOSM+8ASj9x7Tg=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "NWBZBIROXZQEETCDKX6IZVVBV4EY637KCIX56LE5EHIQERCTSDYGXWG6PU", + "comment": "Wallet2", + "state": { + "algo": 320000000000000n, + "onl": 1, + "sel": "0eG0edle+ejWcS4Q8DNlITgqaKqNvOtCxNQs+4AncGo=", + "vote": "V4YUoGYXrgDjCluBBbBx2Kq9kkbCZudsuSwmSlCUnK0=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "U2573KTKRCC7I47FJUTW6DBEUN2VZQ63ZVYISQMIUEJTWDNOGSUTL67HBE", + "comment": "Wallet20", + "state": { + "algo": 320000000000000n, + "onl": 1, + "sel": "cDT+xkHQJ13RgfkAUoNMfGk890z2C1V4HSmkxbm6gRk=", + "vote": "r66g4ULatIt179X+2embK0RgwoLdPEq3R3uTTMfP9Hk=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "DBGTTXBPXGKL4TBBISC73RMB3NNZIZBSH2EICWZTQRA42QKNA4S2W4SP7U", + "comment": "Wallet3", + "state": { + "algo": 320000000000000n, + "onl": 1, + "sel": "DmlAnKrkD8lgUB1ahLsy/FIjbZ0fypaowyDc8GKwWZA=", + "vote": "ROBSmA9EfZitGyubHMTfmw8kSiohADB3n4McvTR8g88=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "XKZWM4PWPLZZWIANNT4S7LU26SPVIKMCDVQAAYRD4G3QJIOJL2X6RZOKK4", + "comment": "Wallet4", + "state": { + "algo": 320000000000000n, + "onl": 1, + "sel": "74a0jcs/Y/uCh24vej1rb6CHu64yvW2nYrM0ZUVEhMo=", + "vote": "rwkur9iwJbzNECWvELxzFeJpbZl7dpiThgPJOHnRykg=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "LPBKDDUNKPXE7GAICEDXGTNCAJNC6IFJUSD4IK2H2IIB3OAFXLM3RLLIVQ", + "comment": "Wallet5", + "state": { + "algo": 320000000000000n, + "onl": 1, + "sel": "V4ldV+IY068YK/h7Wb6aNRIo8pr2bYQg8KDgFd25xVw=", + "vote": "d2KdyajjKvpukuGmM2MxEC9XDEgjjF/Spsevjd877RI=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "MZZS43WEFY56LV3WXEVLROT3LYFLEBZ536UY3Z3J56S7EI3SYYOJVO6YRM", + "comment": "Wallet6", + "state": { + "algo": 320000000000000n, + "onl": 1, + "sel": "BoBmrNpHTxySZ8DIlg5ZlINKwTPd/K75CCdhNzs9alo=", + "vote": "N6v+PVEUn9fLZb+9sQDu5lpCpsXLHY0skx/8bWDqk7Q=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "RP7BOFGBCPNHWPRJEGPNNQRNC3WXJUUAVSBTHMGUXLF36IEHSBGJOHOYZ4", + "comment": "Wallet7", + "state": { + "algo": 320000000000000n, + "onl": 1, + "sel": "n0LW+MxrO2S8/AmPClPaGdTDC5PM/MENdEwrm21KmgU=", + "vote": "/e1z3LMbc8C4m9DZ6NCILpv7bZ/yVdmZUp/M32OSUN4=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "RDHKWTWXOE5AOWUWTROSR4WFLAHMUCRDZIA7OFBXXMMRBXGQ4BYQRPOXXU", + "comment": "Wallet8", + "state": { + "algo": 320000000000000n, + "onl": 1, + "sel": "AGJ4v2nOA62A8rGm4H56VEo/6QdhVVJUuEASUybDPNI=", + "vote": "eL2GxfrIoG2kuknlGa8I6vPtMbpygYflrye0u/hE4Lg=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "UXPVVSG7EYC7YR7PRVOZKWYYYZPKEXWGYR6XHBMSAV6BHKQEVFYVYJBVQI", + "comment": "Wallet9", + "state": { + "algo": 320000000000000n, + "onl": 1, + "sel": "P4tRdjhyJ9dSNItTY+r2+tQmPfHa6oBAzIh4X3df4gM=", + "vote": "VHITXAytk0804xXBLBVKGlRAcAcDSZKcR2fiz4HtWBU=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "GD64YIY3TWGDMCNPP553DZPPR6LDUSFQOIJVFDPPXWEG3FVOJCCDBBHU5A", + "comment": "bank-testnet", + "state": { + "algo": 200000000000000n, + "onl": 1, + "sel": "r6aMJIPeqUPB8u4IvOU/wihF+sgqJVsjibvsYHVqj1s=", + "vote": "mPB1VDBFOPSIEFhXo7VJRLxn45ylDSRnO8J1nXQf4f0=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "GFICEF3GYRENRQHINLRPG7TS7TUIOARUIN7KWXWFROSG55BWFFRCRX5DAA", + "comment": "n1-testnet", + "state": { + "algo": 150000000000000n, + "onl": 1, + "sel": "38qDzZjLPfernXNx7leElHsl39WLXMSgLHbEACeNgn4=", + "vote": "8ITl30j5PTSDjmR26G3/rZL7IQM3cSfqqxnJSZf3X0w=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "GFY7ND6YSM5OGNSMAJDYCO6O75SWQRCYOJHCWOPYHUYCWQFWML52TWREBQ", + "comment": "n10-testnet", + "state": { + "algo": 150000000000000n, + "onl": 1, + "sel": "iwwKBjoUUUePkoG0ldxc0v6i1fIhVySn2l2kWwekn2A=", + "vote": "DaZFFz72XkcUIuPXcEz6VxWj4SVjzMpOwpTfO2k308g=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "VQFEAD2SXHMLJ3BNSGYUHRZZWBOI7HUQZGFFJEKYD3SGNS667FTMPRDC4Y", + "comment": "n11-testnet", + "state": { + "algo": 50000000000000n, + "onl": 1, + "sel": "ckpVY6EaDInNeU1WLHQQXNsAaQnh+bpFhzNWzw0ZirI=", + "vote": "4N1HJ9R2TrTEzLOyO1vUWPYi6sUcdAwQWoHQNBR/CME=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "6J7K7FIYKWTT3LSOZKYWAMSZC5RDID4CJ24C2S5DBQ5V7YUIHOBHPAO4KY", + "comment": "n12-testnet", + "state": { + "algo": 50000000000000n, + "onl": 1, + "sel": "n16osH+x1UIrzDNa7PCZHn/UtheRoLcTBwGRnx0fTa8=", + "vote": "Tj0inLse0V3sQRPw+5rVQTIWOqTxn7/URDzUaWGHftg=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "G5KCM3LSFV4GHRYQBXGWTNMR5XESE3PIRODD7ZLASPIGOHPV7CO7UKLZFM", + "comment": "n13-testnet", + "state": { + "algo": 50000000000000n, + "onl": 1, + "sel": "tveXF/sDXqBXQY52IEMuvTeVguKzPfN8GLdKgtv3gRg=", + "vote": "uwQJnVuqEtdGnWbbfu+TTLe++56z8wQCzv22IDioALE=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "XNQAMZMMLQV3TGYGJYYLYZUHP4YNEKAJM6RAMJ5SBXFLS3XDBIUVGCZPH4", + "comment": "n14-testnet", + "state": { + "algo": 50000000000000n, + "onl": 1, + "sel": "8xotecjUoo1YVzWME3ib9uh+kPUNnzsFcuHrjxxhjZM=", + "vote": "oQ/iakoP5B6gTTm0+xfHHGFS4Ink30I6FWUGkxRNfo8=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "WXCLU5C6QH6KPVNAHNBGFUMC5JAOQCZP3HF76OT2TH3IAI3XTSPCLVILSU", + "comment": "n15-testnet", + "state": { + "algo": 200000000000000n, + "onl": 1, + "sel": "NRxs0rM5dov2oZrf6XrFSmG9CRlS3Bmzt0be7uF/nHw=", + "vote": "R8xKtpYYNuTuTqMui/qzxYpc1m8KpbaK/eizYxVQDaY=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "7NRVO2ABPGFRX3374TIJZ46BR72CCSHKTR6PG5VVYNLUPWUVXGOU3O5YQA", + "comment": "n16-testnet", + "state": { + "algo": 200000000000000n, + "onl": 1, + "sel": "IQG+jgm2daCxMLxm/f9tTVrDk/hD0ZhB5dxDQn47BSE=", + "vote": "CGwAHrq3QFFlsP7NmHed+Xx4BwFsE2f6dB30Os75KxY=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "537URFEXANB7M6UVND6WDM75DPRRORDXWFLSOG7EGILSKDIU4T32N4KAN4", + "comment": "n17-testnet", + "state": { + "algo": 200000000000000n, + "onl": 1, + "sel": "SdLlaWBe8B1JanMq0Y7T1Z9C8dKhI36MQiSffXQt7Lo=", + "vote": "k4Xr6Bg6VpcY0GKwfr6kI89KqOihmCOToLLuIgFjv9c=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "ZNQXW7V5MISZFOZGVLAHKXS7GLWLXCLRPZTTIAZSTFRZPYTC54NWDZ6XZY", + "comment": "n18-testnet", + "state": { + "algo": 200000000000000n, + "onl": 1, + "sel": "TNMELlR1C+r4OmGVp9vc9XlehgD3a0EwfrepuMiDe+c=", + "vote": "060veVAG/L2r2IAjqs2TcYy2cthocqrhgrCCoP5lzZ4=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "G3WQEPSGZOQVVJ2H3F6ICMHRIE2JL6U3X3JDABWJRN4HNDUJIAT4YTOGXA", + "comment": "n19-testnet", + "state": { + "algo": 300000000000000n, + "onl": 1, + "sel": "ktbtHTm1mUU5u/VMrOuMujMgemUf496zilQsGBynsxQ=", + "vote": "XHXYdLvxKIIjtlmwHVqxvtAyRDE+SQR1tpzgXoNo5FA=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "2YNZ5XDUHYXL2COTVLZBRYV2A7VETFKQZQCPYMQRBOKTAANHP37DUH5BOI", + "comment": "n2-testnet", + "state": { + "algo": 150000000000000n, + "onl": 1, + "sel": "u7lR9NcWfssuMvFYuqCi5/nX0Fj9qBKbE0B2OpRhmMg=", + "vote": "/UGQ/1dcp7OTmguYALryqQYRj0oMWhs/ahAbQTL/mRA=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "IH5Z5UZCZKNAH5OICUGHFEYM2JDMJRUSIUV4TZEQYHRNS3T2ROOV32CDIA", + "comment": "n20-testnet", + "state": { + "algo": 300000000000000n, + "onl": 1, + "sel": "Jbcg+BVB6EOTe42U0dq1psQfoFZItb6Phst22z33j60=", + "vote": "8Y1QY+WJIziffLecmnr0ZRGJFKtA3oVALQoD3nVKlt8=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "FFJZOPQCYSRZISSJF33MBQJGGTIB2JFUEGBJIY6GXRWEU23ONC65GUZXHM", + "comment": "n3-testnet", + "state": { + "algo": 150000000000000n, + "onl": 1, + "sel": "+K8AsLfvuTEuHMANNp2LxGuotgEjFtqOjuR/o4KR6LA=", + "vote": "SerMKyY37A1jFkE0BdrP+vuTdVn9oOJc5QjC5f98Dz8=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "ZWYIEI37V6HI62ZQCPJ5I6AIVKZP6JVCBQJKZEQQCWF4A4G2QGFENKS5XU", + "comment": "n4-testnet", + "state": { + "algo": 150000000000000n, + "onl": 1, + "sel": "SmhBpQdh23++6xC01unged2JU1Wgm2zZ8v5LQiG/VqA=", + "vote": "U2lZo9ahjkKBvcS3qSWsmSx+PGI/m6OtnQrQOH1iuII=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "V32YQ6LMMT7X6MML35KOX4MKY7LXWEH4JETZYKAXQ5RX4ZQQ6FAJJ6EGJQ", + "comment": "n5-testnet", + "state": { + "algo": 150000000000000n, + "onl": 1, + "sel": "0yRtE7WSj32D5e/ov4o22ZgipQvqJZ6nx9NX1LdxFJI=", + "vote": "scoN8x6Eq0bV4tBLT5R59jU+8gmHgh/6FX6mfV2tIKY=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "OEFWPZHFT25CSDHFRFW62JANGQLB5WD25GJBCGYTTPHFUMAYYD7SEAIVDI", + "comment": "n6-testnet", + "state": { + "algo": 150000000000000n, + "onl": 1, + "sel": "dWChUcA1ONX3iNEvHu9GST67XRePhAv6jd3XWt5clvI=", + "vote": "rTfQ/l3lEfGQtzwjFii5ir2nCLSU+RT+0xI5af/XDEU=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "KCQLDL4GCVDLDYW5PYK7GJTUGHYRJ6CZ4QSRIZTXVRUIUAMDKYDFNUIFHU", + "comment": "n7-testnet", + "state": { + "algo": 150000000000000n, + "onl": 1, + "sel": "gNXMo6XiZvuQs2mtomJZtra7XiZHySIOWLuWivu4iso=", + "vote": "okgQcI/L7YDAMOyqrLKs6CUB91k+mMFfMTaEb+ixvyY=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "UMMQNIYQXSI4VBGBXJUQ64ABURY6TPR7F4M5CMCOHYMB7GPVIZETZRNRBM", + "comment": "n8-testnet", + "state": { + "algo": 150000000000000n, + "onl": 1, + "sel": "ukzMIkE2U33xKq6LGX19NBLirZNANQAf3oiZtlkn5ls=", + "vote": "HYHBaeVeN0DXYBNjRBuGtZqrBr3bSBC1YDQrv93dNrc=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "2INEY2MWIWIUNQS24YVXKT4M3RIKMEZGTVAOJG47N7EOJE7MKXOC6GJSMU", + "comment": "n9-testnet", + "state": { + "algo": 150000000000000n, + "onl": 1, + "sel": "7aUtPCawOYpPYjVd6oZOnZ+1CZXApr8QR4q1cOkVyWo=", + "vote": "kcq1XWHnMrjbv/fvMmzIfGZzDtJtdL7i70lpWZ0kGi0=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "IE4C3BNWT4EYKPUZXGWDOOKBTJFVOYAZKBCWFYRC37U7BJKBIUH6NEB7SQ", + "comment": "pp1-testnet", + "state": { + "algo": 50000000000000n, + "onl": 1, + "sel": "C3PdYqoDjrjyaGvZ6M/W0E56Mv5BXdtRwj7+4unpxDM=", + "vote": "8fdNikU3nMNyZb3AZlNTnsfsytvrd8bK2b/dYQgJj30=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "7WCI7XPEMWY6XNWHG2VXGYGDLHPTJ333CZ2WBGGUHCSYPTXPBWYCHZYTSE", + "comment": "pp2-testnet", + "state": { + "algo": 25000000000000n, + "onl": 1, + "sel": "l3K4aA15T42mTM+QE7GpOzbOcth6hMljBxna7gSR8IA=", + "vote": "NsjSVQJj4XxK5Tt0R7pvU6wQB0MRKHDwC9F2bfUX/vM=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "WYX5JGDYM7TBTMBBEE2OI4GC4KVCTLB2P67B3PUQQS4OMUERE7NIIZDWO4", + "comment": "pp3-testnet", + "state": { + "algo": 25000000000000n, + "onl": 1, + "sel": "YmLs97jSdlbYU1H0PwZdzo6hlp0eyBwJ+ydM9ggEENI=", + "vote": "GeDnbm9KKEu2dZ1FACwI0NsVWgoU0udpZef06IiTdfQ=", + "voteKd": 10000n, + "voteLst": 3000000n, + }, + }, + { + "addr": "2GJF4FEEPNCFKNYSOP6EOQGDQQCGDXPQHWE474DCKP5QO3HFBO73IBLBBY", + "comment": "u1-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "NHZ3VOL34MVWENM72QB6ZBRDMFJTU6R57HAJALSBERH4BNAGR4QDYYBT7A", + "comment": "u10-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "PTLGEQAIGTDWHPKA3IC5BL5UQE52XDZHQH7FUXRV4S6ZBRR5HGZENQ7LTQ", + "comment": "u100-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "3IE2GDYYSI56U53AQ6UUWRGAIGG5D4RHWLMCXJOPWQJA2ABF2X2OLFXGJE", + "comment": "u11-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "IAMUOCM2SEISQZYZZYTLHKSAALDJIXS2IQRU2GPZUOZWB2NLMFZPJSQ7VQ", + "comment": "u12-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "54GKXNGS7HNFHZGO7OIWK3H2KPKZYWSARW7PV4ITVTNCA65K6ESRKI6N3U", + "comment": "u13-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "5ZSFGF66FIJMMRORTYD2PLDAN67FA2J7LF3IYF4ZKD4DJHLEBYJ76DXGVU", + "comment": "u14-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "DY7K3FLRZTW2ZTYVOC4TCGK4JBL7NSJ4GR4BU252QNAVOCVTGEBCPCSJME", + "comment": "u15-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "JG4JQZNYP2524UDVRPPIMSFCIVQPVXLB5AKHM76VXIIRFNMIN3ROIYW65E", + "comment": "u16-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "7J4QX5DVIXSWBC2NJB44LPPUJXOAJQFMBCOS4EDI3XOE5WS76IY7WFTBQI", + "comment": "u17-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "6SA2WG5XM5Q6SSMBRK3TOHY552A75RVANBQQMKTT67PLUN44T3CJZAQOPM", + "comment": "u18-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "64DCC5CMTM4SMMO3QRTY3EDCHS73KDSNNH2XZL262DBK2LR4GJRETWUWIE", + "comment": "u19-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "TQ2B4MTCC6TARNEP4QPPMCKNBBNXKFTQKPVLAFC5XXRR2SWV5DICZELJOY", + "comment": "u2-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "ATNCIRLQLVZ7I4QBGW54DI6CY4AJVBQBPECVNS645RBMYDTK6VV55HXFUU", + "comment": "u20-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "4LP77VEVJ7QNESED4GICPRBZUNP7ZLKKLEVBRDSKX5NZSUFXPSEA575K5E", + "comment": "u21-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "7D34RBEHVI3A7YTQWOUTCSKNQYS5BDBN4E647DOC6WDVOLHPDPSSBY4MWI", + "comment": "u22-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "UMMKTTPNHIURGX24K7UYJ7T3WBB5J7OYBOQJ5WLPRG3BDYWJAEJLVBNHME", + "comment": "u23-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "EOPSQC3QTL7QJ4AQ2J4OJIJMKQLTMIEETJI7OFWYADIMHDWMHQ6MWCTUMQ", + "comment": "u24-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "XT3AVLURALOWTIMGZKB37J2M22NUQCRXTL4DJZHSTPCGLNQKVL7MR3MKFM", + "comment": "u25-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "WS63FDTLLYHC2NS7NXTEO7RPLNMAFM2D2BPJLTMAQJWPR2JCNYTTRMSOAE", + "comment": "u26-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "P5S5GGUHOMVOKWOZPJO74MBYVRXQWDBW6AOTHQZVKJKFGM7VBU6CNR4ATI", + "comment": "u27-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "PXVAI3MUYH4WWJXEQP7XNH3YIMO5ZBAFJWYUL7DOGPAHALE4K6GZBF4THU", + "comment": "u28-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "VGTKWLFANSULZAFDGBONHF55VVKE4V4F63JRDB66XM4K6KCQX6CL22WPRE", + "comment": "u29-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "QB2OTQ6DKUEJFP66A37ASIT4O3UZUOX24DAMWU2D3GCBDIYIXSIDHSXO4E", + "comment": "u3-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "4F6LA64ZLFN33ATWJ74UPAX56OLTXPL74SS5ATXUL7RGX7NKEFKMAWUQYE", + "comment": "u30-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "3JBNL7BZECXKYWZRPWETNL65XEYMAHLC6G3MZN2YMPFL3V7XSDXZEMBHVQ", + "comment": "u31-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "4M2QSKTXKPPZMNUAQ4UDS7ASMQCEUE4WTWGV6AM326425IJ64UNZBCIRGA", + "comment": "u32-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "J37V3LXHPRRKBODXNMNYNUJQIICCFFC4O4XB4YJCPVUAVZNOUG5DWDCEIA", + "comment": "u33-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "I75JBQHNYEYM3J742RBVW4W6RR3YY3BLG2PKO4PXYLVNEX5L646ASDJOOY", + "comment": "u34-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "ZHEIOZ7E2BEBCCKK5QM7DCZAOPTTONMQWHNJ6FOLKBHY466VON6DCZERD4", + "comment": "u35-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "4QMGP4C6OMSCNJI25H7UQGBFHRHL7KXAEQI57JNAXEO2EW3VT6D6LODT5Y", + "comment": "u36-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "KRED3JOLOJE3SLL5NGHAWSUGEMHCYJLD6PX43SIJYN2GC6MS6HPUPPO2LY", + "comment": "u37-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "SVFLDISKS4PDMJKOB6DVVVN6NQ776FHZMGWCOUQVQCH6GXTKCXIHTLYRRQ", + "comment": "u38-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "7IWGAPZ4VWRZLP2IHFSAC3JYOKNAZP6ONBNGGWUWHAUT7F23YFT3XKGNVU", + "comment": "u39-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "O2QVZMKATOIEU2OD4X42MLXAYVRXLRDKJTDXKBFCN3PCKN2Z3PUS5HKIVA", + "comment": "u4-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "H2YN73YPRWKY4GT744RRD65CXSQZO7MK72MV4RDHTIBV6YQUB2G56TVF2Y", + "comment": "u40-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "WGUAFWHRRX7VXPO3XXYCJL5ELO6REUGD57HRMBKTALT2TTXOLSHNOUEQCE", + "comment": "u41-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "RYHCD7GPAEBRV657FJJAG2ZZUDVPR66IU7CA5Y7UDMYSEEIWR4QDNSPLYQ", + "comment": "u42-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "BKTO5TKB4L57YWTZKQBOQ37EWH2HVXGJPXP3L6YSYOAWP3CYYBWLZ2PHTQ", + "comment": "u43-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "FL7LZ57VQQNW5NDJK2IKEAHIXRTB7VFBJEA2MIAEK3QVZPIBGLYW7XSZDY", + "comment": "u44-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "MXXQXZS2TAMIULLXXLX6MM6AHJAOQLHEIB2U3LR4KYKK7ZKRVUSHTU62QA", + "comment": "u45-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "UGOPPKTJQ2KPHU5I56733IMT3B7ECT5O44GW2FYX5SNDVIEDG72Z5GC5IA", + "comment": "u46-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "Y7MGWPRBHQN2PF3I2A3RWCQMVA42VR6FJONJ3W26WGKE4KMCGCVJIDLHEY", + "comment": "u47-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "NNFIWU43AUEZIUIQQECDXM3HRPUEJMPPZLXTM4ZFJKHWSZ2FEGCVMMJUBQ", + "comment": "u48-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "RN3HTSJKSUO6OECM3OPDFQQ2FYZWEY2OWAQGSMQSGY4DI7JJ4HBV2OIJJU", + "comment": "u49-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "OLYQUMZKLYDX2FVHECURBX4SRQSLMIIWN7D7VRJG7B6DS3IU6M5WYVNAAY", + "comment": "u5-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "PIG4P6JA2WDG7HBBR4FFDMVUCUD5Y5CTQ3K3KY34Y4AMT3CWEMVIKQLZZI", + "comment": "u50-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "QIDX47JRS37LRIYVY744SV7KTFGYXY5ABEK2VALNZCMN2H4FBLO7WWKYRM", + "comment": "u51-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "VQZCPUMOYIGCXOK2AK4XYYLWJNRBLS457IL4OSBKGVBHFZ5QPLTCUOTW4A", + "comment": "u52-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "WE2AIYHXI2LHABITCPTZRBTLFT54HPL4MKIR4HTASARNGCCZLXXDE67H3M", + "comment": "u53-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "HAIGM3LXXVKDCGCNQELNOBFZKP6C4A2ZY464F4TB7GWSVDN6I4SI7EOZUE", + "comment": "u54-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "MVZLGPXT6DZQIORE4PIO7NZD7QMJOZZZCOEVPZ3EQX2V4WG3PFU3BXUGDI", + "comment": "u55-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "MB5XJGVVKQU7NSEWWP65QW6H4JVEQYPA5626J4NGQP2E4BUMXRTEGW5X5Y", + "comment": "u56-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "EODZLNWFSRYZKLLF2YAOST2CYQCBRQGXPFQJLDW4CCMYFTYKBSWMF6QUAU", + "comment": "u57-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "LPAMNP7GJC5CNOMWRDII47WWYPF3TOVEIBDSSJA6PKOCPZ5AKRUWMIU2OM", + "comment": "u58-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "THRYS4MAIMEKG7BSAZ4EOKCVUJ7HA6AOCTK2UOKDGZ4TF7Q4BRVTBOUSYU", + "comment": "u59-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "7V7YITMPBTJ3IHHS2D35PVWRZGNFYWWQVRMTI4QP2CBPSKNDRGG66W2HFQ", + "comment": "u6-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "FHA2V46TK5CW66HQPOMLTH5PSKX2JX2IWLWZIYJUZ2RI7SK6HSSBTJBNHM", + "comment": "u60-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "7EJAXCVH7XLWDCWSXID4FNZ6T2SZRA4S7XIZOWA74ITAB272ZF2T5LSWSE", + "comment": "u61-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "K5L3YNZPU6SVNJOWAOKULCWBPIBNMR2VBCASVI4NWDM2APZ6GL36DFDR5Y", + "comment": "u62-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "5BY6RFBNUYHBYH4E4AWVMEOMI7YFKX7X3IPB5GRGAHH4BSXHIL34P3H43A", + "comment": "u63-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "BX2UBG5VCT2ASTGXHVG5NS6VVCYVB6GLKBN4NAAN7ABSTP7BMYCX2T2WEY", + "comment": "u64-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "37JPBYKXMWF6DO3FFWW53LBQCG636MTC7WG6DTRAPDFVXUIATFOMFR5ZLQ", + "comment": "u65-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "ODSPT3NISYMGEE3TJ6U6JCVC44L7DUCPHIV2QMPPRKBWJDALALGVCAPMRE", + "comment": "u66-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "CQA775B5TCU72Y2BNL6VCURBVJE45QV77RXHQ5KYRMMP6NCQ5BR7XJRYRA", + "comment": "u67-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "3Q4SYOBDOAVXUUTKBXEFFSK3BQMUQX5ORZPDA4PHB56KJJONPFFJ7YZ6HU", + "comment": "u68-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "K23ME4QVDHSJWMGUHPGCL2OODAGBHIBW2KGYLLIR3UAEFD5ZW2KFB4WJ34", + "comment": "u69-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "UD2OLL24RFDFMAKK7CCHKFIABPAP7ET4CYQUEYCJVGEIEJUAMDOGJZT26Y", + "comment": "u7-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "KYXWZODLYDHTDMRUBOGOEV42G6H6KJ2JSBFZBP6XNWT42A6QEMEW23JWAM", + "comment": "u70-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "V464X6D3XJVVJ372FFC2NBBDZLBNQA6H55J57WJMMSNOLHOJQ5UF3EUGNY", + "comment": "u71-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "K27ODRPQARZM3236D2XC27QIV27GO2MUR65RGAJKO7UACIFYHG5QKPOCFU", + "comment": "u72-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "FT3JD6TXUZOLOMN4O5CFZYSIHR4T5XJIF2YNV6WGEORNO2X65QW3VUP77I", + "comment": "u73-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "WOTGZ4WOQ4S7YWVAOQ52GGOQPYQI2M7EPZENR27AOZLYFIEJDI3RYFB7OU", + "comment": "u74-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "46MGTGNCTAC62NVNAVXAGP7PUJJIW5GXYYTSUDURCBSRZEDLGME7ICGE4E", + "comment": "u75-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "MBTXWM5M5XQNUEKLBTW7GPU4LFPUETQQPVUBRCOA7FQ47H4J727NFRKKQE", + "comment": "u76-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "4MCTFKPQCY25X6QARHGVD75OYUMQAAU5QLWCE2EM37NWOS7IFJSABMGKBI", + "comment": "u77-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "PY6K3OGCXZVYQYZVA7W3MVZCAU5AFAWQ5J5THILXYIBYCKCGH4ELFU6TNU", + "comment": "u78-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "4ABEMED4I7UYU6CJSLWYQXQHOK2XCQ443BSHR3SL7QJGXNYJ5QCYILSSNU", + "comment": "u79-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "AXBINC5KA3I6IF3JAMKYQU3JLYTA5P2U4PUW3M4L53NEBNCRLHDHHOT2HY", + "comment": "u8-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "5SXA2C6CGZ63OYDY5G4NFLIPJLKCZAMQWLMD2CBNSHUEXVS3ZYHAQCI5TI", + "comment": "u80-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "EVP6MJIZWN6EE64TKEI4ANETP25MHYVXFWESU626TFA5VDVC75KSBGAA54", + "comment": "u81-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "QAUV22GPBAOCO2JGAJF7U474S5SKXVWSZ7KG6P22P4MH3GNBGEJXAVDQLM", + "comment": "u82-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "4FOOFGIWV4H7AXTEJXV2C4ONZ5NXAMUDKJSZDLSKACZ4JA4SWIU6UTLZAU", + "comment": "u83-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "ARUMRBUW3HBQXE4QAL25PPVWAJSKGORTNUIOW3VA5GAMDECOVNYC7GJJS4", + "comment": "u84-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "EJGCYTFUZPJDL2JBZJFQXKZIYJUDB7IBF3E2BH6GXWYWXUHSBCKYFJUKSU", + "comment": "u85-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "FJMEFROCSGQ7C7IXMAPUST37QTQ2Y4A7RMLGK6YTUGHOCLOEL5BDE4AM2M", + "comment": "u86-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "4V635E2WOGIKKWZ6QMYXDWQLYTUKRN7YAYADBQPETS75MKCR66ZC5IEG5M", + "comment": "u87-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "AFJB4HWJLTMMA45VZAJJSUOFF7NROAEEMGT4Z3FQI5APWY472SJ6RNBWU4", + "comment": "u88-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "BYO56YQOSRBUTNPXYO4XDMG7FU7SIP3QGVKAYQIJVJ4UIIMBRG3E4JMVD4", + "comment": "u89-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "FQJO4LDTXEVQ2ZBFYDEAOYPQQZCZTMASMSXJ6V7LBYKOTFSCBUKKIU3DXA", + "comment": "u9-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "WUCEVFNJGUNLMNG2AJMVYJRGQUFXRAFVX2ZRT7AC47WS6IRHPXHSUZ4NUA", + "comment": "u90-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "5J5Q72IHCVAK5NE54ZI2RUZUF3HN2EAQEYQ674H3VX4UUHBMRYAZFRQDIY", + "comment": "u91-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "2LK2SZ3L4PWUXXM4XYFFSCFIV7V5VQJUDFVK7QXK6HJL4OUQKQLWG77EUI", + "comment": "u92-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "QUWHMJLFQAIIG5LV7NK5VNESUUW23RINBSHKKKQDIV4AP56RSTYSNZHDRQ", + "comment": "u93-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "YJEGUEJ2UW2ABLO6XI5QIHQID5ZKUDUDQPHQEN7MH5SS2FLZ573CHRHCZM", + "comment": "u94-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "XOUVBGEZMDVYPES4MGTAEBYU5O6LOCOH27ZJ3ML7ATWEU63N6IWW6F4BLM", + "comment": "u95-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "6CFS2YVK2IMVVFBGGHSPUQBIKMNWRRB44EIUUB4EFXAL7IOJXAHRGXKAGA", + "comment": "u96-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "W5ITKFRKK265A4WKF7IRCZ4MCC7HM3INCJGKPPH3AEKDFYMOJJ4FDLQWYI", + "comment": "u97-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "MBMU3IODI6OFX34MBDMNTD6WSVA6B3XLDVB3IHZJQY3TZUYBPKRNFTUQSM", + "comment": "u98-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + { + "addr": "CKNVTB7DPRZO3MB64RQFPZIHCHCC4GBSTAAJKVQ2SLYNKVYPK4EJFBCQKM", + "comment": "u99-testnet", + "state": { + "algo": 2000000000000n, + }, + }, + ], + "fees": "A7NMWS3NT3IUDMLVO26ULGXGIIOUQ3ND2TXSER6EBGRZNOBOUIQXHIBGDE", + "id": "v1.0", + "network": "testnet", + "proto": "https://github.com/algorand/spec/tree/a26ed78ed8f834e2b9ccb6eb7d3ee9f629a6e622", + "rwd": "7777777777777777777777777777777777777777777777777774MSJUVU", + "timestamp": 1560210455, +} +`; diff --git a/packages/algod_client/tests/__snapshots__/get_health.test.ts.snap b/packages/algod_client/tests/__snapshots__/get_health.test.ts.snap new file mode 100644 index 00000000..9c3fbbfc --- /dev/null +++ b/packages/algod_client/tests/__snapshots__/get_health.test.ts.snap @@ -0,0 +1,3 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`GET health > Common Tests > Basic request and response validation 1`] = `undefined`; diff --git a/packages/algod_client/tests/__snapshots__/get_ready.test.ts.snap b/packages/algod_client/tests/__snapshots__/get_ready.test.ts.snap new file mode 100644 index 00000000..b05ba1f1 --- /dev/null +++ b/packages/algod_client/tests/__snapshots__/get_ready.test.ts.snap @@ -0,0 +1,3 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`GET ready > Common Tests > Basic request and response validation 1`] = `undefined`; diff --git a/packages/algod_client/tests/__snapshots__/get_v_2_accounts_address.test.ts.snap b/packages/algod_client/tests/__snapshots__/get_v_2_accounts_address.test.ts.snap new file mode 100644 index 00000000..fc3b0bf4 --- /dev/null +++ b/packages/algod_client/tests/__snapshots__/get_v_2_accounts_address.test.ts.snap @@ -0,0 +1,7261 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`GET v2_accounts_ADDRESS > Common Tests > Basic request and response validation 1`] = ` +{ + "address": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "amount": 13857000n, + "amountWithoutPendingRewards": 13857000n, + "appsLocalState": [], + "appsTotalSchema": { + "numByteSlice": 8, + "numUint": 23, + }, + "assets": [ + { + "amount": 0n, + "assetId": 705457144n, + "isFrozen": false, + }, + ], + "createdApps": [ + { + "id": 705408386n, + "params": { + "approvalProgram": Uint8Array [ + 10, + 32, + 3, + 0, + 1, + 4, + 38, + 6, + 11, + 97, + 117, + 99, + 116, + 105, + 111, + 110, + 95, + 101, + 110, + 100, + 12, + 112, + 114, + 101, + 118, + 105, + 111, + 117, + 115, + 95, + 98, + 105, + 100, + 15, + 112, + 114, + 101, + 118, + 105, + 111, + 117, + 115, + 95, + 98, + 105, + 100, + 100, + 101, + 114, + 3, + 97, + 115, + 97, + 10, + 97, + 115, + 97, + 95, + 97, + 109, + 111, + 117, + 110, + 116, + 5, + 99, + 108, + 97, + 105, + 109, + 49, + 24, + 64, + 0, + 3, + 136, + 1, + 163, + 49, + 27, + 65, + 0, + 166, + 128, + 4, + 40, + 38, + 178, + 2, + 128, + 4, + 240, + 170, + 112, + 35, + 128, + 4, + 48, + 198, + 213, + 138, + 128, + 4, + 219, + 127, + 232, + 67, + 128, + 4, + 230, + 84, + 98, + 91, + 128, + 4, + 30, + 193, + 43, + 239, + 54, + 26, + 0, + 142, + 6, + 0, + 1, + 0, + 19, + 0, + 49, + 0, + 61, + 0, + 83, + 0, + 95, + 0, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 23, + 192, + 48, + 136, + 0, + 106, + 35, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 23, + 54, + 26, + 2, + 23, + 49, + 22, + 35, + 9, + 73, + 56, + 16, + 36, + 18, + 68, + 136, + 0, + 112, + 35, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 136, + 0, + 144, + 35, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 49, + 22, + 35, + 9, + 73, + 56, + 16, + 35, + 18, + 68, + 136, + 0, + 126, + 35, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 136, + 0, + 162, + 35, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 23, + 192, + 48, + 136, + 0, + 207, + 35, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 20, + 68, + 35, + 67, + 138, + 1, + 0, + 49, + 0, + 50, + 9, + 18, + 68, + 34, + 43, + 101, + 68, + 20, + 68, + 43, + 139, + 255, + 103, + 177, + 50, + 10, + 139, + 255, + 178, + 17, + 178, + 20, + 36, + 178, + 16, + 34, + 178, + 1, + 179, + 137, + 138, + 3, + 0, + 49, + 0, + 50, + 9, + 18, + 68, + 34, + 40, + 101, + 68, + 20, + 68, + 139, + 255, + 56, + 20, + 50, + 10, + 18, + 68, + 139, + 255, + 56, + 18, + 39, + 4, + 76, + 103, + 50, + 7, + 139, + 254, + 8, + 40, + 76, + 103, + 41, + 139, + 253, + 103, + 137, + 138, + 0, + 0, + 137, + 138, + 1, + 0, + 50, + 7, + 34, + 40, + 101, + 68, + 12, + 68, + 139, + 255, + 56, + 0, + 73, + 49, + 0, + 18, + 68, + 139, + 255, + 56, + 8, + 34, + 41, + 101, + 68, + 75, + 1, + 12, + 68, + 41, + 75, + 1, + 103, + 42, + 79, + 2, + 103, + 49, + 0, + 39, + 5, + 79, + 2, + 102, + 137, + 138, + 0, + 0, + 49, + 0, + 34, + 39, + 5, + 99, + 76, + 73, + 79, + 2, + 68, + 49, + 0, + 34, + 42, + 101, + 68, + 18, + 65, + 0, + 10, + 34, + 41, + 101, + 68, + 139, + 0, + 76, + 9, + 140, + 1, + 177, + 49, + 0, + 178, + 7, + 139, + 1, + 73, + 178, + 8, + 35, + 178, + 16, + 34, + 178, + 1, + 179, + 49, + 0, + 139, + 0, + 79, + 2, + 9, + 39, + 5, + 76, + 102, + 137, + 138, + 1, + 0, + 50, + 7, + 34, + 40, + 101, + 68, + 13, + 68, + 177, + 34, + 42, + 101, + 68, + 34, + 42, + 101, + 68, + 34, + 39, + 4, + 101, + 68, + 178, + 18, + 178, + 20, + 178, + 21, + 139, + 255, + 178, + 17, + 36, + 178, + 16, + 34, + 178, + 1, + 179, + 137, + 138, + 0, + 0, + 40, + 34, + 103, + 41, + 34, + 103, + 39, + 4, + 34, + 103, + 43, + 34, + 103, + 42, + 50, + 3, + 103, + 137, + ], + "clearStateProgram": Uint8Array [ + 10, + 129, + 1, + 67, + ], + "creator": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "globalState": [ + { + "key": Uint8Array [ + 97, + 115, + 97, + ], + "value": { + "bytes": Uint8Array [], + "type": 2, + "uint": 0n, + }, + }, + { + "key": Uint8Array [ + 97, + 115, + 97, + 95, + 97, + 109, + 111, + 117, + 110, + 116, + ], + "value": { + "bytes": Uint8Array [], + "type": 2, + "uint": 0n, + }, + }, + { + "key": Uint8Array [ + 97, + 117, + 99, + 116, + 105, + 111, + 110, + 95, + 101, + 110, + 100, + ], + "value": { + "bytes": Uint8Array [], + "type": 2, + "uint": 0n, + }, + }, + { + "key": Uint8Array [ + 112, + 114, + 101, + 118, + 105, + 111, + 117, + 115, + 95, + 98, + 105, + 100, + ], + "value": { + "bytes": Uint8Array [], + "type": 2, + "uint": 0n, + }, + }, + { + "key": Uint8Array [ + 112, + 114, + 101, + 118, + 105, + 111, + 117, + 115, + 95, + 98, + 105, + 100, + 100, + 101, + 114, + ], + "value": { + "bytes": Uint8Array [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": 1, + "uint": 0n, + }, + }, + ], + "globalStateSchema": { + "numByteSlice": 1, + "numUint": 4, + }, + "localStateSchema": { + "numByteSlice": 0, + "numUint": 1, + }, + }, + }, + { + "id": 705410358n, + "params": { + "approvalProgram": Uint8Array [ + 8, + 32, + 3, + 0, + 1, + 4, + 38, + 6, + 11, + 104, + 105, + 103, + 104, + 101, + 115, + 116, + 95, + 98, + 105, + 100, + 3, + 97, + 115, + 97, + 14, + 104, + 105, + 103, + 104, + 101, + 115, + 116, + 95, + 98, + 105, + 100, + 100, + 101, + 114, + 11, + 97, + 117, + 99, + 116, + 105, + 111, + 110, + 95, + 101, + 110, + 100, + 7, + 97, + 115, + 97, + 95, + 97, + 109, + 116, + 0, + 49, + 27, + 34, + 18, + 64, + 0, + 248, + 54, + 26, + 0, + 128, + 4, + 40, + 38, + 178, + 2, + 18, + 64, + 0, + 215, + 54, + 26, + 0, + 128, + 4, + 240, + 170, + 112, + 35, + 18, + 64, + 0, + 156, + 54, + 26, + 0, + 128, + 4, + 57, + 4, + 42, + 238, + 18, + 64, + 0, + 104, + 54, + 26, + 0, + 128, + 4, + 181, + 137, + 6, + 134, + 18, + 64, + 0, + 76, + 54, + 26, + 0, + 128, + 4, + 201, + 1, + 40, + 49, + 18, + 64, + 0, + 30, + 54, + 26, + 0, + 128, + 4, + 36, + 55, + 141, + 60, + 18, + 64, + 0, + 1, + 0, + 49, + 25, + 129, + 5, + 18, + 49, + 24, + 34, + 19, + 16, + 68, + 136, + 1, + 152, + 35, + 67, + 49, + 25, + 34, + 18, + 49, + 24, + 34, + 19, + 16, + 68, + 54, + 26, + 1, + 34, + 85, + 53, + 5, + 54, + 26, + 2, + 34, + 85, + 53, + 6, + 52, + 5, + 52, + 6, + 136, + 1, + 88, + 35, + 67, + 49, + 25, + 34, + 18, + 49, + 24, + 34, + 19, + 16, + 68, + 136, + 1, + 62, + 35, + 67, + 49, + 25, + 34, + 18, + 49, + 24, + 34, + 19, + 16, + 68, + 54, + 26, + 1, + 34, + 85, + 53, + 4, + 49, + 22, + 35, + 9, + 53, + 3, + 52, + 3, + 56, + 16, + 35, + 18, + 68, + 52, + 3, + 52, + 4, + 136, + 0, + 218, + 35, + 67, + 49, + 25, + 34, + 18, + 49, + 24, + 34, + 19, + 16, + 68, + 54, + 26, + 1, + 23, + 53, + 0, + 54, + 26, + 2, + 23, + 53, + 1, + 49, + 22, + 35, + 9, + 53, + 2, + 52, + 2, + 56, + 16, + 36, + 18, + 68, + 52, + 0, + 52, + 1, + 52, + 2, + 136, + 0, + 103, + 35, + 67, + 49, + 25, + 34, + 18, + 49, + 24, + 34, + 19, + 16, + 68, + 54, + 26, + 1, + 34, + 85, + 136, + 0, + 41, + 35, + 67, + 49, + 25, + 34, + 18, + 64, + 0, + 1, + 0, + 49, + 24, + 34, + 18, + 68, + 136, + 0, + 2, + 35, + 67, + 138, + 0, + 0, + 41, + 34, + 103, + 39, + 4, + 34, + 103, + 43, + 34, + 103, + 40, + 34, + 103, + 42, + 39, + 5, + 103, + 137, + 138, + 1, + 0, + 49, + 0, + 50, + 9, + 18, + 68, + 41, + 100, + 34, + 18, + 68, + 41, + 139, + 255, + 192, + 48, + 103, + 177, + 36, + 178, + 16, + 34, + 178, + 1, + 50, + 10, + 178, + 20, + 139, + 255, + 192, + 48, + 178, + 17, + 34, + 178, + 18, + 179, + 137, + 138, + 3, + 0, + 49, + 0, + 50, + 9, + 18, + 68, + 43, + 100, + 34, + 18, + 68, + 139, + 255, + 56, + 20, + 50, + 10, + 18, + 68, + 139, + 255, + 56, + 17, + 41, + 100, + 18, + 68, + 39, + 4, + 139, + 255, + 56, + 18, + 103, + 43, + 50, + 7, + 139, + 254, + 8, + 103, + 40, + 139, + 253, + 103, + 137, + 138, + 2, + 0, + 177, + 35, + 178, + 16, + 139, + 254, + 178, + 7, + 139, + 255, + 178, + 8, + 34, + 178, + 1, + 179, + 137, + 138, + 2, + 0, + 50, + 7, + 43, + 100, + 12, + 68, + 139, + 254, + 56, + 8, + 40, + 100, + 13, + 68, + 139, + 254, + 56, + 0, + 49, + 0, + 18, + 68, + 139, + 254, + 56, + 7, + 50, + 10, + 18, + 68, + 42, + 100, + 39, + 5, + 19, + 65, + 0, + 7, + 42, + 100, + 40, + 100, + 136, + 255, + 188, + 40, + 139, + 254, + 56, + 8, + 103, + 42, + 139, + 254, + 56, + 0, + 103, + 137, + 138, + 0, + 0, + 50, + 9, + 40, + 100, + 136, + 255, + 165, + 137, + 138, + 2, + 0, + 177, + 36, + 178, + 16, + 34, + 178, + 1, + 41, + 100, + 178, + 17, + 39, + 4, + 100, + 178, + 18, + 42, + 100, + 178, + 20, + 139, + 255, + 192, + 28, + 178, + 21, + 179, + 137, + 138, + 0, + 0, + 177, + 35, + 178, + 16, + 34, + 178, + 1, + 50, + 9, + 178, + 7, + 50, + 9, + 178, + 9, + 34, + 178, + 8, + 179, + 137, + ], + "clearStateProgram": Uint8Array [ + 8, + 129, + 0, + 67, + ], + "creator": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "globalState": [ + { + "key": Uint8Array [ + 97, + 115, + 97, + ], + "value": { + "bytes": Uint8Array [], + "type": 2, + "uint": 705457144n, + }, + }, + { + "key": Uint8Array [ + 97, + 115, + 97, + 95, + 97, + 109, + 116, + ], + "value": { + "bytes": Uint8Array [], + "type": 2, + "uint": 1n, + }, + }, + { + "key": Uint8Array [ + 97, + 117, + 99, + 116, + 105, + 111, + 110, + 95, + 101, + 110, + 100, + ], + "value": { + "bytes": Uint8Array [], + "type": 2, + "uint": 1721928880n, + }, + }, + { + "key": Uint8Array [ + 104, + 105, + 103, + 104, + 101, + 115, + 116, + 95, + 98, + 105, + 100, + ], + "value": { + "bytes": Uint8Array [], + "type": 2, + "uint": 10000n, + }, + }, + { + "key": Uint8Array [ + 104, + 105, + 103, + 104, + 101, + 115, + 116, + 95, + 98, + 105, + 100, + 100, + 101, + 114, + ], + "value": { + "bytes": Uint8Array [], + "type": 1, + "uint": 0n, + }, + }, + ], + "globalStateSchema": { + "numByteSlice": 1, + "numUint": 4, + }, + "localStateSchema": { + "numByteSlice": 0, + "numUint": 0, + }, + }, + }, + { + "id": 708093293n, + "params": { + "approvalProgram": Uint8Array [ + 10, + 32, + 2, + 1, + 8, + 38, + 1, + 4, + 21, + 31, + 124, + 117, + 49, + 27, + 65, + 0, + 158, + 128, + 4, + 254, + 107, + 223, + 105, + 128, + 4, + 115, + 192, + 75, + 77, + 128, + 4, + 224, + 4, + 71, + 69, + 128, + 4, + 120, + 205, + 206, + 5, + 128, + 4, + 131, + 30, + 122, + 95, + 54, + 26, + 0, + 142, + 5, + 0, + 1, + 0, + 23, + 0, + 53, + 0, + 72, + 0, + 94, + 0, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 54, + 26, + 2, + 136, + 0, + 106, + 40, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 87, + 2, + 0, + 136, + 0, + 96, + 73, + 21, + 22, + 87, + 6, + 2, + 76, + 80, + 40, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 136, + 0, + 75, + 40, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 54, + 26, + 2, + 136, + 0, + 59, + 40, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 136, + 0, + 54, + 40, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 20, + 68, + 34, + 67, + 138, + 2, + 1, + 139, + 254, + 23, + 139, + 255, + 23, + 8, + 22, + 137, + 138, + 1, + 1, + 139, + 255, + 137, + 138, + 1, + 1, + 139, + 255, + 137, + 138, + 2, + 1, + 139, + 255, + 23, + 35, + 11, + 139, + 254, + 76, + 35, + 88, + 137, + 138, + 1, + 1, + 139, + 255, + 137, + ], + "clearStateProgram": Uint8Array [ + 10, + 129, + 1, + 67, + ], + "creator": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "globalStateSchema": { + "numByteSlice": 0, + "numUint": 0, + }, + "localStateSchema": { + "numByteSlice": 0, + "numUint": 0, + }, + }, + }, + { + "id": 709373991n, + "params": { + "approvalProgram": Uint8Array [ + 10, + 32, + 1, + 1, + 38, + 1, + 4, + 21, + 31, + 124, + 117, + 49, + 27, + 65, + 0, + 126, + 128, + 4, + 87, + 127, + 226, + 73, + 128, + 4, + 21, + 110, + 231, + 140, + 54, + 26, + 0, + 142, + 2, + 0, + 1, + 0, + 83, + 0, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 54, + 26, + 2, + 54, + 26, + 3, + 54, + 26, + 4, + 54, + 26, + 5, + 54, + 26, + 6, + 54, + 26, + 7, + 54, + 26, + 8, + 54, + 26, + 9, + 54, + 26, + 10, + 54, + 26, + 11, + 54, + 26, + 12, + 54, + 26, + 13, + 54, + 26, + 14, + 54, + 26, + 15, + 87, + 0, + 8, + 54, + 26, + 15, + 87, + 8, + 8, + 54, + 26, + 15, + 87, + 16, + 8, + 54, + 26, + 15, + 87, + 24, + 8, + 136, + 0, + 38, + 40, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 54, + 26, + 2, + 136, + 0, + 79, + 40, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 20, + 68, + 34, + 67, + 138, + 18, + 1, + 139, + 238, + 139, + 239, + 80, + 139, + 240, + 80, + 139, + 241, + 80, + 139, + 242, + 80, + 139, + 243, + 80, + 139, + 244, + 80, + 139, + 245, + 80, + 139, + 246, + 80, + 139, + 247, + 80, + 139, + 248, + 80, + 139, + 249, + 80, + 139, + 250, + 80, + 139, + 251, + 80, + 139, + 252, + 80, + 139, + 253, + 80, + 139, + 254, + 80, + 139, + 255, + 80, + 128, + 2, + 0, + 18, + 76, + 80, + 137, + 138, + 2, + 1, + 139, + 254, + 139, + 255, + 80, + 137, + ], + "clearStateProgram": Uint8Array [ + 10, + 129, + 1, + 67, + ], + "creator": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "globalStateSchema": { + "numByteSlice": 0, + "numUint": 0, + }, + "localStateSchema": { + "numByteSlice": 0, + "numUint": 0, + }, + }, + }, + { + "id": 709806536n, + "params": { + "approvalProgram": Uint8Array [ + 10, + 32, + 1, + 1, + 49, + 27, + 65, + 0, + 138, + 128, + 4, + 192, + 63, + 46, + 28, + 54, + 26, + 0, + 142, + 1, + 0, + 1, + 0, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 54, + 26, + 2, + 54, + 26, + 3, + 54, + 26, + 4, + 54, + 26, + 5, + 54, + 26, + 6, + 54, + 26, + 7, + 54, + 26, + 8, + 54, + 26, + 9, + 54, + 26, + 10, + 54, + 26, + 11, + 54, + 26, + 12, + 54, + 26, + 13, + 54, + 26, + 14, + 54, + 26, + 15, + 87, + 0, + 8, + 54, + 26, + 15, + 87, + 8, + 8, + 54, + 26, + 15, + 87, + 16, + 8, + 54, + 26, + 15, + 87, + 24, + 1, + 23, + 192, + 48, + 54, + 26, + 15, + 87, + 25, + 8, + 54, + 26, + 15, + 87, + 33, + 1, + 23, + 192, + 50, + 49, + 22, + 34, + 9, + 73, + 56, + 16, + 34, + 18, + 68, + 54, + 26, + 15, + 87, + 34, + 1, + 23, + 192, + 28, + 136, + 0, + 21, + 128, + 4, + 21, + 31, + 124, + 117, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 20, + 68, + 34, + 67, + 138, + 22, + 1, + 139, + 234, + 139, + 235, + 80, + 139, + 236, + 80, + 139, + 237, + 80, + 139, + 238, + 80, + 139, + 239, + 80, + 139, + 240, + 80, + 139, + 241, + 80, + 139, + 242, + 80, + 139, + 243, + 80, + 139, + 244, + 80, + 139, + 245, + 80, + 139, + 246, + 80, + 139, + 247, + 80, + 139, + 248, + 80, + 139, + 249, + 80, + 139, + 250, + 80, + 139, + 252, + 80, + 176, + 139, + 251, + 22, + 139, + 253, + 22, + 139, + 255, + 115, + 0, + 68, + 22, + 139, + 254, + 56, + 23, + 73, + 21, + 22, + 87, + 6, + 2, + 76, + 80, + 79, + 3, + 79, + 3, + 80, + 79, + 2, + 80, + 128, + 2, + 0, + 26, + 80, + 76, + 80, + 137, + ], + "clearStateProgram": Uint8Array [ + 10, + 129, + 1, + 67, + ], + "creator": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "globalStateSchema": { + "numByteSlice": 0, + "numUint": 0, + }, + "localStateSchema": { + "numByteSlice": 0, + "numUint": 0, + }, + }, + }, + { + "id": 709982020n, + "params": { + "approvalProgram": Uint8Array [ + 10, + 32, + 2, + 1, + 4, + 38, + 1, + 2, + 0, + 4, + 49, + 27, + 65, + 0, + 41, + 128, + 4, + 142, + 167, + 80, + 210, + 54, + 26, + 0, + 142, + 1, + 0, + 1, + 0, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 54, + 26, + 2, + 136, + 0, + 21, + 128, + 4, + 21, + 31, + 124, + 117, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 20, + 68, + 34, + 67, + 138, + 2, + 1, + 139, + 255, + 129, + 0, + 89, + 139, + 255, + 129, + 2, + 89, + 139, + 255, + 79, + 2, + 75, + 2, + 82, + 76, + 139, + 255, + 21, + 139, + 255, + 78, + 2, + 82, + 76, + 73, + 21, + 35, + 8, + 22, + 87, + 6, + 2, + 40, + 76, + 80, + 76, + 80, + 76, + 80, + 139, + 254, + 21, + 35, + 8, + 22, + 87, + 6, + 2, + 40, + 76, + 80, + 139, + 254, + 80, + 76, + 80, + 137, + ], + "clearStateProgram": Uint8Array [ + 10, + 129, + 1, + 67, + ], + "creator": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "globalStateSchema": { + "numByteSlice": 0, + "numUint": 0, + }, + "localStateSchema": { + "numByteSlice": 0, + "numUint": 0, + }, + }, + }, + { + "id": 713725461n, + "params": { + "approvalProgram": Uint8Array [ + 10, + 32, + 1, + 1, + 38, + 1, + 4, + 21, + 31, + 124, + 117, + 49, + 27, + 65, + 0, + 60, + 128, + 4, + 175, + 32, + 157, + 140, + 128, + 4, + 113, + 61, + 114, + 228, + 54, + 26, + 0, + 142, + 2, + 0, + 1, + 0, + 20, + 0, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 136, + 0, + 35, + 40, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 136, + 0, + 22, + 40, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 20, + 68, + 34, + 67, + 138, + 1, + 1, + 139, + 255, + 137, + 138, + 1, + 1, + 139, + 255, + 137, + ], + "clearStateProgram": Uint8Array [ + 10, + 129, + 1, + 67, + ], + "creator": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "globalStateSchema": { + "numByteSlice": 0, + "numUint": 0, + }, + "localStateSchema": { + "numByteSlice": 0, + "numUint": 0, + }, + }, + }, + { + "id": 716754254n, + "params": { + "approvalProgram": Uint8Array [ + 10, + 32, + 2, + 1, + 4, + 38, + 1, + 2, + 0, + 4, + 49, + 27, + 65, + 0, + 41, + 128, + 4, + 142, + 167, + 80, + 210, + 54, + 26, + 0, + 142, + 1, + 0, + 1, + 0, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 54, + 26, + 2, + 136, + 0, + 21, + 128, + 4, + 21, + 31, + 124, + 117, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 20, + 68, + 34, + 67, + 138, + 2, + 1, + 139, + 255, + 129, + 0, + 89, + 139, + 255, + 129, + 2, + 89, + 139, + 255, + 79, + 2, + 75, + 2, + 82, + 76, + 139, + 255, + 21, + 139, + 255, + 78, + 2, + 82, + 76, + 73, + 21, + 35, + 8, + 22, + 87, + 6, + 2, + 40, + 76, + 80, + 76, + 80, + 76, + 80, + 139, + 254, + 21, + 35, + 8, + 22, + 87, + 6, + 2, + 40, + 76, + 80, + 139, + 254, + 80, + 76, + 80, + 137, + ], + "clearStateProgram": Uint8Array [ + 10, + 129, + 1, + 67, + ], + "creator": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "globalStateSchema": { + "numByteSlice": 0, + "numUint": 0, + }, + "localStateSchema": { + "numByteSlice": 0, + "numUint": 0, + }, + }, + }, + { + "id": 717891588n, + "params": { + "approvalProgram": Uint8Array [ + 10, + 32, + 3, + 0, + 1, + 4, + 38, + 6, + 11, + 97, + 117, + 99, + 116, + 105, + 111, + 110, + 95, + 101, + 110, + 100, + 12, + 112, + 114, + 101, + 118, + 105, + 111, + 117, + 115, + 95, + 98, + 105, + 100, + 15, + 112, + 114, + 101, + 118, + 105, + 111, + 117, + 115, + 95, + 98, + 105, + 100, + 100, + 101, + 114, + 3, + 97, + 115, + 97, + 10, + 97, + 115, + 97, + 95, + 97, + 109, + 111, + 117, + 110, + 116, + 5, + 99, + 108, + 97, + 105, + 109, + 49, + 24, + 64, + 0, + 3, + 136, + 1, + 163, + 49, + 27, + 65, + 0, + 166, + 128, + 4, + 40, + 38, + 178, + 2, + 128, + 4, + 240, + 170, + 112, + 35, + 128, + 4, + 48, + 198, + 213, + 138, + 128, + 4, + 219, + 127, + 232, + 67, + 128, + 4, + 230, + 84, + 98, + 91, + 128, + 4, + 30, + 193, + 43, + 239, + 54, + 26, + 0, + 142, + 6, + 0, + 1, + 0, + 19, + 0, + 49, + 0, + 61, + 0, + 83, + 0, + 95, + 0, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 23, + 192, + 48, + 136, + 0, + 106, + 35, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 23, + 54, + 26, + 2, + 23, + 49, + 22, + 35, + 9, + 73, + 56, + 16, + 36, + 18, + 68, + 136, + 0, + 112, + 35, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 136, + 0, + 144, + 35, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 49, + 22, + 35, + 9, + 73, + 56, + 16, + 35, + 18, + 68, + 136, + 0, + 126, + 35, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 136, + 0, + 162, + 35, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 23, + 192, + 48, + 136, + 0, + 207, + 35, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 20, + 68, + 35, + 67, + 138, + 1, + 0, + 49, + 0, + 50, + 9, + 18, + 68, + 34, + 43, + 101, + 68, + 20, + 68, + 43, + 139, + 255, + 103, + 177, + 50, + 10, + 139, + 255, + 178, + 17, + 178, + 20, + 36, + 178, + 16, + 34, + 178, + 1, + 179, + 137, + 138, + 3, + 0, + 49, + 0, + 50, + 9, + 18, + 68, + 34, + 40, + 101, + 68, + 20, + 68, + 139, + 255, + 56, + 20, + 50, + 10, + 18, + 68, + 139, + 255, + 56, + 18, + 39, + 4, + 76, + 103, + 50, + 7, + 139, + 254, + 8, + 40, + 76, + 103, + 41, + 139, + 253, + 103, + 137, + 138, + 0, + 0, + 137, + 138, + 1, + 0, + 50, + 7, + 34, + 40, + 101, + 68, + 12, + 68, + 139, + 255, + 56, + 0, + 73, + 49, + 0, + 18, + 68, + 139, + 255, + 56, + 8, + 34, + 41, + 101, + 68, + 75, + 1, + 12, + 68, + 41, + 75, + 1, + 103, + 42, + 79, + 2, + 103, + 49, + 0, + 39, + 5, + 79, + 2, + 102, + 137, + 138, + 0, + 0, + 49, + 0, + 34, + 39, + 5, + 99, + 76, + 73, + 79, + 2, + 68, + 49, + 0, + 34, + 42, + 101, + 68, + 18, + 65, + 0, + 10, + 34, + 41, + 101, + 68, + 139, + 0, + 76, + 9, + 140, + 1, + 177, + 49, + 0, + 178, + 7, + 139, + 1, + 73, + 178, + 8, + 35, + 178, + 16, + 34, + 178, + 1, + 179, + 49, + 0, + 139, + 0, + 79, + 2, + 9, + 39, + 5, + 76, + 102, + 137, + 138, + 1, + 0, + 50, + 7, + 34, + 40, + 101, + 68, + 13, + 68, + 177, + 34, + 42, + 101, + 68, + 34, + 42, + 101, + 68, + 34, + 39, + 4, + 101, + 68, + 178, + 18, + 178, + 20, + 178, + 21, + 139, + 255, + 178, + 17, + 36, + 178, + 16, + 34, + 178, + 1, + 179, + 137, + 138, + 0, + 0, + 40, + 34, + 103, + 41, + 34, + 103, + 39, + 4, + 34, + 103, + 43, + 34, + 103, + 42, + 50, + 3, + 103, + 137, + ], + "clearStateProgram": Uint8Array [ + 10, + 129, + 1, + 67, + ], + "creator": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "globalState": [ + { + "key": Uint8Array [ + 97, + 117, + 99, + 116, + 105, + 111, + 110, + 95, + 101, + 110, + 100, + ], + "value": { + "bytes": Uint8Array [], + "type": 2, + "uint": 0n, + }, + }, + { + "key": Uint8Array [ + 112, + 114, + 101, + 118, + 105, + 111, + 117, + 115, + 95, + 98, + 105, + 100, + ], + "value": { + "bytes": Uint8Array [], + "type": 2, + "uint": 0n, + }, + }, + { + "key": Uint8Array [ + 97, + 115, + 97, + ], + "value": { + "bytes": Uint8Array [], + "type": 2, + "uint": 0n, + }, + }, + { + "key": Uint8Array [ + 112, + 114, + 101, + 118, + 105, + 111, + 117, + 115, + 95, + 98, + 105, + 100, + 100, + 101, + 114, + ], + "value": { + "bytes": Uint8Array [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": 1, + "uint": 0n, + }, + }, + { + "key": Uint8Array [ + 97, + 115, + 97, + 95, + 97, + 109, + 111, + 117, + 110, + 116, + ], + "value": { + "bytes": Uint8Array [], + "type": 2, + "uint": 0n, + }, + }, + ], + "globalStateSchema": { + "numByteSlice": 1, + "numUint": 4, + }, + "localStateSchema": { + "numByteSlice": 0, + "numUint": 1, + }, + }, + }, + { + "id": 717893078n, + "params": { + "approvalProgram": Uint8Array [ + 10, + 32, + 3, + 0, + 1, + 4, + 38, + 6, + 11, + 97, + 117, + 99, + 116, + 105, + 111, + 110, + 95, + 101, + 110, + 100, + 12, + 112, + 114, + 101, + 118, + 105, + 111, + 117, + 115, + 95, + 98, + 105, + 100, + 15, + 112, + 114, + 101, + 118, + 105, + 111, + 117, + 115, + 95, + 98, + 105, + 100, + 100, + 101, + 114, + 3, + 97, + 115, + 97, + 10, + 97, + 115, + 97, + 95, + 97, + 109, + 111, + 117, + 110, + 116, + 5, + 99, + 108, + 97, + 105, + 109, + 49, + 24, + 64, + 0, + 3, + 136, + 1, + 163, + 49, + 27, + 65, + 0, + 166, + 128, + 4, + 40, + 38, + 178, + 2, + 128, + 4, + 240, + 170, + 112, + 35, + 128, + 4, + 48, + 198, + 213, + 138, + 128, + 4, + 219, + 127, + 232, + 67, + 128, + 4, + 230, + 84, + 98, + 91, + 128, + 4, + 30, + 193, + 43, + 239, + 54, + 26, + 0, + 142, + 6, + 0, + 1, + 0, + 19, + 0, + 49, + 0, + 61, + 0, + 83, + 0, + 95, + 0, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 23, + 192, + 48, + 136, + 0, + 106, + 35, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 23, + 54, + 26, + 2, + 23, + 49, + 22, + 35, + 9, + 73, + 56, + 16, + 36, + 18, + 68, + 136, + 0, + 112, + 35, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 136, + 0, + 144, + 35, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 49, + 22, + 35, + 9, + 73, + 56, + 16, + 35, + 18, + 68, + 136, + 0, + 126, + 35, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 136, + 0, + 162, + 35, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 23, + 192, + 48, + 136, + 0, + 207, + 35, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 20, + 68, + 35, + 67, + 138, + 1, + 0, + 49, + 0, + 50, + 9, + 18, + 68, + 34, + 43, + 101, + 68, + 20, + 68, + 43, + 139, + 255, + 103, + 177, + 50, + 10, + 139, + 255, + 178, + 17, + 178, + 20, + 36, + 178, + 16, + 34, + 178, + 1, + 179, + 137, + 138, + 3, + 0, + 49, + 0, + 50, + 9, + 18, + 68, + 34, + 40, + 101, + 68, + 20, + 68, + 139, + 255, + 56, + 20, + 50, + 10, + 18, + 68, + 139, + 255, + 56, + 18, + 39, + 4, + 76, + 103, + 50, + 7, + 139, + 254, + 8, + 40, + 76, + 103, + 41, + 139, + 253, + 103, + 137, + 138, + 0, + 0, + 137, + 138, + 1, + 0, + 50, + 7, + 34, + 40, + 101, + 68, + 12, + 68, + 139, + 255, + 56, + 0, + 73, + 49, + 0, + 18, + 68, + 139, + 255, + 56, + 8, + 34, + 41, + 101, + 68, + 75, + 1, + 12, + 68, + 41, + 75, + 1, + 103, + 42, + 79, + 2, + 103, + 49, + 0, + 39, + 5, + 79, + 2, + 102, + 137, + 138, + 0, + 0, + 49, + 0, + 34, + 39, + 5, + 99, + 76, + 73, + 79, + 2, + 68, + 49, + 0, + 34, + 42, + 101, + 68, + 18, + 65, + 0, + 10, + 34, + 41, + 101, + 68, + 139, + 0, + 76, + 9, + 140, + 1, + 177, + 49, + 0, + 178, + 7, + 139, + 1, + 73, + 178, + 8, + 35, + 178, + 16, + 34, + 178, + 1, + 179, + 49, + 0, + 139, + 0, + 79, + 2, + 9, + 39, + 5, + 76, + 102, + 137, + 138, + 1, + 0, + 50, + 7, + 34, + 40, + 101, + 68, + 13, + 68, + 177, + 34, + 42, + 101, + 68, + 34, + 42, + 101, + 68, + 34, + 39, + 4, + 101, + 68, + 178, + 18, + 178, + 20, + 178, + 21, + 139, + 255, + 178, + 17, + 36, + 178, + 16, + 34, + 178, + 1, + 179, + 137, + 138, + 0, + 0, + 40, + 34, + 103, + 41, + 34, + 103, + 39, + 4, + 34, + 103, + 43, + 34, + 103, + 42, + 50, + 3, + 103, + 137, + ], + "clearStateProgram": Uint8Array [ + 10, + 129, + 1, + 67, + ], + "creator": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "globalState": [ + { + "key": Uint8Array [ + 97, + 115, + 97, + 95, + 97, + 109, + 111, + 117, + 110, + 116, + ], + "value": { + "bytes": Uint8Array [], + "type": 2, + "uint": 0n, + }, + }, + { + "key": Uint8Array [ + 97, + 117, + 99, + 116, + 105, + 111, + 110, + 95, + 101, + 110, + 100, + ], + "value": { + "bytes": Uint8Array [], + "type": 2, + "uint": 0n, + }, + }, + { + "key": Uint8Array [ + 112, + 114, + 101, + 118, + 105, + 111, + 117, + 115, + 95, + 98, + 105, + 100, + ], + "value": { + "bytes": Uint8Array [], + "type": 2, + "uint": 0n, + }, + }, + { + "key": Uint8Array [ + 97, + 115, + 97, + ], + "value": { + "bytes": Uint8Array [], + "type": 2, + "uint": 0n, + }, + }, + { + "key": Uint8Array [ + 112, + 114, + 101, + 118, + 105, + 111, + 117, + 115, + 95, + 98, + 105, + 100, + 100, + 101, + 114, + ], + "value": { + "bytes": Uint8Array [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": 1, + "uint": 0n, + }, + }, + ], + "globalStateSchema": { + "numByteSlice": 1, + "numUint": 4, + }, + "localStateSchema": { + "numByteSlice": 0, + "numUint": 1, + }, + }, + }, + { + "id": 718129252n, + "params": { + "approvalProgram": Uint8Array [ + 10, + 32, + 3, + 0, + 1, + 4, + 38, + 6, + 11, + 97, + 117, + 99, + 116, + 105, + 111, + 110, + 95, + 101, + 110, + 100, + 12, + 112, + 114, + 101, + 118, + 105, + 111, + 117, + 115, + 95, + 98, + 105, + 100, + 15, + 112, + 114, + 101, + 118, + 105, + 111, + 117, + 115, + 95, + 98, + 105, + 100, + 100, + 101, + 114, + 3, + 97, + 115, + 97, + 10, + 97, + 115, + 97, + 95, + 97, + 109, + 111, + 117, + 110, + 116, + 5, + 99, + 108, + 97, + 105, + 109, + 49, + 24, + 64, + 0, + 3, + 136, + 1, + 163, + 49, + 27, + 65, + 0, + 166, + 128, + 4, + 40, + 38, + 178, + 2, + 128, + 4, + 240, + 170, + 112, + 35, + 128, + 4, + 48, + 198, + 213, + 138, + 128, + 4, + 219, + 127, + 232, + 67, + 128, + 4, + 230, + 84, + 98, + 91, + 128, + 4, + 30, + 193, + 43, + 239, + 54, + 26, + 0, + 142, + 6, + 0, + 1, + 0, + 19, + 0, + 49, + 0, + 61, + 0, + 83, + 0, + 95, + 0, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 23, + 192, + 48, + 136, + 0, + 106, + 35, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 23, + 54, + 26, + 2, + 23, + 49, + 22, + 35, + 9, + 73, + 56, + 16, + 36, + 18, + 68, + 136, + 0, + 112, + 35, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 136, + 0, + 144, + 35, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 49, + 22, + 35, + 9, + 73, + 56, + 16, + 35, + 18, + 68, + 136, + 0, + 126, + 35, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 136, + 0, + 162, + 35, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 23, + 192, + 48, + 136, + 0, + 207, + 35, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 20, + 68, + 35, + 67, + 138, + 1, + 0, + 49, + 0, + 50, + 9, + 18, + 68, + 34, + 43, + 101, + 68, + 20, + 68, + 43, + 139, + 255, + 103, + 177, + 50, + 10, + 139, + 255, + 178, + 17, + 178, + 20, + 36, + 178, + 16, + 34, + 178, + 1, + 179, + 137, + 138, + 3, + 0, + 49, + 0, + 50, + 9, + 18, + 68, + 34, + 40, + 101, + 68, + 20, + 68, + 139, + 255, + 56, + 20, + 50, + 10, + 18, + 68, + 139, + 255, + 56, + 18, + 39, + 4, + 76, + 103, + 50, + 7, + 139, + 254, + 8, + 40, + 76, + 103, + 41, + 139, + 253, + 103, + 137, + 138, + 0, + 0, + 137, + 138, + 1, + 0, + 50, + 7, + 34, + 40, + 101, + 68, + 12, + 68, + 139, + 255, + 56, + 0, + 73, + 49, + 0, + 18, + 68, + 139, + 255, + 56, + 8, + 34, + 41, + 101, + 68, + 75, + 1, + 12, + 68, + 41, + 75, + 1, + 103, + 42, + 79, + 2, + 103, + 49, + 0, + 39, + 5, + 79, + 2, + 102, + 137, + 138, + 0, + 0, + 49, + 0, + 34, + 39, + 5, + 99, + 76, + 73, + 79, + 2, + 68, + 49, + 0, + 34, + 42, + 101, + 68, + 18, + 65, + 0, + 10, + 34, + 41, + 101, + 68, + 139, + 0, + 76, + 9, + 140, + 1, + 177, + 49, + 0, + 178, + 7, + 139, + 1, + 73, + 178, + 8, + 35, + 178, + 16, + 34, + 178, + 1, + 179, + 49, + 0, + 139, + 0, + 79, + 2, + 9, + 39, + 5, + 76, + 102, + 137, + 138, + 1, + 0, + 50, + 7, + 34, + 40, + 101, + 68, + 13, + 68, + 177, + 34, + 42, + 101, + 68, + 34, + 42, + 101, + 68, + 34, + 39, + 4, + 101, + 68, + 178, + 18, + 178, + 20, + 178, + 21, + 139, + 255, + 178, + 17, + 36, + 178, + 16, + 34, + 178, + 1, + 179, + 137, + 138, + 0, + 0, + 40, + 34, + 103, + 41, + 34, + 103, + 39, + 4, + 34, + 103, + 43, + 34, + 103, + 42, + 50, + 3, + 103, + 137, + ], + "clearStateProgram": Uint8Array [ + 10, + 129, + 1, + 67, + ], + "creator": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "globalState": [ + { + "key": Uint8Array [ + 97, + 115, + 97, + 95, + 97, + 109, + 111, + 117, + 110, + 116, + ], + "value": { + "bytes": Uint8Array [], + "type": 2, + "uint": 0n, + }, + }, + { + "key": Uint8Array [ + 97, + 117, + 99, + 116, + 105, + 111, + 110, + 95, + 101, + 110, + 100, + ], + "value": { + "bytes": Uint8Array [], + "type": 2, + "uint": 0n, + }, + }, + { + "key": Uint8Array [ + 112, + 114, + 101, + 118, + 105, + 111, + 117, + 115, + 95, + 98, + 105, + 100, + ], + "value": { + "bytes": Uint8Array [], + "type": 2, + "uint": 0n, + }, + }, + { + "key": Uint8Array [ + 97, + 115, + 97, + ], + "value": { + "bytes": Uint8Array [], + "type": 2, + "uint": 0n, + }, + }, + { + "key": Uint8Array [ + 112, + 114, + 101, + 118, + 105, + 111, + 117, + 115, + 95, + 98, + 105, + 100, + 100, + 101, + 114, + ], + "value": { + "bytes": Uint8Array [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": 1, + "uint": 0n, + }, + }, + ], + "globalStateSchema": { + "numByteSlice": 1, + "numUint": 4, + }, + "localStateSchema": { + "numByteSlice": 0, + "numUint": 1, + }, + }, + }, + { + "id": 718348254n, + "params": { + "approvalProgram": Uint8Array [ + 10, + 32, + 1, + 1, + 49, + 27, + 65, + 0, + 38, + 128, + 4, + 165, + 62, + 90, + 65, + 54, + 26, + 0, + 142, + 1, + 0, + 1, + 0, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 136, + 0, + 21, + 128, + 4, + 21, + 31, + 124, + 117, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 20, + 68, + 34, + 67, + 138, + 1, + 1, + 139, + 255, + 137, + ], + "clearStateProgram": Uint8Array [ + 10, + 129, + 1, + 67, + ], + "creator": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "globalStateSchema": { + "numByteSlice": 0, + "numUint": 0, + }, + "localStateSchema": { + "numByteSlice": 0, + "numUint": 0, + }, + }, + }, + { + "id": 719046155n, + "params": { + "approvalProgram": Uint8Array [ + 10, + 32, + 1, + 1, + 38, + 1, + 4, + 21, + 31, + 124, + 117, + 49, + 24, + 64, + 0, + 3, + 136, + 0, + 210, + 49, + 27, + 65, + 0, + 140, + 128, + 4, + 49, + 226, + 229, + 96, + 128, + 4, + 143, + 140, + 47, + 113, + 128, + 4, + 223, + 95, + 163, + 143, + 128, + 4, + 241, + 167, + 125, + 22, + 128, + 4, + 172, + 157, + 156, + 23, + 54, + 26, + 0, + 142, + 5, + 0, + 1, + 0, + 17, + 0, + 36, + 0, + 55, + 0, + 76, + 0, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 136, + 0, + 94, + 40, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 136, + 0, + 89, + 40, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 136, + 0, + 76, + 40, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 23, + 192, + 28, + 54, + 26, + 2, + 136, + 0, + 57, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 136, + 0, + 65, + 40, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 20, + 68, + 34, + 67, + 138, + 0, + 1, + 128, + 8, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 3, + 137, + 138, + 1, + 1, + 139, + 255, + 137, + 138, + 1, + 1, + 139, + 255, + 137, + 138, + 2, + 0, + 139, + 255, + 23, + 139, + 254, + 128, + 9, + 108, + 111, + 99, + 97, + 108, + 95, + 105, + 110, + 116, + 79, + 2, + 102, + 137, + 138, + 1, + 1, + 139, + 255, + 137, + 138, + 0, + 0, + 128, + 10, + 103, + 108, + 111, + 98, + 97, + 108, + 95, + 105, + 110, + 116, + 129, + 42, + 103, + 137, + ], + "clearStateProgram": Uint8Array [ + 10, + 129, + 1, + 67, + ], + "creator": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "globalState": [ + { + "key": Uint8Array [ + 103, + 108, + 111, + 98, + 97, + 108, + 95, + 105, + 110, + 116, + ], + "value": { + "bytes": Uint8Array [], + "type": 2, + "uint": 42n, + }, + }, + ], + "globalStateSchema": { + "numByteSlice": 0, + "numUint": 1, + }, + "localStateSchema": { + "numByteSlice": 0, + "numUint": 1, + }, + }, + }, + { + "id": 719241638n, + "params": { + "approvalProgram": Uint8Array [ + 10, + 32, + 1, + 1, + 49, + 27, + 65, + 0, + 35, + 128, + 4, + 111, + 227, + 46, + 135, + 54, + 26, + 0, + 142, + 1, + 0, + 1, + 0, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 136, + 0, + 21, + 128, + 4, + 21, + 31, + 124, + 117, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 20, + 68, + 34, + 67, + 138, + 0, + 1, + 128, + 3, + 49, + 50, + 51, + 73, + 21, + 22, + 87, + 6, + 2, + 76, + 80, + 137, + ], + "clearStateProgram": Uint8Array [ + 10, + 129, + 1, + 67, + ], + "creator": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "globalStateSchema": { + "numByteSlice": 0, + "numUint": 0, + }, + "localStateSchema": { + "numByteSlice": 0, + "numUint": 0, + }, + }, + }, + { + "id": 719253364n, + "params": { + "approvalProgram": Uint8Array [ + 10, + 32, + 1, + 1, + 38, + 1, + 4, + 21, + 31, + 124, + 117, + 49, + 27, + 65, + 0, + 95, + 128, + 4, + 65, + 217, + 223, + 225, + 128, + 4, + 47, + 202, + 221, + 246, + 128, + 4, + 156, + 189, + 61, + 61, + 54, + 26, + 0, + 142, + 3, + 0, + 1, + 0, + 25, + 0, + 49, + 0, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 136, + 0, + 65, + 73, + 21, + 22, + 87, + 6, + 2, + 76, + 80, + 40, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 136, + 0, + 50, + 73, + 21, + 22, + 87, + 6, + 2, + 76, + 80, + 40, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 136, + 0, + 36, + 22, + 40, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 20, + 68, + 34, + 67, + 138, + 0, + 1, + 128, + 3, + 97, + 115, + 100, + 137, + 138, + 0, + 1, + 128, + 4, + 65, + 66, + 67, + 68, + 137, + 138, + 0, + 1, + 34, + 137, + ], + "clearStateProgram": Uint8Array [ + 10, + 129, + 1, + 67, + ], + "creator": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "globalStateSchema": { + "numByteSlice": 0, + "numUint": 0, + }, + "localStateSchema": { + "numByteSlice": 0, + "numUint": 0, + }, + }, + }, + { + "id": 719254146n, + "params": { + "approvalProgram": Uint8Array [ + 10, + 32, + 1, + 1, + 38, + 1, + 4, + 21, + 31, + 124, + 117, + 49, + 27, + 65, + 0, + 95, + 128, + 4, + 65, + 217, + 223, + 225, + 128, + 4, + 47, + 202, + 221, + 246, + 128, + 4, + 156, + 189, + 61, + 61, + 54, + 26, + 0, + 142, + 3, + 0, + 1, + 0, + 25, + 0, + 49, + 0, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 136, + 0, + 65, + 73, + 21, + 22, + 87, + 6, + 2, + 76, + 80, + 40, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 136, + 0, + 51, + 73, + 21, + 22, + 87, + 6, + 2, + 76, + 80, + 40, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 136, + 0, + 41, + 22, + 40, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 20, + 68, + 34, + 67, + 138, + 0, + 1, + 128, + 4, + 116, + 101, + 115, + 116, + 137, + 138, + 0, + 1, + 128, + 8, + 65, + 81, + 73, + 68, + 66, + 65, + 61, + 61, + 137, + 138, + 0, + 1, + 129, + 51, + 137, + ], + "clearStateProgram": Uint8Array [ + 10, + 129, + 1, + 67, + ], + "creator": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "globalStateSchema": { + "numByteSlice": 0, + "numUint": 0, + }, + "localStateSchema": { + "numByteSlice": 0, + "numUint": 0, + }, + }, + }, + { + "id": 720689424n, + "params": { + "approvalProgram": Uint8Array [ + 10, + 32, + 1, + 1, + 49, + 27, + 65, + 0, + 38, + 128, + 4, + 65, + 110, + 127, + 202, + 54, + 26, + 0, + 142, + 1, + 0, + 1, + 0, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 136, + 0, + 21, + 128, + 4, + 21, + 31, + 124, + 117, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 20, + 68, + 34, + 67, + 138, + 1, + 1, + 139, + 255, + 129, + 0, + 89, + 139, + 255, + 129, + 10, + 89, + 139, + 255, + 78, + 2, + 82, + 137, + ], + "clearStateProgram": Uint8Array [ + 10, + 129, + 1, + 67, + ], + "creator": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "globalStateSchema": { + "numByteSlice": 0, + "numUint": 0, + }, + "localStateSchema": { + "numByteSlice": 0, + "numUint": 0, + }, + }, + }, + { + "id": 721104877n, + "params": { + "approvalProgram": Uint8Array [ + 10, + 32, + 1, + 1, + 49, + 27, + 65, + 0, + 53, + 128, + 4, + 35, + 168, + 2, + 60, + 54, + 26, + 0, + 142, + 1, + 0, + 1, + 0, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 23, + 192, + 48, + 54, + 26, + 2, + 23, + 192, + 50, + 54, + 26, + 3, + 23, + 192, + 28, + 136, + 0, + 21, + 128, + 4, + 21, + 31, + 124, + 117, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 20, + 68, + 34, + 67, + 138, + 3, + 1, + 139, + 253, + 22, + 139, + 254, + 22, + 80, + 137, + ], + "clearStateProgram": Uint8Array [ + 10, + 129, + 1, + 67, + ], + "creator": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "globalStateSchema": { + "numByteSlice": 0, + "numUint": 0, + }, + "localStateSchema": { + "numByteSlice": 0, + "numUint": 0, + }, + }, + }, + { + "id": 729762198n, + "params": { + "approvalProgram": Uint8Array [ + 10, + 32, + 4, + 1, + 0, + 10, + 123, + 38, + 4, + 4, + 21, + 31, + 124, + 117, + 7, + 0, + 3, + 255, + 0, + 2, + 72, + 105, + 5, + 72, + 101, + 108, + 108, + 111, + 1, + 255, + 136, + 0, + 1, + 67, + 138, + 0, + 1, + 49, + 27, + 65, + 0, + 210, + 130, + 7, + 4, + 76, + 92, + 97, + 186, + 4, + 151, + 232, + 228, + 167, + 4, + 118, + 196, + 222, + 17, + 4, + 193, + 202, + 119, + 9, + 4, + 109, + 231, + 98, + 194, + 4, + 89, + 252, + 82, + 130, + 4, + 157, + 158, + 236, + 176, + 54, + 26, + 0, + 142, + 7, + 0, + 2, + 0, + 12, + 0, + 35, + 0, + 54, + 0, + 69, + 0, + 81, + 0, + 98, + 35, + 137, + 34, + 49, + 25, + 144, + 129, + 3, + 26, + 68, + 34, + 137, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 54, + 26, + 2, + 136, + 0, + 154, + 22, + 40, + 76, + 80, + 176, + 34, + 137, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 136, + 0, + 156, + 40, + 76, + 80, + 176, + 34, + 137, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 136, + 0, + 169, + 34, + 137, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 136, + 0, + 171, + 34, + 137, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 35, + 83, + 136, + 0, + 211, + 34, + 137, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 136, + 0, + 247, + 79, + 2, + 22, + 75, + 2, + 21, + 22, + 87, + 6, + 2, + 79, + 3, + 80, + 75, + 3, + 21, + 129, + 13, + 8, + 128, + 2, + 0, + 13, + 79, + 3, + 80, + 76, + 22, + 87, + 6, + 2, + 80, + 79, + 2, + 80, + 79, + 2, + 80, + 76, + 80, + 40, + 76, + 80, + 176, + 34, + 137, + 49, + 25, + 141, + 6, + 0, + 2, + 0, + 2, + 0, + 10, + 0, + 10, + 0, + 10, + 0, + 4, + 35, + 137, + 34, + 137, + 49, + 24, + 20, + 68, + 34, + 137, + 35, + 137, + 138, + 2, + 1, + 139, + 254, + 36, + 89, + 139, + 254, + 21, + 139, + 254, + 78, + 2, + 82, + 139, + 255, + 18, + 68, + 129, + 42, + 137, + 138, + 1, + 1, + 139, + 255, + 36, + 89, + 139, + 255, + 21, + 139, + 255, + 78, + 2, + 82, + 73, + 136, + 0, + 6, + 72, + 75, + 1, + 18, + 68, + 137, + 138, + 1, + 2, + 139, + 255, + 73, + 137, + 138, + 1, + 0, + 139, + 255, + 87, + 0, + 8, + 128, + 1, + 0, + 18, + 68, + 137, + 138, + 0, + 0, + 130, + 2, + 4, + 217, + 63, + 55, + 78, + 11, + 0, + 3, + 42, + 0, + 6, + 104, + 101, + 108, + 108, + 111, + 49, + 80, + 176, + 130, + 2, + 4, + 30, + 114, + 175, + 78, + 22, + 0, + 4, + 0, + 11, + 0, + 5, + 104, + 101, + 108, + 108, + 111, + 0, + 3, + 42, + 0, + 6, + 104, + 101, + 108, + 108, + 111, + 50, + 80, + 176, + 137, + 138, + 1, + 0, + 139, + 255, + 65, + 0, + 39, + 130, + 2, + 4, + 17, + 197, + 71, + 186, + 29, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 42, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 43, + 0, + 18, + 0, + 3, + 42, + 0, + 6, + 104, + 101, + 108, + 108, + 111, + 51, + 80, + 176, + 137, + 138, + 0, + 4, + 41, + 37, + 42, + 43, + 137, + ], + "clearStateProgram": Uint8Array [ + 10, + 129, + 1, + 67, + ], + "creator": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "globalStateSchema": { + "numByteSlice": 2, + "numUint": 1, + }, + "localStateSchema": { + "numByteSlice": 2, + "numUint": 1, + }, + }, + }, + { + "id": 732773208n, + "params": { + "approvalProgram": Uint8Array [ + 10, + 32, + 3, + 1, + 2, + 4, + 38, + 2, + 4, + 21, + 31, + 124, + 117, + 2, + 0, + 4, + 49, + 27, + 65, + 1, + 85, + 128, + 4, + 254, + 107, + 223, + 105, + 128, + 4, + 159, + 216, + 53, + 248, + 128, + 4, + 234, + 69, + 19, + 211, + 128, + 4, + 239, + 52, + 99, + 188, + 128, + 4, + 22, + 138, + 253, + 186, + 128, + 4, + 142, + 167, + 80, + 210, + 128, + 4, + 113, + 61, + 114, + 228, + 128, + 4, + 14, + 24, + 152, + 125, + 128, + 4, + 250, + 39, + 231, + 65, + 128, + 4, + 254, + 243, + 147, + 86, + 128, + 4, + 95, + 31, + 151, + 19, + 54, + 26, + 0, + 142, + 11, + 0, + 1, + 0, + 23, + 0, + 49, + 0, + 79, + 0, + 98, + 0, + 117, + 0, + 139, + 0, + 158, + 0, + 173, + 0, + 210, + 0, + 229, + 0, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 54, + 26, + 2, + 136, + 0, + 241, + 40, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 49, + 22, + 34, + 9, + 73, + 56, + 16, + 34, + 18, + 68, + 136, + 0, + 227, + 40, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 87, + 2, + 0, + 136, + 0, + 214, + 73, + 21, + 22, + 87, + 6, + 2, + 76, + 80, + 40, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 136, + 0, + 193, + 40, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 136, + 0, + 180, + 40, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 54, + 26, + 2, + 136, + 0, + 164, + 40, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 136, + 0, + 207, + 40, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 136, + 0, + 194, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 49, + 22, + 35, + 9, + 73, + 56, + 16, + 34, + 18, + 68, + 49, + 22, + 34, + 9, + 73, + 56, + 16, + 129, + 6, + 18, + 68, + 136, + 0, + 188, + 40, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 136, + 0, + 185, + 40, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 136, + 0, + 172, + 40, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 20, + 68, + 34, + 67, + 138, + 2, + 1, + 139, + 254, + 23, + 139, + 255, + 23, + 8, + 22, + 137, + 138, + 1, + 1, + 139, + 255, + 56, + 8, + 22, + 137, + 138, + 1, + 1, + 139, + 255, + 137, + 138, + 1, + 1, + 139, + 255, + 137, + 138, + 1, + 1, + 139, + 255, + 137, + 138, + 2, + 1, + 139, + 255, + 129, + 0, + 89, + 139, + 255, + 35, + 89, + 139, + 255, + 79, + 2, + 75, + 2, + 82, + 76, + 139, + 255, + 21, + 139, + 255, + 78, + 2, + 82, + 76, + 73, + 21, + 36, + 8, + 22, + 87, + 6, + 2, + 41, + 76, + 80, + 76, + 80, + 76, + 80, + 139, + 254, + 21, + 36, + 8, + 22, + 87, + 6, + 2, + 41, + 76, + 80, + 139, + 254, + 80, + 76, + 80, + 137, + 138, + 1, + 1, + 139, + 255, + 137, + 138, + 1, + 0, + 128, + 18, + 103, + 108, + 111, + 98, + 97, + 108, + 95, + 115, + 116, + 97, + 116, + 105, + 99, + 95, + 105, + 110, + 116, + 115, + 139, + 255, + 103, + 137, + 138, + 2, + 1, + 139, + 255, + 56, + 23, + 73, + 21, + 22, + 87, + 6, + 2, + 76, + 80, + 137, + 138, + 1, + 1, + 139, + 255, + 137, + 138, + 1, + 1, + 139, + 255, + 87, + 0, + 16, + 73, + 87, + 0, + 8, + 23, + 76, + 87, + 8, + 8, + 23, + 8, + 22, + 139, + 255, + 87, + 16, + 16, + 73, + 87, + 0, + 8, + 23, + 76, + 87, + 8, + 8, + 23, + 9, + 22, + 80, + 137, + ], + "clearStateProgram": Uint8Array [ + 10, + 129, + 1, + 67, + ], + "creator": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "globalStateSchema": { + "numByteSlice": 1, + "numUint": 0, + }, + "localStateSchema": { + "numByteSlice": 0, + "numUint": 0, + }, + }, + }, + { + "id": 733078310n, + "params": { + "approvalProgram": Uint8Array [ + 10, + 32, + 3, + 1, + 0, + 4, + 38, + 3, + 4, + 21, + 31, + 124, + 117, + 4, + 159, + 216, + 53, + 248, + 2, + 0, + 4, + 49, + 24, + 64, + 0, + 32, + 128, + 20, + 103, + 108, + 111, + 98, + 97, + 108, + 95, + 115, + 116, + 97, + 116, + 101, + 95, + 98, + 105, + 103, + 95, + 105, + 110, + 116, + 129, + 205, + 152, + 160, + 167, + 214, + 161, + 170, + 59, + 103, + 49, + 27, + 65, + 0, + 223, + 128, + 4, + 254, + 107, + 223, + 105, + 41, + 130, + 6, + 4, + 234, + 69, + 19, + 211, + 4, + 239, + 52, + 99, + 188, + 4, + 22, + 138, + 253, + 186, + 4, + 142, + 167, + 80, + 210, + 4, + 113, + 61, + 114, + 228, + 4, + 11, + 145, + 152, + 78, + 54, + 26, + 0, + 142, + 8, + 0, + 141, + 0, + 115, + 0, + 88, + 0, + 73, + 0, + 58, + 0, + 36, + 0, + 21, + 0, + 2, + 35, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 136, + 0, + 244, + 40, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 40, + 54, + 26, + 1, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 54, + 26, + 2, + 136, + 0, + 143, + 40, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 40, + 54, + 26, + 1, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 40, + 54, + 26, + 1, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 87, + 2, + 0, + 73, + 21, + 22, + 87, + 6, + 2, + 76, + 80, + 40, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 49, + 22, + 34, + 9, + 73, + 56, + 16, + 34, + 18, + 68, + 136, + 0, + 51, + 40, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 54, + 26, + 2, + 136, + 0, + 17, + 40, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 64, + 255, + 88, + 49, + 24, + 20, + 68, + 34, + 67, + 138, + 2, + 1, + 139, + 254, + 23, + 139, + 255, + 23, + 8, + 22, + 137, + 138, + 1, + 1, + 139, + 255, + 56, + 8, + 22, + 137, + 138, + 2, + 1, + 139, + 255, + 35, + 89, + 139, + 255, + 129, + 2, + 89, + 139, + 255, + 79, + 2, + 75, + 2, + 82, + 139, + 255, + 21, + 139, + 255, + 79, + 3, + 79, + 2, + 82, + 75, + 1, + 21, + 36, + 8, + 22, + 87, + 6, + 2, + 42, + 76, + 80, + 79, + 2, + 80, + 76, + 80, + 139, + 254, + 21, + 36, + 8, + 22, + 87, + 6, + 2, + 42, + 76, + 80, + 139, + 254, + 80, + 76, + 80, + 137, + 138, + 1, + 1, + 49, + 0, + 177, + 129, + 160, + 141, + 6, + 178, + 8, + 178, + 7, + 34, + 178, + 16, + 35, + 178, + 1, + 182, + 139, + 255, + 23, + 178, + 24, + 41, + 178, + 26, + 129, + 6, + 178, + 16, + 35, + 178, + 1, + 179, + 183, + 1, + 62, + 73, + 87, + 4, + 0, + 76, + 87, + 0, + 4, + 40, + 18, + 68, + 137, + ], + "clearStateProgram": Uint8Array [ + 10, + 129, + 1, + 67, + ], + "creator": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "globalState": [ + { + "key": Uint8Array [ + 103, + 108, + 111, + 98, + 97, + 108, + 95, + 115, + 116, + 97, + 116, + 101, + 95, + 98, + 105, + 103, + 95, + 105, + 110, + 116, + ], + "value": { + "bytes": Uint8Array [], + "type": 2, + "uint": 33399922244455500n, + }, + }, + ], + "globalStateSchema": { + "numByteSlice": 0, + "numUint": 1, + }, + "localStateSchema": { + "numByteSlice": 0, + "numUint": 0, + }, + }, + }, + ], + "createdAssets": [ + { + "id": 705457144n, + "params": { + "clawback": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "creator": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "decimals": 0, + "defaultFrozen": false, + "freeze": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "manager": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "name": "gold nugget", + "nameB64": Uint8Array [ + 103, + 111, + 108, + 100, + 32, + 110, + 117, + 103, + 103, + 101, + 116, + ], + "reserve": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "total": 1n, + "unitName": "piece", + "unitNameB64": Uint8Array [ + 112, + 105, + 101, + 99, + 101, + ], + "url": "https://path/to/my/asset/details", + "urlB64": Uint8Array [ + 104, + 116, + 116, + 112, + 115, + 58, + 47, + 47, + 112, + 97, + 116, + 104, + 47, + 116, + 111, + 47, + 109, + 121, + 47, + 97, + 115, + 115, + 101, + 116, + 47, + 100, + 101, + 116, + 97, + 105, + 108, + 115, + ], + }, + }, + ], + "minBalance": 3355500n, + "pendingRewards": 0n, + "rewardBase": 27521n, + "rewards": 0n, + "round": 57650387n, + "status": "Offline", + "totalAppsOptedIn": 0, + "totalAssetsOptedIn": 1, + "totalCreatedApps": 21, + "totalCreatedAssets": 1, +} +`; diff --git a/packages/algod_client/tests/__snapshots__/get_v_2_accounts_address_applications_application_id.test.ts.snap b/packages/algod_client/tests/__snapshots__/get_v_2_accounts_address_applications_application_id.test.ts.snap new file mode 100644 index 00000000..250b7e93 --- /dev/null +++ b/packages/algod_client/tests/__snapshots__/get_v_2_accounts_address_applications_application_id.test.ts.snap @@ -0,0 +1,89 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`GET v2_accounts_ADDRESS_applications_APPLICATION-ID > Common Tests > Basic request and response validation 1`] = ` +{ + "createdApp": { + "approvalProgram": Uint8Array [ + 10, + 32, + 1, + 1, + 49, + 27, + 65, + 0, + 38, + 128, + 4, + 165, + 62, + 90, + 65, + 54, + 26, + 0, + 142, + 1, + 0, + 1, + 0, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 136, + 0, + 21, + 128, + 4, + 21, + 31, + 124, + 117, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 20, + 68, + 34, + 67, + 138, + 1, + 1, + 139, + 255, + 137, + ], + "clearStateProgram": Uint8Array [ + 10, + 129, + 1, + 67, + ], + "creator": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "globalStateSchema": { + "numByteSlice": 0, + "numUint": 0, + }, + "localStateSchema": { + "numByteSlice": 0, + "numUint": 0, + }, + }, + "round": 57650387n, +} +`; diff --git a/packages/algod_client/tests/__snapshots__/get_v_2_accounts_address_assets_asset_id.test.ts.snap b/packages/algod_client/tests/__snapshots__/get_v_2_accounts_address_assets_asset_id.test.ts.snap new file mode 100644 index 00000000..f0a7b9ce --- /dev/null +++ b/packages/algod_client/tests/__snapshots__/get_v_2_accounts_address_assets_asset_id.test.ts.snap @@ -0,0 +1,79 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`GET v2_accounts_ADDRESS_assets_ASSET-ID > Common Tests > Basic request and response validation 1`] = ` +{ + "assetHolding": { + "amount": 0n, + "assetId": 705457144n, + "isFrozen": false, + }, + "createdAsset": { + "clawback": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "creator": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "decimals": 0, + "defaultFrozen": false, + "freeze": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "manager": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "name": "gold nugget", + "nameB64": Uint8Array [ + 103, + 111, + 108, + 100, + 32, + 110, + 117, + 103, + 103, + 101, + 116, + ], + "reserve": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "total": 1n, + "unitName": "piece", + "unitNameB64": Uint8Array [ + 112, + 105, + 101, + 99, + 101, + ], + "url": "https://path/to/my/asset/details", + "urlB64": Uint8Array [ + 104, + 116, + 116, + 112, + 115, + 58, + 47, + 47, + 112, + 97, + 116, + 104, + 47, + 116, + 111, + 47, + 109, + 121, + 47, + 97, + 115, + 115, + 101, + 116, + 47, + 100, + 101, + 116, + 97, + 105, + 108, + 115, + ], + }, + "round": 57650387n, +} +`; diff --git a/packages/algod_client/tests/__snapshots__/get_v_2_applications_application_id.test.ts.snap b/packages/algod_client/tests/__snapshots__/get_v_2_applications_application_id.test.ts.snap new file mode 100644 index 00000000..204bd764 --- /dev/null +++ b/packages/algod_client/tests/__snapshots__/get_v_2_applications_application_id.test.ts.snap @@ -0,0 +1,89 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`GET v2_applications_APPLICATION-ID > Common Tests > Basic request and response validation 1`] = ` +{ + "id": 718348254n, + "params": { + "approvalProgram": Uint8Array [ + 10, + 32, + 1, + 1, + 49, + 27, + 65, + 0, + 38, + 128, + 4, + 165, + 62, + 90, + 65, + 54, + 26, + 0, + 142, + 1, + 0, + 1, + 0, + 49, + 25, + 20, + 68, + 49, + 24, + 68, + 54, + 26, + 1, + 136, + 0, + 21, + 128, + 4, + 21, + 31, + 124, + 117, + 76, + 80, + 176, + 34, + 67, + 49, + 25, + 20, + 68, + 49, + 24, + 20, + 68, + 34, + 67, + 138, + 1, + 1, + 139, + 255, + 137, + ], + "clearStateProgram": Uint8Array [ + 10, + 129, + 1, + 67, + ], + "creator": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "globalStateSchema": { + "numByteSlice": 0, + "numUint": 0, + }, + "localStateSchema": { + "numByteSlice": 0, + "numUint": 0, + }, + }, +} +`; diff --git a/packages/algod_client/tests/__snapshots__/get_v_2_assets_asset_id.test.ts.snap b/packages/algod_client/tests/__snapshots__/get_v_2_assets_asset_id.test.ts.snap new file mode 100644 index 00000000..076175a7 --- /dev/null +++ b/packages/algod_client/tests/__snapshots__/get_v_2_assets_asset_id.test.ts.snap @@ -0,0 +1,74 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`GET v2_assets_ASSET-ID > Common Tests > Basic request and response validation 1`] = ` +{ + "id": 705457144n, + "params": { + "clawback": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "creator": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "decimals": 0, + "defaultFrozen": false, + "freeze": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "manager": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "name": "gold nugget", + "nameB64": Uint8Array [ + 103, + 111, + 108, + 100, + 32, + 110, + 117, + 103, + 103, + 101, + 116, + ], + "reserve": "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE", + "total": 1n, + "unitName": "piece", + "unitNameB64": Uint8Array [ + 112, + 105, + 101, + 99, + 101, + ], + "url": "https://path/to/my/asset/details", + "urlB64": Uint8Array [ + 104, + 116, + 116, + 112, + 115, + 58, + 47, + 47, + 112, + 97, + 116, + 104, + 47, + 116, + 111, + 47, + 109, + 121, + 47, + 97, + 115, + 115, + 101, + 116, + 47, + 100, + 101, + 116, + 97, + 105, + 108, + 115, + ], + }, +} +`; diff --git a/packages/algod_client/tests/__snapshots__/get_v_2_blocks_round_hash.test.ts.snap b/packages/algod_client/tests/__snapshots__/get_v_2_blocks_round_hash.test.ts.snap new file mode 100644 index 00000000..2f4a6baf --- /dev/null +++ b/packages/algod_client/tests/__snapshots__/get_v_2_blocks_round_hash.test.ts.snap @@ -0,0 +1,7 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`GET v2_blocks_ROUND_hash > Common Tests > Basic request and response validation 1`] = ` +{ + "blockHash": "PKZ7LQO6KNISFUVXN3HFZQKF4GJV7XKFHFZNNKC6DAHUEZZM3IQQ", +} +`; diff --git a/packages/algod_client/tests/__snapshots__/get_v_2_blocks_round_lightheader_proof.test.ts.snap b/packages/algod_client/tests/__snapshots__/get_v_2_blocks_round_lightheader_proof.test.ts.snap new file mode 100644 index 00000000..54e5fb98 --- /dev/null +++ b/packages/algod_client/tests/__snapshots__/get_v_2_blocks_round_lightheader_proof.test.ts.snap @@ -0,0 +1,266 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`GET v2_blocks_ROUND_lightheader_proof > Common Tests > Basic request and response validation 1`] = ` +{ + "index": 118, + "proof": Uint8Array [ + 187, + 249, + 23, + 222, + 225, + 251, + 159, + 241, + 137, + 8, + 134, + 38, + 14, + 55, + 190, + 190, + 132, + 181, + 26, + 9, + 69, + 101, + 189, + 198, + 35, + 45, + 114, + 177, + 28, + 94, + 176, + 147, + 74, + 123, + 153, + 61, + 118, + 68, + 138, + 183, + 106, + 229, + 25, + 131, + 221, + 10, + 155, + 245, + 130, + 93, + 128, + 53, + 204, + 61, + 9, + 8, + 188, + 166, + 81, + 128, + 21, + 134, + 50, + 234, + 59, + 63, + 115, + 233, + 245, + 71, + 255, + 27, + 67, + 198, + 173, + 65, + 210, + 66, + 54, + 108, + 23, + 206, + 159, + 100, + 124, + 162, + 108, + 172, + 156, + 30, + 51, + 13, + 224, + 54, + 82, + 208, + 15, + 27, + 11, + 157, + 157, + 213, + 208, + 58, + 91, + 206, + 247, + 180, + 20, + 82, + 164, + 70, + 142, + 176, + 124, + 182, + 62, + 179, + 158, + 98, + 86, + 122, + 11, + 75, + 247, + 188, + 19, + 44, + 201, + 239, + 57, + 144, + 103, + 50, + 213, + 22, + 159, + 53, + 50, + 120, + 133, + 38, + 179, + 156, + 154, + 72, + 230, + 48, + 77, + 253, + 151, + 146, + 119, + 244, + 137, + 71, + 13, + 30, + 89, + 157, + 26, + 144, + 27, + 244, + 103, + 41, + 218, + 186, + 24, + 82, + 78, + 179, + 161, + 159, + 177, + 159, + 79, + 210, + 65, + 115, + 101, + 108, + 47, + 178, + 37, + 82, + 6, + 174, + 198, + 164, + 253, + 117, + 168, + 118, + 212, + 230, + 95, + 152, + 83, + 22, + 153, + 250, + 161, + 246, + 253, + 104, + 184, + 25, + 110, + 138, + 198, + 201, + 97, + 74, + 3, + 6, + 73, + 71, + 234, + 161, + 161, + 16, + 216, + 170, + 20, + 42, + 137, + 103, + 152, + 72, + 191, + 250, + 172, + 166, + 127, + 1, + 57, + 119, + 64, + 173, + 86, + 81, + 4, + 124, + 215, + 227, + 171, + 198, + 57, + 101, + 192, + 151, + 95, + 125, + 58, + 142, + ], + "treedepth": 8, +} +`; diff --git a/packages/algod_client/tests/__snapshots__/get_v_2_blocks_round_txids.test.ts.snap b/packages/algod_client/tests/__snapshots__/get_v_2_blocks_round_txids.test.ts.snap new file mode 100644 index 00000000..afa5b072 --- /dev/null +++ b/packages/algod_client/tests/__snapshots__/get_v_2_blocks_round_txids.test.ts.snap @@ -0,0 +1,13 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`GET v2_blocks_ROUND_txids > Common Tests > Basic request and response validation 1`] = ` +{ + "blockTxIds": [ + "W6SAFSKT3V4SMLQXG3YDLI4TOBEGPPVQ5PQNJ7BCQ6K7WEDVDFEQ", + "Q5T6IHV62WN5YRGGBZ5PTTOGD4UEEJ2IJVWVVQPDSRZ5JYLNY2LQ", + "GX4OEJETJKWAFK4RK26SYSLBIAUHP7KQVK6N7CONESCS5UZOZSXQ", + "5UJZEZJDYQZZC5DTUYYGMW2W65KFMETQLYC34JPFSMBCQXLX6T4Q", + "ONXCSR5POM7B53L56LOVJUD5VUNQFPDXOSODIH6LOXMBTQALWB5A", + ], +} +`; diff --git a/packages/algod_client/tests/__snapshots__/get_v_2_devmode_blocks_offset.test.ts.snap b/packages/algod_client/tests/__snapshots__/get_v_2_devmode_blocks_offset.test.ts.snap new file mode 100644 index 00000000..475fe11d --- /dev/null +++ b/packages/algod_client/tests/__snapshots__/get_v_2_devmode_blocks_offset.test.ts.snap @@ -0,0 +1,7 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`GET v2_devmode_blocks_offset > Common Tests > Basic request and response validation 1`] = ` +{ + "offset": 0, +} +`; diff --git a/packages/algod_client/tests/__snapshots__/get_v_2_ledger_supply.test.ts.snap b/packages/algod_client/tests/__snapshots__/get_v_2_ledger_supply.test.ts.snap new file mode 100644 index 00000000..627d0a21 --- /dev/null +++ b/packages/algod_client/tests/__snapshots__/get_v_2_ledger_supply.test.ts.snap @@ -0,0 +1,9 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`GET v2_ledger_supply > Common Tests > Basic request and response validation 1`] = ` +{ + "currentRound": 57650387n, + "onlineMoney": 4932435463568821n, + "totalMoney": 10123920704416688n, +} +`; diff --git a/packages/algod_client/tests/__snapshots__/get_v_2_ledger_sync.test.ts.snap b/packages/algod_client/tests/__snapshots__/get_v_2_ledger_sync.test.ts.snap new file mode 100644 index 00000000..b3092c09 --- /dev/null +++ b/packages/algod_client/tests/__snapshots__/get_v_2_ledger_sync.test.ts.snap @@ -0,0 +1,8 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`GET v2_ledger_sync > Common Tests > Basic request and response validation 1`] = ` +{ + "nodely": "virtual instant follower service", + "round": 0n, +} +`; diff --git a/packages/algod_client/tests/__snapshots__/get_v_2_status.test.ts.snap b/packages/algod_client/tests/__snapshots__/get_v_2_status.test.ts.snap new file mode 100644 index 00000000..70705706 --- /dev/null +++ b/packages/algod_client/tests/__snapshots__/get_v_2_status.test.ts.snap @@ -0,0 +1,24 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`GET v2_status > Common Tests > Basic request and response validation 1`] = ` +{ + "catchpoint": "", + "catchpointAcquiredBlocks": 0, + "catchpointProcessedAccounts": 0, + "catchpointProcessedKvs": 0, + "catchpointTotalAccounts": 0, + "catchpointTotalBlocks": 0, + "catchpointTotalKvs": 0, + "catchpointVerifiedAccounts": 0, + "catchpointVerifiedKvs": 0, + "catchupTime": 0n, + "lastCatchpoint": "", + "lastRound": 57650385n, + "lastVersion": "https://github.com/algorandfoundation/specs/tree/953304de35264fc3ef91bcd05c123242015eeaed", + "nextVersion": "https://github.com/algorandfoundation/specs/tree/953304de35264fc3ef91bcd05c123242015eeaed", + "nextVersionRound": 57650386n, + "nextVersionSupported": true, + "stoppedAtUnsupportedRound": false, + "timeSinceLastRound": 2531775446n, +} +`; diff --git a/packages/algod_client/tests/__snapshots__/get_v_2_status_wait_for_block_after_round.test.ts.snap b/packages/algod_client/tests/__snapshots__/get_v_2_status_wait_for_block_after_round.test.ts.snap new file mode 100644 index 00000000..134bd142 --- /dev/null +++ b/packages/algod_client/tests/__snapshots__/get_v_2_status_wait_for_block_after_round.test.ts.snap @@ -0,0 +1,24 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`GET v2_status_wait-for-block-after_ROUND > Common Tests > Basic request and response validation 1`] = ` +{ + "catchpoint": "", + "catchpointAcquiredBlocks": 0, + "catchpointProcessedAccounts": 0, + "catchpointProcessedKvs": 0, + "catchpointTotalAccounts": 0, + "catchpointTotalBlocks": 0, + "catchpointTotalKvs": 0, + "catchpointVerifiedAccounts": 0, + "catchpointVerifiedKvs": 0, + "catchupTime": 0n, + "lastCatchpoint": "", + "lastRound": 57650386n, + "lastVersion": "https://github.com/algorandfoundation/specs/tree/953304de35264fc3ef91bcd05c123242015eeaed", + "nextVersion": "https://github.com/algorandfoundation/specs/tree/953304de35264fc3ef91bcd05c123242015eeaed", + "nextVersionRound": 57650387n, + "nextVersionSupported": true, + "stoppedAtUnsupportedRound": false, + "timeSinceLastRound": 654084756n, +} +`; diff --git a/packages/algod_client/tests/__snapshots__/get_v_2_transactions_params.test.ts.snap b/packages/algod_client/tests/__snapshots__/get_v_2_transactions_params.test.ts.snap new file mode 100644 index 00000000..ce63a152 --- /dev/null +++ b/packages/algod_client/tests/__snapshots__/get_v_2_transactions_params.test.ts.snap @@ -0,0 +1,47 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`GET v2_transactions_params > Common Tests > Basic request and response validation 1`] = ` +{ + "consensusVersion": "https://github.com/algorandfoundation/specs/tree/953304de35264fc3ef91bcd05c123242015eeaed", + "fee": 0n, + "firstValid": 57650387n, + "flatFee": false, + "genesisHash": Uint8Array [ + 72, + 99, + 181, + 24, + 164, + 179, + 200, + 78, + 200, + 16, + 242, + 45, + 79, + 16, + 129, + 203, + 15, + 113, + 240, + 89, + 167, + 172, + 32, + 222, + 198, + 47, + 127, + 112, + 229, + 9, + 58, + 34, + ], + "genesisId": "testnet-v1.0", + "lastValid": 57651387n, + "minFee": 1000n, +} +`; diff --git a/packages/algod_client/tests/__snapshots__/get_versions.test.ts.snap b/packages/algod_client/tests/__snapshots__/get_versions.test.ts.snap new file mode 100644 index 00000000..d0313bb4 --- /dev/null +++ b/packages/algod_client/tests/__snapshots__/get_versions.test.ts.snap @@ -0,0 +1,52 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`GET versions > Common Tests > Basic request and response validation 1`] = ` +{ + "build": { + "branch": "AVAIL", + "buildNumber": 1, + "channel": "AVAIL", + "commitHash": "7b607ce4+", + "major": 4, + "minor": 4, + }, + "genesisHashB64": Uint8Array [ + 72, + 99, + 181, + 24, + 164, + 179, + 200, + 78, + 200, + 16, + 242, + 45, + 79, + 16, + 129, + 203, + 15, + 113, + 240, + 89, + 167, + 172, + 32, + 222, + 198, + 47, + 127, + 112, + 229, + 9, + 58, + 34, + ], + "genesisId": "testnet-v1.0", + "versions": [ + "v2", + ], +} +`; diff --git a/packages/algod_client/tests/__snapshots__/post_v_2_devmode_blocks_offset_offset.test.ts.snap b/packages/algod_client/tests/__snapshots__/post_v_2_devmode_blocks_offset_offset.test.ts.snap new file mode 100644 index 00000000..a5f88b87 --- /dev/null +++ b/packages/algod_client/tests/__snapshots__/post_v_2_devmode_blocks_offset_offset.test.ts.snap @@ -0,0 +1,3 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`POST v2_devmode_blocks_offset_OFFSET > Common Tests > Basic request and response validation 1`] = `undefined`; diff --git a/packages/algod_client/tests/config.ts b/packages/algod_client/tests/config.ts new file mode 100644 index 00000000..48af4fd9 --- /dev/null +++ b/packages/algod_client/tests/config.ts @@ -0,0 +1,20 @@ +import type { ClientConfig } from '../src/core/client-config' + +export const config: ClientConfig = { + baseUrl: process.env.MOCK_ALGOD_SERVER || 'http://localhost:8000', + apiToken: process.env.MOCK_ALGOD_TOKEN || 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', +} + +const algodServer = process.env.ALGOD_SERVER || 'http://localhost' +const algodPort = process.env.ALGOD_PORT || '4001' +const algodBaseUrl = `${algodServer}:${algodPort}` + +export const localnetConfig: ClientConfig = { + baseUrl: algodBaseUrl, + apiToken: process.env.ALGOD_TOKEN || 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', +} + +export const TEST_ADDRESS = '25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE' +export const TEST_APP_ID = 718348254 +export const TEST_ASSET_ID = 705457144 +export const TEST_ROUND = 24099447 diff --git a/packages/algod_client/tests/delete_v_2_catchup_catchpoint.test.ts b/packages/algod_client/tests/delete_v_2_catchup_catchpoint.test.ts new file mode 100644 index 00000000..b17cb154 --- /dev/null +++ b/packages/algod_client/tests/delete_v_2_catchup_catchpoint.test.ts @@ -0,0 +1,15 @@ +import { expect, test, describe } from "vitest"; + +describe("DELETE v2_catchup_CATCHPOINT", () => { + // Polytest Suite: DELETE v2_catchup_CATCHPOINT + + describe("Common Tests", () => { + // Polytest Group: Common Tests + + test("Basic request and response validation", () => { + throw new Error("TEST NOT IMPLEMENTED"); + }); + + }); + +}); \ No newline at end of file diff --git a/packages/algod_client/tests/delete_v_2_ledger_sync.test.ts b/packages/algod_client/tests/delete_v_2_ledger_sync.test.ts new file mode 100644 index 00000000..01d9ceb7 --- /dev/null +++ b/packages/algod_client/tests/delete_v_2_ledger_sync.test.ts @@ -0,0 +1,36 @@ +import { describe, expect, test } from 'vitest' +import { AlgodClient } from '../src/client' +import { localnetConfig } from './config' + +describe('DELETE v2_ledger_sync', () => { + // Polytest Suite: DELETE v2_ledger_sync + + describe('Common Tests', () => { + // Polytest Group: Common Tests + + // Skipped: The DELETE /v2/ledger/sync endpoint requires algod to run in follower mode. + // Standard localnet does not have follower mode enabled by default. + // To enable follower mode: algod -f -d + test.skip('Basic request and response validation', async () => { + const client = new AlgodClient(localnetConfig) + + // First set a sync round + await client.setSyncRound(2000) + + // Verify it was set + const beforeUnset = await client.getSyncRound() + expect(beforeUnset.round).toBe(2000n) + + // Unset it (DELETE) + const result = await client.unsetSyncRound() + + // Should return void (undefined) + expect(result).toMatchSnapshot() + expect(result).toBeUndefined() + + // Verify it was unset (should return to 0) + const afterUnset = await client.getSyncRound() + expect(afterUnset.round).toBe(0n) + }) + }) +}) \ No newline at end of file diff --git a/packages/algod_client/tests/delete_v_2_participation_participation_id.test.ts b/packages/algod_client/tests/delete_v_2_participation_participation_id.test.ts new file mode 100644 index 00000000..7ef889c7 --- /dev/null +++ b/packages/algod_client/tests/delete_v_2_participation_participation_id.test.ts @@ -0,0 +1,15 @@ +import { expect, test, describe } from "vitest"; + +describe("DELETE v2_participation_PARTICIPATION-ID", () => { + // Polytest Suite: DELETE v2_participation_PARTICIPATION-ID + + describe("Common Tests", () => { + // Polytest Group: Common Tests + + test("Basic request and response validation", () => { + throw new Error("TEST NOT IMPLEMENTED"); + }); + + }); + +}); \ No newline at end of file diff --git a/packages/algod_client/tests/get_debug_settings_config.test.ts b/packages/algod_client/tests/get_debug_settings_config.test.ts new file mode 100644 index 00000000..011b6911 --- /dev/null +++ b/packages/algod_client/tests/get_debug_settings_config.test.ts @@ -0,0 +1,14 @@ +import { describe, test } from 'vitest' + +describe('GET debug_settings_config', () => { + // Polytest Suite: GET debug_settings_config + + describe('Common Tests', () => { + // Polytest Group: Common Tests + + // Skipping: This test requires mocking from the mock server + test.skip('Basic request and response validation', () => { + throw new Error('TEST NOT IMPLEMENTED') + }) + }) +}) diff --git a/packages/algod_client/tests/get_debug_settings_pprof.test.ts b/packages/algod_client/tests/get_debug_settings_pprof.test.ts new file mode 100644 index 00000000..39352847 --- /dev/null +++ b/packages/algod_client/tests/get_debug_settings_pprof.test.ts @@ -0,0 +1,14 @@ +import { describe, test } from 'vitest' + +describe('GET debug_settings_pprof', () => { + // Polytest Suite: GET debug_settings_pprof + + describe('Common Tests', () => { + // Polytest Group: Common Tests + + // Skipping: This test requires mocking from the mock server + test.skip('Basic request and response validation', () => { + throw new Error('TEST NOT IMPLEMENTED') + }) + }) +}) diff --git a/packages/algod_client/tests/get_genesis.test.ts b/packages/algod_client/tests/get_genesis.test.ts new file mode 100644 index 00000000..f645f111 --- /dev/null +++ b/packages/algod_client/tests/get_genesis.test.ts @@ -0,0 +1,19 @@ +import { describe, expect, test } from 'vitest' +import { AlgodClient } from '../src/client' +import { config } from './config' + +describe('GET genesis', () => { + // Polytest Suite: GET genesis + + describe('Common Tests', () => { + // Polytest Group: Common Tests + + test('Basic request and response validation', async () => { + const client = new AlgodClient(config) + + const result = await client.getGenesis() + + expect(result).toMatchSnapshot() + }) + }) +}) \ No newline at end of file diff --git a/packages/algod_client/tests/get_health.test.ts b/packages/algod_client/tests/get_health.test.ts new file mode 100644 index 00000000..5404f896 --- /dev/null +++ b/packages/algod_client/tests/get_health.test.ts @@ -0,0 +1,19 @@ +import { describe, expect, test } from 'vitest' +import { AlgodClient } from '../src/client' +import { config } from './config' + +describe('GET health', () => { + // Polytest Suite: GET health + + describe('Common Tests', () => { + // Polytest Group: Common Tests + + test('Basic request and response validation', async () => { + const client = new AlgodClient(config) + + const result = await client.healthCheck() + + expect(result).toMatchSnapshot() + }) + }) +}) diff --git a/packages/algod_client/tests/get_metrics.test.ts b/packages/algod_client/tests/get_metrics.test.ts new file mode 100644 index 00000000..c0d06217 --- /dev/null +++ b/packages/algod_client/tests/get_metrics.test.ts @@ -0,0 +1,15 @@ +import { expect, test, describe } from "vitest"; + +describe("GET metrics", () => { + // Polytest Suite: GET metrics + + describe("Common Tests", () => { + // Polytest Group: Common Tests + + test("Basic request and response validation", () => { + throw new Error("TEST NOT IMPLEMENTED"); + }); + + }); + +}); \ No newline at end of file diff --git a/packages/algod_client/tests/get_ready.test.ts b/packages/algod_client/tests/get_ready.test.ts new file mode 100644 index 00000000..85547f27 --- /dev/null +++ b/packages/algod_client/tests/get_ready.test.ts @@ -0,0 +1,19 @@ +import { describe, expect, test } from 'vitest' +import { AlgodClient } from '../src/client' +import { config } from './config' + +describe('GET ready', () => { + // Polytest Suite: GET ready + + describe('Common Tests', () => { + // Polytest Group: Common Tests + + test('Basic request and response validation', async () => { + const client = new AlgodClient(config) + + const result = await client.getReady() + + expect(result).toMatchSnapshot() + }) + }) +}) \ No newline at end of file diff --git a/packages/algod_client/tests/get_swagger_json.test.ts b/packages/algod_client/tests/get_swagger_json.test.ts new file mode 100644 index 00000000..284b1be3 --- /dev/null +++ b/packages/algod_client/tests/get_swagger_json.test.ts @@ -0,0 +1,15 @@ +import { expect, test, describe } from "vitest"; + +describe("GET swagger_json", () => { + // Polytest Suite: GET swagger_json + + describe("Common Tests", () => { + // Polytest Group: Common Tests + + test("Basic request and response validation", () => { + throw new Error("TEST NOT IMPLEMENTED"); + }); + + }); + +}); \ No newline at end of file diff --git a/packages/algod_client/tests/get_v_2_accounts_address.test.ts b/packages/algod_client/tests/get_v_2_accounts_address.test.ts new file mode 100644 index 00000000..3fa6426b --- /dev/null +++ b/packages/algod_client/tests/get_v_2_accounts_address.test.ts @@ -0,0 +1,19 @@ +import { describe, expect, test } from 'vitest' +import { AlgodClient } from '../src/client' +import { config, TEST_ADDRESS } from './config' + +describe('GET v2_accounts_ADDRESS', () => { + // Polytest Suite: GET v2_accounts_ADDRESS + + describe('Common Tests', () => { + // Polytest Group: Common Tests + + test('Basic request and response validation', async () => { + const client = new AlgodClient(config) + + const result = await client.accountInformation(TEST_ADDRESS) + + expect(result).toMatchSnapshot() + }) + }) +}) \ No newline at end of file diff --git a/packages/algod_client/tests/get_v_2_accounts_address_applications_application_id.test.ts b/packages/algod_client/tests/get_v_2_accounts_address_applications_application_id.test.ts new file mode 100644 index 00000000..711a4404 --- /dev/null +++ b/packages/algod_client/tests/get_v_2_accounts_address_applications_application_id.test.ts @@ -0,0 +1,19 @@ +import { describe, expect, test } from 'vitest' +import { AlgodClient } from '../src/client' +import { config, TEST_ADDRESS, TEST_APP_ID } from './config' + +describe('GET v2_accounts_ADDRESS_applications_APPLICATION-ID', () => { + // Polytest Suite: GET v2_accounts_ADDRESS_applications_APPLICATION-ID + + describe('Common Tests', () => { + // Polytest Group: Common Tests + + test('Basic request and response validation', async () => { + const client = new AlgodClient(config) + + const result = await client.accountApplicationInformation(TEST_ADDRESS, TEST_APP_ID) + + expect(result).toMatchSnapshot() + }) + }) +}) \ No newline at end of file diff --git a/packages/algod_client/tests/get_v_2_accounts_address_assets.test.ts b/packages/algod_client/tests/get_v_2_accounts_address_assets.test.ts new file mode 100644 index 00000000..6efe6605 --- /dev/null +++ b/packages/algod_client/tests/get_v_2_accounts_address_assets.test.ts @@ -0,0 +1,15 @@ +import { expect, test, describe } from "vitest"; + +describe("GET v2_accounts_ADDRESS_assets", () => { + // Polytest Suite: GET v2_accounts_ADDRESS_assets + + describe("Common Tests", () => { + // Polytest Group: Common Tests + + test("Basic request and response validation", () => { + throw new Error("TEST NOT IMPLEMENTED"); + }); + + }); + +}); \ No newline at end of file diff --git a/packages/algod_client/tests/get_v_2_accounts_address_assets_asset_id.test.ts b/packages/algod_client/tests/get_v_2_accounts_address_assets_asset_id.test.ts new file mode 100644 index 00000000..57adffc1 --- /dev/null +++ b/packages/algod_client/tests/get_v_2_accounts_address_assets_asset_id.test.ts @@ -0,0 +1,19 @@ +import { describe, expect, test } from 'vitest' +import { AlgodClient } from '../src/client' +import { config, TEST_ADDRESS, TEST_ASSET_ID } from './config' + +describe('GET v2_accounts_ADDRESS_assets_ASSET-ID', () => { + // Polytest Suite: GET v2_accounts_ADDRESS_assets_ASSET-ID + + describe('Common Tests', () => { + // Polytest Group: Common Tests + + test('Basic request and response validation', async () => { + const client = new AlgodClient(config) + + const result = await client.accountAssetInformation(TEST_ADDRESS, TEST_ASSET_ID) + + expect(result).toMatchSnapshot() + }) + }) +}) \ No newline at end of file diff --git a/packages/algod_client/tests/get_v_2_accounts_address_transactions_pending.test.ts b/packages/algod_client/tests/get_v_2_accounts_address_transactions_pending.test.ts new file mode 100644 index 00000000..ee9b0bc6 --- /dev/null +++ b/packages/algod_client/tests/get_v_2_accounts_address_transactions_pending.test.ts @@ -0,0 +1,20 @@ +import { describe, expect, test } from 'vitest' +import { AlgodClient } from '../src/client' +import { config, TEST_ADDRESS } from './config' + +describe('GET v2_accounts_ADDRESS_transactions_pending', () => { + // Polytest Suite: GET v2_accounts_ADDRESS_transactions_pending + + describe('Common Tests', () => { + // Polytest Group: Common Tests + + // TODO: Fix msgpack response handling in PollyJS mock server + test.skip('Basic request and response validation', async () => { + const client = new AlgodClient(config) + + const result = await client.getPendingTransactionsByAddress(TEST_ADDRESS) + + expect(result).toMatchSnapshot() + }) + }) +}) \ No newline at end of file diff --git a/packages/algod_client/tests/get_v_2_applications_application_id.test.ts b/packages/algod_client/tests/get_v_2_applications_application_id.test.ts new file mode 100644 index 00000000..12a4b9be --- /dev/null +++ b/packages/algod_client/tests/get_v_2_applications_application_id.test.ts @@ -0,0 +1,19 @@ +import { describe, expect, test } from 'vitest' +import { AlgodClient } from '../src/client' +import { config, TEST_APP_ID } from './config' + +describe('GET v2_applications_APPLICATION-ID', () => { + // Polytest Suite: GET v2_applications_APPLICATION-ID + + describe('Common Tests', () => { + // Polytest Group: Common Tests + + test('Basic request and response validation', async () => { + const client = new AlgodClient(config) + + const result = await client.getApplicationById(TEST_APP_ID) + + expect(result).toMatchSnapshot() + }) + }) +}) \ No newline at end of file diff --git a/packages/algod_client/tests/get_v_2_applications_application_id_box.test.ts b/packages/algod_client/tests/get_v_2_applications_application_id_box.test.ts new file mode 100644 index 00000000..6be38ec9 --- /dev/null +++ b/packages/algod_client/tests/get_v_2_applications_application_id_box.test.ts @@ -0,0 +1,15 @@ +import { expect, test, describe } from "vitest"; + +describe("GET v2_applications_APPLICATION-ID_box", () => { + // Polytest Suite: GET v2_applications_APPLICATION-ID_box + + describe("Common Tests", () => { + // Polytest Group: Common Tests + + test("Basic request and response validation", () => { + throw new Error("TEST NOT IMPLEMENTED"); + }); + + }); + +}); \ No newline at end of file diff --git a/packages/algod_client/tests/get_v_2_applications_application_id_boxes.test.ts b/packages/algod_client/tests/get_v_2_applications_application_id_boxes.test.ts new file mode 100644 index 00000000..6e009633 --- /dev/null +++ b/packages/algod_client/tests/get_v_2_applications_application_id_boxes.test.ts @@ -0,0 +1,15 @@ +import { expect, test, describe } from "vitest"; + +describe("GET v2_applications_APPLICATION-ID_boxes", () => { + // Polytest Suite: GET v2_applications_APPLICATION-ID_boxes + + describe("Common Tests", () => { + // Polytest Group: Common Tests + + test("Basic request and response validation", () => { + throw new Error("TEST NOT IMPLEMENTED"); + }); + + }); + +}); \ No newline at end of file diff --git a/packages/algod_client/tests/get_v_2_assets_asset_id.test.ts b/packages/algod_client/tests/get_v_2_assets_asset_id.test.ts new file mode 100644 index 00000000..1bc14bc1 --- /dev/null +++ b/packages/algod_client/tests/get_v_2_assets_asset_id.test.ts @@ -0,0 +1,21 @@ +import { describe, expect, test } from 'vitest' +import { AlgodClient } from '../src/client' +import { config } from './config' + +const TEST_ASSET_ID = 705457144 + +describe('GET v2_assets_ASSET-ID', () => { + // Polytest Suite: GET v2_assets_ASSET-ID + + describe('Common Tests', () => { + // Polytest Group: Common Tests + + test('Basic request and response validation', async () => { + const client = new AlgodClient(config) + + const result = await client.getAssetById(TEST_ASSET_ID) + + expect(result).toMatchSnapshot() + }) + }) +}) diff --git a/packages/algod_client/tests/get_v_2_blocks_round.test.ts b/packages/algod_client/tests/get_v_2_blocks_round.test.ts new file mode 100644 index 00000000..15c94acf --- /dev/null +++ b/packages/algod_client/tests/get_v_2_blocks_round.test.ts @@ -0,0 +1,20 @@ +import { describe, expect, test } from 'vitest' +import { AlgodClient } from '../src/client' +import { config, TEST_ROUND } from './config' + +describe('GET v2_blocks_ROUND', () => { + // Polytest Suite: GET v2_blocks_ROUND + + describe('Common Tests', () => { + // Polytest Group: Common Tests + + // TODO: Fix msgpack response handling in PollyJS mock server + test.skip('Basic request and response validation', async () => { + const client = new AlgodClient(config) + + const result = await client.getBlock(TEST_ROUND) + + expect(result).toMatchSnapshot() + }) + }) +}) \ No newline at end of file diff --git a/packages/algod_client/tests/get_v_2_blocks_round_hash.test.ts b/packages/algod_client/tests/get_v_2_blocks_round_hash.test.ts new file mode 100644 index 00000000..daf7b095 --- /dev/null +++ b/packages/algod_client/tests/get_v_2_blocks_round_hash.test.ts @@ -0,0 +1,19 @@ +import { describe, expect, test } from 'vitest' +import { AlgodClient } from '../src/client' +import { config, TEST_ROUND } from './config' + +describe('GET v2_blocks_ROUND_hash', () => { + // Polytest Suite: GET v2_blocks_ROUND_hash + + describe('Common Tests', () => { + // Polytest Group: Common Tests + + test('Basic request and response validation', async () => { + const client = new AlgodClient(config) + + const result = await client.getBlockHash(TEST_ROUND) + + expect(result).toMatchSnapshot() + }) + }) +}) \ No newline at end of file diff --git a/packages/algod_client/tests/get_v_2_blocks_round_lightheader_proof.test.ts b/packages/algod_client/tests/get_v_2_blocks_round_lightheader_proof.test.ts new file mode 100644 index 00000000..3c08d3c9 --- /dev/null +++ b/packages/algod_client/tests/get_v_2_blocks_round_lightheader_proof.test.ts @@ -0,0 +1,19 @@ +import { describe, expect, test } from 'vitest' +import { AlgodClient } from '../src/client' +import { config, TEST_ROUND } from './config' + +describe('GET v2_blocks_ROUND_lightheader_proof', () => { + // Polytest Suite: GET v2_blocks_ROUND_lightheader_proof + + describe('Common Tests', () => { + // Polytest Group: Common Tests + + test('Basic request and response validation', async () => { + const client = new AlgodClient(config) + + const result = await client.getLightBlockHeaderProof(TEST_ROUND) + + expect(result).toMatchSnapshot() + }) + }) +}) \ No newline at end of file diff --git a/packages/algod_client/tests/get_v_2_blocks_round_logs.test.ts b/packages/algod_client/tests/get_v_2_blocks_round_logs.test.ts new file mode 100644 index 00000000..7d19fbb3 --- /dev/null +++ b/packages/algod_client/tests/get_v_2_blocks_round_logs.test.ts @@ -0,0 +1,15 @@ +import { expect, test, describe } from "vitest"; + +describe("GET v2_blocks_ROUND_logs", () => { + // Polytest Suite: GET v2_blocks_ROUND_logs + + describe("Common Tests", () => { + // Polytest Group: Common Tests + + test("Basic request and response validation", () => { + throw new Error("TEST NOT IMPLEMENTED"); + }); + + }); + +}); \ No newline at end of file diff --git a/packages/algod_client/tests/get_v_2_blocks_round_transactions_txid_proof.test.ts b/packages/algod_client/tests/get_v_2_blocks_round_transactions_txid_proof.test.ts new file mode 100644 index 00000000..c00887c0 --- /dev/null +++ b/packages/algod_client/tests/get_v_2_blocks_round_transactions_txid_proof.test.ts @@ -0,0 +1,15 @@ +import { expect, test, describe } from "vitest"; + +describe("GET v2_blocks_ROUND_transactions_TXID_proof", () => { + // Polytest Suite: GET v2_blocks_ROUND_transactions_TXID_proof + + describe("Common Tests", () => { + // Polytest Group: Common Tests + + test("Basic request and response validation", () => { + throw new Error("TEST NOT IMPLEMENTED"); + }); + + }); + +}); \ No newline at end of file diff --git a/packages/algod_client/tests/get_v_2_blocks_round_txids.test.ts b/packages/algod_client/tests/get_v_2_blocks_round_txids.test.ts new file mode 100644 index 00000000..26bc38cf --- /dev/null +++ b/packages/algod_client/tests/get_v_2_blocks_round_txids.test.ts @@ -0,0 +1,19 @@ +import { describe, expect, test } from 'vitest' +import { AlgodClient } from '../src/client' +import { config, TEST_ROUND } from './config' + +describe('GET v2_blocks_ROUND_txids', () => { + // Polytest Suite: GET v2_blocks_ROUND_txids + + describe('Common Tests', () => { + // Polytest Group: Common Tests + + test('Basic request and response validation', async () => { + const client = new AlgodClient(config) + + const result = await client.getBlockTxIds(TEST_ROUND) + + expect(result).toMatchSnapshot() + }) + }) +}) \ No newline at end of file diff --git a/packages/algod_client/tests/get_v_2_deltas_round.test.ts b/packages/algod_client/tests/get_v_2_deltas_round.test.ts new file mode 100644 index 00000000..206a15a7 --- /dev/null +++ b/packages/algod_client/tests/get_v_2_deltas_round.test.ts @@ -0,0 +1,20 @@ +import { describe, expect, test } from 'vitest' +import { AlgodClient } from '../src/client' +import { config, TEST_ROUND } from './config' + +describe('GET v2_deltas_ROUND', () => { + // Polytest Suite: GET v2_deltas_ROUND + + describe('Common Tests', () => { + // Polytest Group: Common Tests + + // TODO: Fix msgpack response handling in PollyJS mock server + test.skip('Basic request and response validation', async () => { + const client = new AlgodClient(config) + + const result = await client.getLedgerStateDelta(TEST_ROUND) + + expect(result).toMatchSnapshot() + }) + }) +}) \ No newline at end of file diff --git a/packages/algod_client/tests/get_v_2_deltas_round_txn_group.test.ts b/packages/algod_client/tests/get_v_2_deltas_round_txn_group.test.ts new file mode 100644 index 00000000..cebc5c1f --- /dev/null +++ b/packages/algod_client/tests/get_v_2_deltas_round_txn_group.test.ts @@ -0,0 +1,15 @@ +import { expect, test, describe } from "vitest"; + +describe("GET v2_deltas_ROUND_txn_group", () => { + // Polytest Suite: GET v2_deltas_ROUND_txn_group + + describe("Common Tests", () => { + // Polytest Group: Common Tests + + test("Basic request and response validation", () => { + throw new Error("TEST NOT IMPLEMENTED"); + }); + + }); + +}); \ No newline at end of file diff --git a/packages/algod_client/tests/get_v_2_deltas_txn_group_id.test.ts b/packages/algod_client/tests/get_v_2_deltas_txn_group_id.test.ts new file mode 100644 index 00000000..8d57195b --- /dev/null +++ b/packages/algod_client/tests/get_v_2_deltas_txn_group_id.test.ts @@ -0,0 +1,15 @@ +import { expect, test, describe } from "vitest"; + +describe("GET v2_deltas_txn_group_ID", () => { + // Polytest Suite: GET v2_deltas_txn_group_ID + + describe("Common Tests", () => { + // Polytest Group: Common Tests + + test("Basic request and response validation", () => { + throw new Error("TEST NOT IMPLEMENTED"); + }); + + }); + +}); \ No newline at end of file diff --git a/packages/algod_client/tests/get_v_2_devmode_blocks_offset.test.ts b/packages/algod_client/tests/get_v_2_devmode_blocks_offset.test.ts new file mode 100644 index 00000000..7ea354d1 --- /dev/null +++ b/packages/algod_client/tests/get_v_2_devmode_blocks_offset.test.ts @@ -0,0 +1,21 @@ +import { describe, expect, test } from 'vitest' +import { AlgodClient } from '../src/client' +import { localnetConfig } from './config' + +describe('GET v2_devmode_blocks_offset', () => { + // Polytest Suite: GET v2_devmode_blocks_offset + + describe('Common Tests', () => { + // Polytest Group: Common Tests + + test('Basic request and response validation', async () => { + const client = new AlgodClient(localnetConfig) + + const result = await client.getBlockTimeStampOffset() + + expect(result).toMatchSnapshot() + expect(result).toHaveProperty('offset') + expect(typeof result.offset).toBe('number') + }) + }) +}) \ No newline at end of file diff --git a/packages/algod_client/tests/get_v_2_experimental.test.ts b/packages/algod_client/tests/get_v_2_experimental.test.ts new file mode 100644 index 00000000..695cba58 --- /dev/null +++ b/packages/algod_client/tests/get_v_2_experimental.test.ts @@ -0,0 +1,15 @@ +import { expect, test, describe } from "vitest"; + +describe("GET v2_experimental", () => { + // Polytest Suite: GET v2_experimental + + describe("Common Tests", () => { + // Polytest Group: Common Tests + + test("Basic request and response validation", () => { + throw new Error("TEST NOT IMPLEMENTED"); + }); + + }); + +}); \ No newline at end of file diff --git a/packages/algod_client/tests/get_v_2_ledger_supply.test.ts b/packages/algod_client/tests/get_v_2_ledger_supply.test.ts new file mode 100644 index 00000000..c2ca2ce1 --- /dev/null +++ b/packages/algod_client/tests/get_v_2_ledger_supply.test.ts @@ -0,0 +1,19 @@ +import { describe, expect, test } from 'vitest' +import { AlgodClient } from '../src/client' +import { config } from './config' + +describe('GET v2_ledger_supply', () => { + // Polytest Suite: GET v2_ledger_supply + + describe('Common Tests', () => { + // Polytest Group: Common Tests + + test('Basic request and response validation', async () => { + const client = new AlgodClient(config) + + const result = await client.getSupply() + + expect(result).toMatchSnapshot() + }) + }) +}) \ No newline at end of file diff --git a/packages/algod_client/tests/get_v_2_ledger_sync.test.ts b/packages/algod_client/tests/get_v_2_ledger_sync.test.ts new file mode 100644 index 00000000..1c1f4e04 --- /dev/null +++ b/packages/algod_client/tests/get_v_2_ledger_sync.test.ts @@ -0,0 +1,19 @@ +import { describe, expect, test } from 'vitest' +import { AlgodClient } from '../src/client' +import { config } from './config' + +describe('GET v2_ledger_sync', () => { + // Polytest Suite: GET v2_ledger_sync + + describe('Common Tests', () => { + // Polytest Group: Common Tests + + test('Basic request and response validation', async () => { + const client = new AlgodClient(config) + + const result = await client.getSyncRound() + + expect(result).toMatchSnapshot() + }) + }) +}) \ No newline at end of file diff --git a/packages/algod_client/tests/get_v_2_participation.test.ts b/packages/algod_client/tests/get_v_2_participation.test.ts new file mode 100644 index 00000000..fe7107dc --- /dev/null +++ b/packages/algod_client/tests/get_v_2_participation.test.ts @@ -0,0 +1,14 @@ +import { describe, test } from 'vitest' + +describe('GET v2_participation', () => { + // Polytest Suite: GET v2_participation + + describe('Common Tests', () => { + // Polytest Group: Common Tests + + // Skipping: This test requires mocking from the mock server + test.skip('Basic request and response validation', () => { + throw new Error('TEST NOT IMPLEMENTED') + }) + }) +}) diff --git a/packages/algod_client/tests/get_v_2_participation_participation_id.test.ts b/packages/algod_client/tests/get_v_2_participation_participation_id.test.ts new file mode 100644 index 00000000..044765ff --- /dev/null +++ b/packages/algod_client/tests/get_v_2_participation_participation_id.test.ts @@ -0,0 +1,14 @@ +import { describe, test } from 'vitest' + +describe('GET v2_participation_PARTICIPATION-ID', () => { + // Polytest Suite: GET v2_participation_PARTICIPATION-ID + + describe('Common Tests', () => { + // Polytest Group: Common Tests + + // Skipping: This test requires mocking from the mock server + test.skip('Basic request and response validation', () => { + throw new Error('TEST NOT IMPLEMENTED') + }) + }) +}) diff --git a/packages/algod_client/tests/get_v_2_stateproofs_round.test.ts b/packages/algod_client/tests/get_v_2_stateproofs_round.test.ts new file mode 100644 index 00000000..84c26340 --- /dev/null +++ b/packages/algod_client/tests/get_v_2_stateproofs_round.test.ts @@ -0,0 +1,15 @@ +import { expect, test, describe } from "vitest"; + +describe("GET v2_stateproofs_ROUND", () => { + // Polytest Suite: GET v2_stateproofs_ROUND + + describe("Common Tests", () => { + // Polytest Group: Common Tests + + test("Basic request and response validation", () => { + throw new Error("TEST NOT IMPLEMENTED"); + }); + + }); + +}); \ No newline at end of file diff --git a/packages/algod_client/tests/get_v_2_status.test.ts b/packages/algod_client/tests/get_v_2_status.test.ts new file mode 100644 index 00000000..3fd27b2c --- /dev/null +++ b/packages/algod_client/tests/get_v_2_status.test.ts @@ -0,0 +1,19 @@ +import { describe, expect, test } from 'vitest' +import { AlgodClient } from '../src/client' +import { config } from './config' + +describe('GET v2_status', () => { + // Polytest Suite: GET v2_status + + describe('Common Tests', () => { + // Polytest Group: Common Tests + + test('Basic request and response validation', async () => { + const client = new AlgodClient(config) + + const result = await client.getStatus() + + expect(result).toMatchSnapshot() + }) + }) +}) diff --git a/packages/algod_client/tests/get_v_2_status_wait_for_block_after_round.test.ts b/packages/algod_client/tests/get_v_2_status_wait_for_block_after_round.test.ts new file mode 100644 index 00000000..257908fe --- /dev/null +++ b/packages/algod_client/tests/get_v_2_status_wait_for_block_after_round.test.ts @@ -0,0 +1,19 @@ +import { describe, expect, test } from 'vitest' +import { AlgodClient } from '../src/client' +import { config, TEST_ROUND } from './config' + +describe('GET v2_status_wait-for-block-after_ROUND', () => { + // Polytest Suite: GET v2_status_wait-for-block-after_ROUND + + describe('Common Tests', () => { + // Polytest Group: Common Tests + + test('Basic request and response validation', async () => { + const client = new AlgodClient(config) + + const result = await client.waitForBlock(TEST_ROUND) + + expect(result).toMatchSnapshot() + }) + }) +}) \ No newline at end of file diff --git a/packages/algod_client/tests/get_v_2_transactions_params.test.ts b/packages/algod_client/tests/get_v_2_transactions_params.test.ts new file mode 100644 index 00000000..cfd14d33 --- /dev/null +++ b/packages/algod_client/tests/get_v_2_transactions_params.test.ts @@ -0,0 +1,19 @@ +import { describe, expect, test } from 'vitest' +import { AlgodClient } from '../src/client' +import { config } from './config' + +describe('GET v2_transactions_params', () => { + // Polytest Suite: GET v2_transactions_params + + describe('Common Tests', () => { + // Polytest Group: Common Tests + + test('Basic request and response validation', async () => { + const client = new AlgodClient(config) + + const result = await client.getTransactionParams() + + expect(result).toMatchSnapshot() + }) + }) +}) \ No newline at end of file diff --git a/packages/algod_client/tests/get_v_2_transactions_pending.test.ts b/packages/algod_client/tests/get_v_2_transactions_pending.test.ts new file mode 100644 index 00000000..95a8e23d --- /dev/null +++ b/packages/algod_client/tests/get_v_2_transactions_pending.test.ts @@ -0,0 +1,20 @@ +import { describe, expect, test } from 'vitest' +import { AlgodClient } from '../src/client' +import { config } from './config' + +describe('GET v2_transactions_pending', () => { + // Polytest Suite: GET v2_transactions_pending + + describe('Common Tests', () => { + // Polytest Group: Common Tests + + // TODO: Fix msgpack response handling in PollyJS mock server + test.skip('Basic request and response validation', async () => { + const client = new AlgodClient(config) + + const result = await client.getPendingTransactions() + + expect(result).toMatchSnapshot() + }) + }) +}) \ No newline at end of file diff --git a/packages/algod_client/tests/get_v_2_transactions_pending_txid.test.ts b/packages/algod_client/tests/get_v_2_transactions_pending_txid.test.ts new file mode 100644 index 00000000..bb11f389 --- /dev/null +++ b/packages/algod_client/tests/get_v_2_transactions_pending_txid.test.ts @@ -0,0 +1,15 @@ +import { expect, test, describe } from "vitest"; + +describe("GET v2_transactions_pending_TXID", () => { + // Polytest Suite: GET v2_transactions_pending_TXID + + describe("Common Tests", () => { + // Polytest Group: Common Tests + + test("Basic request and response validation", () => { + throw new Error("TEST NOT IMPLEMENTED"); + }); + + }); + +}); \ No newline at end of file diff --git a/packages/algod_client/tests/get_versions.test.ts b/packages/algod_client/tests/get_versions.test.ts new file mode 100644 index 00000000..7b6d7312 --- /dev/null +++ b/packages/algod_client/tests/get_versions.test.ts @@ -0,0 +1,19 @@ +import { describe, expect, test } from 'vitest' +import { AlgodClient } from '../src/client' +import { config } from './config' + +describe('GET versions', () => { + // Polytest Suite: GET versions + + describe('Common Tests', () => { + // Polytest Group: Common Tests + + test('Basic request and response validation', async () => { + const client = new AlgodClient(config) + + const result = await client.getVersion() + + expect(result).toMatchSnapshot() + }) + }) +}) \ No newline at end of file diff --git a/packages/algod_client/tests/post_v_2_catchup_catchpoint.test.ts b/packages/algod_client/tests/post_v_2_catchup_catchpoint.test.ts new file mode 100644 index 00000000..6d875514 --- /dev/null +++ b/packages/algod_client/tests/post_v_2_catchup_catchpoint.test.ts @@ -0,0 +1,19 @@ +import { expect, test, describe } from "vitest"; + +describe("POST v2_catchup_CATCHPOINT", () => { + // Polytest Suite: POST v2_catchup_CATCHPOINT + + describe("Common Tests", () => { + // Polytest Group: Common Tests + + // Skipped: The startCatchup() method has not been implemented in api.service.ts yet. + // This endpoint requires implementing: + // 1. CatchupStart response model in src/models/catchup-start.ts + // 2. startCatchup(catchpoint: string, params?: { min?: number }) method in src/apis/api.service.ts + test.skip("Basic request and response validation", () => { + throw new Error("TEST NOT IMPLEMENTED"); + }); + + }); + +}); \ No newline at end of file diff --git a/packages/algod_client/tests/post_v_2_devmode_blocks_offset_offset.test.ts b/packages/algod_client/tests/post_v_2_devmode_blocks_offset_offset.test.ts new file mode 100644 index 00000000..1fe37436 --- /dev/null +++ b/packages/algod_client/tests/post_v_2_devmode_blocks_offset_offset.test.ts @@ -0,0 +1,46 @@ +import { describe, expect, test } from 'vitest' +import { AlgodClient } from '../src/client' +import { localnetConfig } from './config' + +describe('POST v2_devmode_blocks_offset_OFFSET', () => { + // Polytest Suite: POST v2_devmode_blocks_offset_OFFSET + + describe('Common Tests', () => { + // Polytest Group: Common Tests + + test('Basic request and response validation', async () => { + const client = new AlgodClient(localnetConfig) + + // Set a timestamp offset of 60 seconds + const result = await client.setBlockTimeStampOffset(60) + + // Should return void (undefined) + expect(result).toMatchSnapshot() + expect(result).toBeUndefined() + }) + + test('Set offset and verify with GET', async () => { + const client = new AlgodClient(localnetConfig) + + // Set offset to 100 seconds + await client.setBlockTimeStampOffset(100) + + // Verify it was set by reading it back + const currentOffset = await client.getBlockTimeStampOffset() + expect(currentOffset.offset).toBe(100) + }) + + test('Unset offset with zero', async () => { + const client = new AlgodClient(localnetConfig) + + // Offset of 0 unsets the value and uses real clock + const result = await client.setBlockTimeStampOffset(0) + + expect(result).toBeUndefined() + + // Verify it was unset + const currentOffset = await client.getBlockTimeStampOffset() + expect(currentOffset.offset).toBe(0) + }) + }) +}) diff --git a/packages/algod_client/tests/post_v_2_ledger_sync_round.test.ts b/packages/algod_client/tests/post_v_2_ledger_sync_round.test.ts new file mode 100644 index 00000000..696d7cf6 --- /dev/null +++ b/packages/algod_client/tests/post_v_2_ledger_sync_round.test.ts @@ -0,0 +1,53 @@ +import { describe, expect, test } from 'vitest' +import { AlgodClient } from '../src/client' +import { localnetConfig } from './config' + +describe('POST v2_ledger_sync_ROUND', () => { + // Polytest Suite: POST v2_ledger_sync_ROUND + + describe('Common Tests', () => { + // Polytest Group: Common Tests + + // Skipped: The POST /v2/ledger/sync/{round} endpoint requires algod to run in follower mode. + // Standard localnet does not have follower mode enabled by default. + // To enable follower mode: algod -f -d + test.skip('Basic request and response validation', async () => { + const client = new AlgodClient(localnetConfig) + + // Set sync round to 1000 + const result = await client.setSyncRound(1000) + + // Should return void (undefined) + expect(result).toMatchSnapshot() + expect(result).toBeUndefined() + }) + + // Skipped: The POST /v2/ledger/sync/{round} endpoint requires algod to run in follower mode. + // Standard localnet does not have follower mode enabled by default. + // To enable follower mode: algod -f -d + test.skip('Set sync round and verify with GET', async () => { + const client = new AlgodClient(localnetConfig) + + // Set sync round to 5000 + await client.setSyncRound(5000) + + // Verify it was set by reading it back + const syncRound = await client.getSyncRound() + expect(syncRound.round).toBe(5000n) + }) + + // Skipped: The POST /v2/ledger/sync/{round} endpoint requires algod to run in follower mode. + // Standard localnet does not have follower mode enabled by default. + // To enable follower mode: algod -f -d + test.skip('Set sync round with bigint', async () => { + const client = new AlgodClient(localnetConfig) + + // Test with bigint parameter + await client.setSyncRound(10000n) + + // Verify it was set + const syncRound = await client.getSyncRound() + expect(syncRound.round).toBe(10000n) + }) + }) +}) \ No newline at end of file diff --git a/packages/algod_client/tests/post_v_2_participation.test.ts b/packages/algod_client/tests/post_v_2_participation.test.ts new file mode 100644 index 00000000..2ac5de24 --- /dev/null +++ b/packages/algod_client/tests/post_v_2_participation.test.ts @@ -0,0 +1,15 @@ +import { expect, test, describe } from "vitest"; + +describe("POST v2_participation", () => { + // Polytest Suite: POST v2_participation + + describe("Common Tests", () => { + // Polytest Group: Common Tests + + test("Basic request and response validation", () => { + throw new Error("TEST NOT IMPLEMENTED"); + }); + + }); + +}); \ No newline at end of file diff --git a/packages/algod_client/tests/post_v_2_participation_generate_address.test.ts b/packages/algod_client/tests/post_v_2_participation_generate_address.test.ts new file mode 100644 index 00000000..69544ccc --- /dev/null +++ b/packages/algod_client/tests/post_v_2_participation_generate_address.test.ts @@ -0,0 +1,15 @@ +import { expect, test, describe } from "vitest"; + +describe("POST v2_participation_generate_ADDRESS", () => { + // Polytest Suite: POST v2_participation_generate_ADDRESS + + describe("Common Tests", () => { + // Polytest Group: Common Tests + + test("Basic request and response validation", () => { + throw new Error("TEST NOT IMPLEMENTED"); + }); + + }); + +}); \ No newline at end of file diff --git a/packages/algod_client/tests/post_v_2_participation_participation_id.test.ts b/packages/algod_client/tests/post_v_2_participation_participation_id.test.ts new file mode 100644 index 00000000..f76d05e4 --- /dev/null +++ b/packages/algod_client/tests/post_v_2_participation_participation_id.test.ts @@ -0,0 +1,15 @@ +import { expect, test, describe } from "vitest"; + +describe("POST v2_participation_PARTICIPATION-ID", () => { + // Polytest Suite: POST v2_participation_PARTICIPATION-ID + + describe("Common Tests", () => { + // Polytest Group: Common Tests + + test("Basic request and response validation", () => { + throw new Error("TEST NOT IMPLEMENTED"); + }); + + }); + +}); \ No newline at end of file diff --git a/packages/algod_client/tests/post_v_2_shutdown.test.ts b/packages/algod_client/tests/post_v_2_shutdown.test.ts new file mode 100644 index 00000000..009a1d11 --- /dev/null +++ b/packages/algod_client/tests/post_v_2_shutdown.test.ts @@ -0,0 +1,15 @@ +import { expect, test, describe } from "vitest"; + +describe("POST v2_shutdown", () => { + // Polytest Suite: POST v2_shutdown + + describe("Common Tests", () => { + // Polytest Group: Common Tests + + test("Basic request and response validation", () => { + throw new Error("TEST NOT IMPLEMENTED"); + }); + + }); + +}); \ No newline at end of file diff --git a/packages/algod_client/tests/post_v_2_teal_compile.test.ts b/packages/algod_client/tests/post_v_2_teal_compile.test.ts new file mode 100644 index 00000000..c282df77 --- /dev/null +++ b/packages/algod_client/tests/post_v_2_teal_compile.test.ts @@ -0,0 +1,15 @@ +import { expect, test, describe } from "vitest"; + +describe("POST v2_teal_compile", () => { + // Polytest Suite: POST v2_teal_compile + + describe("Common Tests", () => { + // Polytest Group: Common Tests + + test("Basic request and response validation", () => { + throw new Error("TEST NOT IMPLEMENTED"); + }); + + }); + +}); \ No newline at end of file diff --git a/packages/algod_client/tests/post_v_2_teal_disassemble.test.ts b/packages/algod_client/tests/post_v_2_teal_disassemble.test.ts new file mode 100644 index 00000000..c899322a --- /dev/null +++ b/packages/algod_client/tests/post_v_2_teal_disassemble.test.ts @@ -0,0 +1,15 @@ +import { expect, test, describe } from "vitest"; + +describe("POST v2_teal_disassemble", () => { + // Polytest Suite: POST v2_teal_disassemble + + describe("Common Tests", () => { + // Polytest Group: Common Tests + + test("Basic request and response validation", () => { + throw new Error("TEST NOT IMPLEMENTED"); + }); + + }); + +}); \ No newline at end of file diff --git a/packages/algod_client/tests/post_v_2_teal_dryrun.test.ts b/packages/algod_client/tests/post_v_2_teal_dryrun.test.ts new file mode 100644 index 00000000..a66a3916 --- /dev/null +++ b/packages/algod_client/tests/post_v_2_teal_dryrun.test.ts @@ -0,0 +1,15 @@ +import { expect, test, describe } from "vitest"; + +describe("POST v2_teal_dryrun", () => { + // Polytest Suite: POST v2_teal_dryrun + + describe("Common Tests", () => { + // Polytest Group: Common Tests + + test("Basic request and response validation", () => { + throw new Error("TEST NOT IMPLEMENTED"); + }); + + }); + +}); \ No newline at end of file diff --git a/packages/algod_client/tests/post_v_2_transactions.test.ts b/packages/algod_client/tests/post_v_2_transactions.test.ts new file mode 100644 index 00000000..7836177b --- /dev/null +++ b/packages/algod_client/tests/post_v_2_transactions.test.ts @@ -0,0 +1,15 @@ +import { expect, test, describe } from "vitest"; + +describe("POST v2_transactions", () => { + // Polytest Suite: POST v2_transactions + + describe("Common Tests", () => { + // Polytest Group: Common Tests + + test("Basic request and response validation", () => { + throw new Error("TEST NOT IMPLEMENTED"); + }); + + }); + +}); \ No newline at end of file diff --git a/packages/algod_client/tests/post_v_2_transactions_async.test.ts b/packages/algod_client/tests/post_v_2_transactions_async.test.ts new file mode 100644 index 00000000..adb5df95 --- /dev/null +++ b/packages/algod_client/tests/post_v_2_transactions_async.test.ts @@ -0,0 +1,15 @@ +import { expect, test, describe } from "vitest"; + +describe("POST v2_transactions_async", () => { + // Polytest Suite: POST v2_transactions_async + + describe("Common Tests", () => { + // Polytest Group: Common Tests + + test("Basic request and response validation", () => { + throw new Error("TEST NOT IMPLEMENTED"); + }); + + }); + +}); \ No newline at end of file diff --git a/packages/algod_client/tests/post_v_2_transactions_simulate.test.ts b/packages/algod_client/tests/post_v_2_transactions_simulate.test.ts new file mode 100644 index 00000000..710ee7c6 --- /dev/null +++ b/packages/algod_client/tests/post_v_2_transactions_simulate.test.ts @@ -0,0 +1,15 @@ +import { expect, test, describe } from "vitest"; + +describe("POST v2_transactions_simulate", () => { + // Polytest Suite: POST v2_transactions_simulate + + describe("Common Tests", () => { + // Polytest Group: Common Tests + + test("Basic request and response validation", () => { + throw new Error("TEST NOT IMPLEMENTED"); + }); + + }); + +}); \ No newline at end of file diff --git a/packages/algod_client/tests/put_debug_settings_pprof.test.ts b/packages/algod_client/tests/put_debug_settings_pprof.test.ts new file mode 100644 index 00000000..c181a60b --- /dev/null +++ b/packages/algod_client/tests/put_debug_settings_pprof.test.ts @@ -0,0 +1,15 @@ +import { expect, test, describe } from "vitest"; + +describe("PUT debug_settings_pprof", () => { + // Polytest Suite: PUT debug_settings_pprof + + describe("Common Tests", () => { + // Polytest Group: Common Tests + + test("Basic request and response validation", () => { + throw new Error("TEST NOT IMPLEMENTED"); + }); + + }); + +}); \ No newline at end of file diff --git a/packages/indexer_client/src/apis/api.service.ts b/packages/indexer_client/src/apis/api.service.ts index a287be65..e87a2244 100644 --- a/packages/indexer_client/src/apis/api.service.ts +++ b/packages/indexer_client/src/apis/api.service.ts @@ -70,7 +70,7 @@ export class IndexerApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = IndexerApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/accounts/{account-id}/apps-local-state', path: { 'account-id': accountId }, @@ -85,11 +85,7 @@ export class IndexerApi { mediaType: undefined, }) - const responseMeta = LookupAccountAppLocalStatesMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as LookupAccountAppLocalStates + return AlgorandSerializer.decode(payload, LookupAccountAppLocalStatesMeta, responseFormat) } /** @@ -103,7 +99,7 @@ export class IndexerApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = IndexerApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/accounts/{account-id}/assets', path: { 'account-id': accountId }, @@ -118,11 +114,7 @@ export class IndexerApi { mediaType: undefined, }) - const responseMeta = LookupAccountAssetsMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as LookupAccountAssets + return AlgorandSerializer.decode(payload, LookupAccountAssetsMeta, responseFormat) } /** @@ -140,7 +132,7 @@ export class IndexerApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = IndexerApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/accounts/{account-id}', path: { 'account-id': accountId }, @@ -154,11 +146,7 @@ export class IndexerApi { mediaType: undefined, }) - const responseMeta = LookupAccountByIdMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as LookupAccountById + return AlgorandSerializer.decode(payload, LookupAccountByIdMeta, responseFormat) } /** @@ -172,7 +160,7 @@ export class IndexerApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = IndexerApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/accounts/{account-id}/created-applications', path: { 'account-id': accountId }, @@ -187,11 +175,7 @@ export class IndexerApi { mediaType: undefined, }) - const responseMeta = LookupAccountCreatedApplicationsMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as LookupAccountCreatedApplications + return AlgorandSerializer.decode(payload, LookupAccountCreatedApplicationsMeta, responseFormat) } /** @@ -205,7 +189,7 @@ export class IndexerApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = IndexerApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/accounts/{account-id}/created-assets', path: { 'account-id': accountId }, @@ -220,11 +204,7 @@ export class IndexerApi { mediaType: undefined, }) - const responseMeta = LookupAccountCreatedAssetsMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as LookupAccountCreatedAssets + return AlgorandSerializer.decode(payload, LookupAccountCreatedAssetsMeta, responseFormat) } /** @@ -254,7 +234,7 @@ export class IndexerApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = IndexerApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/accounts/{account-id}/transactions', path: { 'account-id': accountId }, @@ -284,11 +264,7 @@ export class IndexerApi { mediaType: undefined, }) - const responseMeta = LookupAccountTransactionsMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as LookupAccountTransactions + return AlgorandSerializer.decode(payload, LookupAccountTransactionsMeta, responseFormat) } /** @@ -299,7 +275,7 @@ export class IndexerApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = IndexerApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/applications/{application-id}/box', path: { 'application-id': typeof applicationId === 'bigint' ? applicationId.toString() : applicationId }, @@ -309,11 +285,7 @@ export class IndexerApi { mediaType: undefined, }) - const responseMeta = BoxMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as Box + return AlgorandSerializer.decode(payload, BoxMeta, responseFormat) } /** @@ -324,7 +296,7 @@ export class IndexerApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = IndexerApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/applications/{application-id}', path: { 'application-id': typeof applicationId === 'bigint' ? applicationId.toString() : applicationId }, @@ -334,11 +306,7 @@ export class IndexerApi { mediaType: undefined, }) - const responseMeta = LookupApplicationByIdMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as LookupApplicationById + return AlgorandSerializer.decode(payload, LookupApplicationByIdMeta, responseFormat) } /** @@ -359,7 +327,7 @@ export class IndexerApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = IndexerApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/applications/{application-id}/logs', path: { 'application-id': typeof applicationId === 'bigint' ? applicationId.toString() : applicationId }, @@ -376,11 +344,7 @@ export class IndexerApi { mediaType: undefined, }) - const responseMeta = LookupApplicationLogsByIdMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as LookupApplicationLogsById + return AlgorandSerializer.decode(payload, LookupApplicationLogsByIdMeta, responseFormat) } /** @@ -400,7 +364,7 @@ export class IndexerApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = IndexerApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/assets/{asset-id}/balances', path: { 'asset-id': typeof assetId === 'bigint' ? assetId.toString() : assetId }, @@ -420,11 +384,7 @@ export class IndexerApi { mediaType: undefined, }) - const responseMeta = LookupAssetBalancesMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as LookupAssetBalances + return AlgorandSerializer.decode(payload, LookupAssetBalancesMeta, responseFormat) } /** @@ -435,7 +395,7 @@ export class IndexerApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = IndexerApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/assets/{asset-id}', path: { 'asset-id': typeof assetId === 'bigint' ? assetId.toString() : assetId }, @@ -445,11 +405,7 @@ export class IndexerApi { mediaType: undefined, }) - const responseMeta = LookupAssetByIdMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as LookupAssetById + return AlgorandSerializer.decode(payload, LookupAssetByIdMeta, responseFormat) } /** @@ -481,7 +437,7 @@ export class IndexerApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = IndexerApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/assets/{asset-id}/transactions', path: { 'asset-id': typeof assetId === 'bigint' ? assetId.toString() : assetId }, @@ -513,11 +469,7 @@ export class IndexerApi { mediaType: undefined, }) - const responseMeta = LookupAssetTransactionsMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as LookupAssetTransactions + return AlgorandSerializer.decode(payload, LookupAssetTransactionsMeta, responseFormat) } /** @@ -528,7 +480,7 @@ export class IndexerApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = IndexerApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/blocks/{round-number}', path: { 'round-number': typeof roundNumber === 'bigint' ? roundNumber.toString() : roundNumber }, @@ -538,11 +490,7 @@ export class IndexerApi { mediaType: undefined, }) - const responseMeta = BlockMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as Block + return AlgorandSerializer.decode(payload, BlockMeta, responseFormat) } /** @@ -553,7 +501,7 @@ export class IndexerApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = IndexerApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/transactions/{txid}', path: { txid: txid }, @@ -563,11 +511,7 @@ export class IndexerApi { mediaType: undefined, }) - const responseMeta = LookupTransactionMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as LookupTransaction + return AlgorandSerializer.decode(payload, LookupTransactionMeta, responseFormat) } async makeHealthCheck(): Promise { @@ -575,7 +519,7 @@ export class IndexerApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = IndexerApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/health', path: {}, @@ -585,11 +529,7 @@ export class IndexerApi { mediaType: undefined, }) - const responseMeta = HealthCheckMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as HealthCheck + return AlgorandSerializer.decode(payload, HealthCheckMeta, responseFormat) } /** @@ -612,7 +552,7 @@ export class IndexerApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = IndexerApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/accounts', path: {}, @@ -638,11 +578,7 @@ export class IndexerApi { mediaType: undefined, }) - const responseMeta = SearchForAccountsMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as SearchForAccounts + return AlgorandSerializer.decode(payload, SearchForAccountsMeta, responseFormat) } /** @@ -656,7 +592,7 @@ export class IndexerApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = IndexerApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/applications/{application-id}/boxes', path: { 'application-id': typeof applicationId === 'bigint' ? applicationId.toString() : applicationId }, @@ -666,11 +602,7 @@ export class IndexerApi { mediaType: undefined, }) - const responseMeta = SearchForApplicationBoxesMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as SearchForApplicationBoxes + return AlgorandSerializer.decode(payload, SearchForApplicationBoxesMeta, responseFormat) } /** @@ -687,7 +619,7 @@ export class IndexerApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = IndexerApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/applications', path: {}, @@ -703,11 +635,7 @@ export class IndexerApi { mediaType: undefined, }) - const responseMeta = SearchForApplicationsMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as SearchForApplications + return AlgorandSerializer.decode(payload, SearchForApplicationsMeta, responseFormat) } /** @@ -726,7 +654,7 @@ export class IndexerApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = IndexerApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/assets', path: {}, @@ -744,11 +672,7 @@ export class IndexerApi { mediaType: undefined, }) - const responseMeta = SearchForAssetsMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as SearchForAssets + return AlgorandSerializer.decode(payload, SearchForAssetsMeta, responseFormat) } /** @@ -769,7 +693,7 @@ export class IndexerApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = IndexerApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/block-headers', path: {}, @@ -789,11 +713,7 @@ export class IndexerApi { mediaType: undefined, }) - const responseMeta = SearchForBlockHeadersMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as SearchForBlockHeaders + return AlgorandSerializer.decode(payload, SearchForBlockHeadersMeta, responseFormat) } /** @@ -825,7 +745,7 @@ export class IndexerApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = IndexerApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v2/transactions', path: {}, @@ -860,10 +780,6 @@ export class IndexerApi { mediaType: undefined, }) - const responseMeta = SearchForTransactionsMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as SearchForTransactions + return AlgorandSerializer.decode(payload, SearchForTransactionsMeta, responseFormat) } } diff --git a/packages/indexer_client/src/core/codecs.ts b/packages/indexer_client/src/core/codecs.ts index 829dcd7b..214a543d 100644 --- a/packages/indexer_client/src/core/codecs.ts +++ b/packages/indexer_client/src/core/codecs.ts @@ -1,42 +1,28 @@ import { decode as msgpackDecode, encode as msgpackEncode } from 'algorand-msgpack' -export function encodeMsgPack(data: T): Uint8Array { +export function encodeMsgPack(data: ApiData): Uint8Array { return new Uint8Array(msgpackEncode(data, { sortKeys: true, ignoreUndefined: true })) } -export function decodeMsgPack(buffer: Uint8Array): T { - const map = msgpackDecode(buffer, { useMap: true }) as unknown - return mapToObject(map) as T +type MsgPackDecodeOptions = { + useMap: boolean + rawBinaryStringKeys: boolean + rawBinaryStringValues: boolean } -/** - * Converts a Map structure from msgpack decoding to a plain object structure. - * Maps are converted to objects recursively, except for the special case - * where the field name is "r" which remains as a Map. - */ -function mapToObject(value: unknown, fieldName?: string): unknown { - // Preserve Uint8Array as-is - if (value instanceof Uint8Array) { - return value - } else if (value instanceof Map) { - // Special case: keep "r" field as Map - if (fieldName === 'r') { - const newMap = new Map() - for (const [k, v] of value.entries()) { - newMap.set(k, mapToObject(v)) - } - return newMap - } - - // Convert Map to object - const obj: Record = {} - for (const [k, v] of value.entries()) { - obj[k] = mapToObject(v, k) - } - return obj - } else if (Array.isArray(value)) { - return value.map((item) => mapToObject(item)) - } - - return value +export function decodeMsgPack( + buffer: Uint8Array, + options: MsgPackDecodeOptions = { useMap: true, rawBinaryStringKeys: true, rawBinaryStringValues: true }, +): Map { + return msgpackDecode(buffer, options) as Map } +export type ApiData = + | null + | undefined + | string + | number + | bigint + | boolean + | Uint8Array + | object + | Map // TODO: NC - Do we ever have a string key? diff --git a/packages/indexer_client/src/core/model-runtime.ts b/packages/indexer_client/src/core/model-runtime.ts index ed41c188..07f6d681 100644 --- a/packages/indexer_client/src/core/model-runtime.ts +++ b/packages/indexer_client/src/core/model-runtime.ts @@ -1,19 +1,24 @@ import { - encodeSignedTransaction as transactEncodeSignedTransaction, - decodeSignedTransaction as transactDecodeSignedTransaction, + addressFromPublicKey, + decodedTransactionMapToObject, + fromSignedTransactionDto, + toSignedTransactionDto, type SignedTransaction, } from '@algorandfoundation/algokit-transact' -import { encodeMsgPack, decodeMsgPack } from './codecs' -import { toBase64, fromBase64 } from './serialization' +import { Buffer } from 'buffer' +import { ApiData, decodeMsgPack, encodeMsgPack } from './codecs' export type BodyFormat = 'json' | 'msgpack' | 'map' export interface ScalarFieldType { readonly kind: 'scalar' + // TODO: NC - Make this a type field readonly isBytes?: boolean readonly isBigint?: boolean + readonly isAddress?: boolean } +// TODO: NC - Needs to be renamed export interface CodecFieldType { readonly kind: 'codec' readonly codecKey: string @@ -34,7 +39,13 @@ export interface RecordFieldType { readonly value: FieldType } -export type FieldType = ScalarFieldType | CodecFieldType | ModelFieldType | ArrayFieldType | RecordFieldType +export interface MapFieldType { + readonly kind: 'map' + readonly keyType: 'number' | 'bigint' | 'bytes' + readonly value: FieldType +} + +export type FieldType = ScalarFieldType | CodecFieldType | ModelFieldType | ArrayFieldType | RecordFieldType | MapFieldType export interface FieldMetadata { readonly name: string @@ -61,39 +72,26 @@ export interface ModelMetadata { readonly passThrough?: FieldType } -// Registry for model metadata to avoid direct circular imports between model files -const modelMetaRegistry = new Map() - -export function registerModelMeta(name: string, meta: ModelMetadata): void { - modelMetaRegistry.set(name, meta) -} - -export function getModelMeta(name: string): ModelMetadata { - const meta = modelMetaRegistry.get(name) - if (!meta) throw new Error(`Model metadata not registered: ${name}`) - return meta -} - -export interface TypeCodec { - encode(value: TValue, format: BodyFormat): unknown - decode(value: unknown, format: BodyFormat): TValue +export interface EncodeableTypeConverter> { + beforeEncoding(value: T, format: BodyFormat): Record + afterDecoding(decoded: Record | Map, format: BodyFormat): T } -const codecRegistry = new Map>() - -export function registerCodec(key: string, codec: TypeCodec): void { - codecRegistry.set(key, codec as TypeCodec) -} +const encodeableTypeConverterRegistry = new Map>>() -export function getCodec(key: string): TypeCodec | undefined { - return codecRegistry.get(key) as TypeCodec | undefined +export function registerEncodeableTypeConverter(key: string, codec: EncodeableTypeConverter>): void { + encodeableTypeConverterRegistry.set(key, codec) } export class AlgorandSerializer { - static encode(value: unknown, meta: ModelMetadata, format: 'map'): Map - static encode(value: unknown, meta: ModelMetadata, format: 'json'): string - static encode(value: unknown, meta: ModelMetadata, format?: 'msgpack'): Uint8Array - static encode(value: unknown, meta: ModelMetadata, format: BodyFormat = 'msgpack'): Uint8Array | string | Map { + static encode(value: Record, meta: ModelMetadata, format: 'map'): Map + static encode(value: Record, meta: ModelMetadata, format: 'json'): string + static encode(value: Record, meta: ModelMetadata, format?: 'msgpack'): Uint8Array + static encode( + value: Record, + meta: ModelMetadata, + format: BodyFormat = 'msgpack', + ): Uint8Array | string | Map { if (format === 'map') { // For map format, use msgpack transformation to preserve types like bigint, then convert to nested Maps const wire = this.transform(value, meta, { direction: 'encode', format: 'msgpack' }) @@ -107,25 +105,25 @@ export class AlgorandSerializer { return typeof wire === 'string' ? wire : JSON.stringify(wire) } - static decode(payload: unknown, meta: ModelMetadata, format: BodyFormat = 'msgpack'): T { - let wire: unknown = payload + static decode(value: Uint8Array | string, meta: ModelMetadata, format: BodyFormat = 'msgpack'): T { + let wire: ApiData = value if (format === 'msgpack') { - if (payload instanceof Uint8Array) { - wire = decodeMsgPack(payload) + if (value instanceof Uint8Array) { + wire = decodeMsgPack(value) } - } else if (typeof payload === 'string') { - wire = JSON.parse(payload) + } else if (typeof value === 'string') { + wire = JSON.parse(value) } return this.transform(wire, meta, { direction: 'decode', format }) as T } - private static transform(value: unknown, meta: ModelMetadata, ctx: TransformContext): unknown { + private static transform(value: ApiData, meta: ModelMetadata, ctx: TransformContext): ApiData { if (value === undefined || value === null) { return value } if (meta.codecKey) { - return this.applyCodec(value, meta.codecKey, ctx) + return this.applyEncodeableTypeConversion(value, meta.codecKey, ctx) } switch (meta.kind) { @@ -139,20 +137,20 @@ export class AlgorandSerializer { } } - private static transformObject(value: unknown, meta: ModelMetadata, ctx: TransformContext): unknown { + private static transformObject(value: ApiData, meta: ModelMetadata, ctx: TransformContext): ApiData { const fields = meta.fields ?? [] - const hasFlattenedSignedTxn = fields.some((f) => f.flattened && f.type.kind === 'codec' && f.type.codecKey === 'SignedTransaction') + const hasFlattenedField = fields.some((f) => f.flattened) if (ctx.direction === 'encode') { - const src = value as Record - const out: Record = {} + const src = value as Record + const out: Record = {} for (const field of fields) { const fieldValue = src[field.name] if (fieldValue === undefined) continue const encoded = this.transformType(fieldValue, field.type, ctx) if (encoded === undefined && fieldValue === undefined) continue - if (field.flattened && field.type.kind === 'codec' && field.type.codecKey === 'SignedTransaction') { - // Merge signed transaction map into parent - const mapValue = encoded as Record + if (field.flattened) { + // Merge flattened field into parent + const mapValue = encoded as Record for (const [k, v] of Object.entries(mapValue ?? {})) out[k] = v continue } @@ -167,66 +165,206 @@ export class AlgorandSerializer { return out } - const src = value as Record - const out: Record = {} + // Decoding + const out: Record = {} const fieldByWire = new Map(fields.filter((f) => !!f.wireKey).map((field) => [field.wireKey as string, field])) - for (const [wireKey, wireValue] of Object.entries(src)) { - const field = fieldByWire.get(wireKey) + // Build a map of wire keys for each flattened field + const flattenedFieldWireKeys = new Map>() + if (hasFlattenedField) { + for (const field of fields) { + if (field.flattened && field.type.kind === 'model') { + const modelMeta = typeof field.type.meta === 'function' ? field.type.meta() : field.type.meta + const wireKeys = this.collectWireKeys(modelMeta) + flattenedFieldWireKeys.set(field, wireKeys) + } + } + } + + const entries = value instanceof Map ? Array.from(value.entries()) : Object.entries(value as Record) + const unmatchedEntries = new Map() + + for (const [key, wireValue] of entries) { + const wireKey = key instanceof Uint8Array ? Buffer.from(key).toString('utf-8') : key + const isStringKey = typeof wireKey === 'string' + const field = isStringKey ? fieldByWire.get(wireKey) : undefined + if (field) { const decoded = this.transformType(wireValue, field.type, ctx) - out[field.name] = decoded + out[field.name] = decoded === null && !field.nullable ? undefined : decoded continue } - if (meta.additionalProperties) { + + if (isStringKey && meta.additionalProperties) { out[wireKey] = this.transformType(wireValue, meta.additionalProperties, ctx) continue } - // If we have a flattened SignedTransaction, skip unknown keys (e.g., 'sig', 'txn') - if (!hasFlattenedSignedTxn) { - out[wireKey] = wireValue + + // Store unmatched entries for potential flattened field reconstruction + if (isStringKey) { + unmatchedEntries.set(wireKey, wireValue) + } + } + + // Reconstruct flattened fields from unmatched entries + if (hasFlattenedField) { + for (const field of fields) { + if (out[field.name] !== undefined) continue + if (field.flattened) { + if (field.type.kind === 'codec') { + // Reconstruct codec from entire object map + out[field.name] = this.applyEncodeableTypeConversion(value, field.type.codecKey, ctx) + } else if (field.type.kind === 'model') { + const modelMeta = typeof field.type.meta === 'function' ? field.type.meta() : field.type.meta + + // Check if this flattened model contains nested flattened codecs + const hasNestedCodec = this.hasNestedFlattenedCodec(modelMeta) + + let decoded: ApiData + if (hasNestedCodec) { + // If the model has nested flattened codecs, we need to pass the original value + // so the nested model can reconstruct its flattened codec fields + decoded = this.transform(value, modelMeta, ctx) + } else { + // Filter the wire data to only include keys belonging to this flattened model + const modelWireKeys = flattenedFieldWireKeys.get(field) + if (modelWireKeys) { + const filteredData: Record = {} + for (const [k, v] of unmatchedEntries.entries()) { + if (modelWireKeys.has(k)) { + filteredData[k] = v + } + } + // Also check if the original value is a Map and filter it + if (value instanceof Map) { + const filteredMap = new Map() + for (const [k, v] of value.entries()) { + const keyStr = k instanceof Uint8Array ? Buffer.from(k).toString('utf-8') : String(k) + if (typeof keyStr === 'string' && modelWireKeys.has(keyStr)) { + filteredMap.set(k as string | Uint8Array, v) + } + } + decoded = this.transform(filteredMap, modelMeta, ctx) + } else { + decoded = this.transform(filteredData, modelMeta, ctx) + } + } else { + decoded = undefined + } + } + + // If the field is optional and the decoded object is empty, set it to undefined + if (field.optional && decoded !== undefined && this.isEmptyObject(decoded)) { + out[field.name] = undefined + } else { + out[field.name] = decoded + } + } + } } } - // If there are flattened fields, attempt to reconstruct them from remaining keys by decoding - for (const field of fields) { - if (out[field.name] !== undefined) continue - if (field.flattened && field.type.kind === 'codec' && field.type.codecKey === 'SignedTransaction') { - // Reconstruct from entire object map - out[field.name] = this.applyCodec(src, 'SignedTransaction', ctx) + // Add any remaining unmatched entries if there are no flattened fields + if (!hasFlattenedField) { + for (const [k, v] of unmatchedEntries.entries()) { + out[k] = v } } return out } - private static transformType(value: unknown, type: FieldType, ctx: TransformContext): unknown { + private static collectWireKeys(meta: ModelMetadata): Set { + const wireKeys = new Set() + if (meta.kind !== 'object' || !meta.fields) return wireKeys + + for (const field of meta.fields) { + if (field.wireKey) { + wireKeys.add(field.wireKey) + } + if (field.flattened && field.type.kind === 'model') { + const childMeta = typeof field.type.meta === 'function' ? field.type.meta() : field.type.meta + const childKeys = this.collectWireKeys(childMeta) + for (const key of childKeys) { + wireKeys.add(key) + } + } + // Note: flattened codec fields don't have predictable wire keys, + // so they need to be handled differently during reconstruction + } + + return wireKeys + } + + private static hasNestedFlattenedCodec(meta: ModelMetadata): boolean { + if (meta.kind !== 'object' || !meta.fields) return false + + for (const field of meta.fields) { + if (field.flattened) { + if (field.type.kind === 'codec') { + return true + } + if (field.type.kind === 'model') { + const childMeta = typeof field.type.meta === 'function' ? field.type.meta() : field.type.meta + if (this.hasNestedFlattenedCodec(childMeta)) { + return true + } + } + } + } + + return false + } + + private static isEmptyObject(value: ApiData): boolean { + if (value === null || value === undefined) return true + if (typeof value !== 'object') return false + if (Array.isArray(value)) return false + if (value instanceof Uint8Array) return false + if (value instanceof Map) return value.size === 0 + + // Check if it's a plain object with no own properties (excluding undefined values) + const keys = Object.keys(value) + if (keys.length === 0) return true + + // Check if all properties are undefined + return keys.every((key) => (value as Record)[key] === undefined) + } + + private static transformType(value: ApiData, type: FieldType, ctx: TransformContext): ApiData { if (value === undefined || value === null) return value switch (type.kind) { case 'scalar': return this.transformScalar(value, type, ctx) case 'codec': - return this.applyCodec(value, type.codecKey, ctx) + return this.applyEncodeableTypeConversion(value, type.codecKey, ctx) case 'model': return this.transform(value, typeof type.meta === 'function' ? type.meta() : type.meta, ctx) case 'array': if (!Array.isArray(value)) return value return value.map((item) => this.transformType(item, type.item, ctx)) - case 'record': - if (typeof value !== 'object' || value === null) return value + case 'record': { + if ((!(value instanceof Map) && typeof value !== 'object') || value === null) return value + const entries = value instanceof Map ? Array.from(value.entries()) : Object.entries(value as Record) return Object.fromEntries( - Object.entries(value as Record).map(([k, v]) => [k, this.transformType(v, type.value, ctx)]), + entries.map(([k, v]) => { + const key = k instanceof Uint8Array ? Buffer.from(k).toString('utf-8') : k + return [key, this.transformType(v, type.value, ctx)] + }), ) + } + case 'map': + return this.transformMap(value, type, ctx) default: return value } } - private static transformScalar(value: unknown, meta: ScalarFieldType, ctx: TransformContext): unknown { + private static transformScalar(value: ApiData, meta: ScalarFieldType, ctx: TransformContext): ApiData { if (ctx.direction === 'encode') { if (meta.isBytes && ctx.format === 'json') { - if (value instanceof Uint8Array) return toBase64(value) + if (value instanceof Uint8Array) return Buffer.from(value).toString('base64') } if (meta.isBigint && ctx.format === 'json') { if (typeof value === 'bigint') return value.toString() @@ -237,7 +375,17 @@ export class AlgorandSerializer { } if (meta.isBytes && ctx.format === 'json' && typeof value === 'string') { - return fromBase64(value) + return new Uint8Array(Buffer.from(value, 'base64')) + } + + if (value instanceof Uint8Array) { + if (meta.isAddress) { + // TODO: NC - Fix all the address models to have this on it. + return addressFromPublicKey(value) + } else if (!meta.isBytes) { + return Buffer.from(value).toString('utf-8') + } + return value } if (meta.isBigint) { @@ -253,18 +401,61 @@ export class AlgorandSerializer { } } + if (value instanceof Map) { + const out: Record = {} + for (const [k, v] of value.entries()) { + const key = k instanceof Uint8Array ? Buffer.from(k).toString('utf-8') : k.toString() + out[key] = this.transformType(v, { kind: 'scalar', isBytes: v instanceof Uint8Array }, ctx) + } + return out + } + + if (Array.isArray(value)) { + return value.map((item) => this.transformType(item, { kind: 'scalar', isBytes: item instanceof Uint8Array }, ctx)) + } + return value } - private static applyCodec(value: unknown, codecKey: string, ctx: TransformContext): unknown { - const codec = codecRegistry.get(codecKey) + private static applyEncodeableTypeConversion(value: ApiData, typeKey: string, ctx: TransformContext): ApiData { + const codec = encodeableTypeConverterRegistry.get(typeKey) if (!codec) { - throw new Error(`Codec for "${codecKey}" is not registered`) + throw new Error(`Type converter for "${typeKey}" is not registered`) + } + + // TODO: NC - Need to properly guard against these conditions + if (ctx.direction === 'encode') { + if (value instanceof Map) { + throw new Error(`Cannot encode Map with type converter "${typeKey}"`) + } + return codec.beforeEncoding(value as Parameters[0], ctx.format) } - return ctx.direction === 'encode' ? codec.encode(value, ctx.format) : codec.decode(value, ctx.format) + + return codec.afterDecoding(value as Parameters[0], ctx.format) } - private static convertToNestedMaps(value: unknown): Map | unknown[] | unknown { + private static transformMap(value: ApiData, meta: MapFieldType, ctx: TransformContext): ApiData { + if (ctx.direction === 'encode') { + if (!(value instanceof Map)) return value + const result = new Map() + for (const [k, v] of value.entries()) { + const transformedValue = this.transformType(v, meta.value, ctx) + result.set(k, transformedValue) + } + return result + } + // Decoding + if ((!(value instanceof Map) && typeof value !== 'object') || value === null) return value + const entries = value instanceof Map ? Array.from(value.entries()) : Object.entries(value as Record) + const result = new Map() + for (const [k, v] of entries) { + const transformedValue = this.transformType(v, meta.value, ctx) + result.set(k, transformedValue) + } + return result + } + + private static convertToNestedMaps(value: ApiData): Map | ApiData[] | ApiData { if (value === null || value === undefined) { return value } @@ -282,8 +473,8 @@ export class AlgorandSerializer { } if (typeof value === 'object' && value !== null && !(value instanceof Uint8Array)) { - const map = new Map() - Object.entries(value as Record).forEach(([key, val]) => { + const map = new Map() + Object.entries(value as Record).forEach(([key, val]) => { map.set(key, this.convertToNestedMaps(val)) }) return map @@ -301,39 +492,23 @@ interface TransformContext { readonly format: BodyFormat } -const encodeSignedTransactionImpl = (value: unknown): Uint8Array => transactEncodeSignedTransaction(value as SignedTransaction) -const decodeSignedTransactionImpl = (value: Uint8Array): SignedTransaction => transactDecodeSignedTransaction(value) - -class SignedTransactionCodec implements TypeCodec { - encode(value: unknown, format: BodyFormat): unknown { - if (value == null) return value +class SignedTransactionConverter implements EncodeableTypeConverter { + beforeEncoding(value: SignedTransaction, format: BodyFormat): Record { if (format === 'json') { - if (value instanceof Uint8Array) return toBase64(value) - return toBase64(encodeSignedTransactionImpl(value)) - } - if (value instanceof Uint8Array) { - // Already canonical bytes; decode to structured map so parent encoding keeps map semantics - return decodeMsgPack(value) + throw new Error('JSON format not supported for SignedTransaction encoding') } - // Convert signed transaction object into canonical map representation - return decodeMsgPack(encodeSignedTransactionImpl(value)) + return toSignedTransactionDto(value) } - - decode(value: unknown, format: BodyFormat): unknown { - if (value == null) return value - if (format === 'json') { - if (typeof value === 'string') return decodeSignedTransactionImpl(fromBase64(value)) - if (value instanceof Uint8Array) return decodeSignedTransactionImpl(value) - return value + afterDecoding(value: Record | Map, format: BodyFormat): SignedTransaction { + if (format === 'json' || !(value instanceof Map)) { + throw new Error('JSON format not supported for SignedTransaction decoding') } - if (value instanceof Uint8Array) return decodeSignedTransactionImpl(value) - // Value is a decoded map; re-encode to bytes before handing to transact decoder - try { - return decodeSignedTransactionImpl(encodeMsgPack(value)) - } catch { - return value + if (!(value instanceof Map)) { + throw new Error('Invalid decoded msgpack format for SignedTransaction') } + const stxnDto = decodedTransactionMapToObject(value) as Parameters[0] + return fromSignedTransactionDto(stxnDto) } } -registerCodec('SignedTransaction', new SignedTransactionCodec()) +registerEncodeableTypeConverter('SignedTransaction', new SignedTransactionConverter()) diff --git a/packages/indexer_client/src/core/request.ts b/packages/indexer_client/src/core/request.ts index a8a88eff..9b43c0ac 100644 --- a/packages/indexer_client/src/core/request.ts +++ b/packages/indexer_client/src/core/request.ts @@ -85,7 +85,11 @@ export async function request( try { const ct = response.headers.get('content-type') ?? '' if (ct.includes('application/msgpack')) { - errorBody = decodeMsgPack(new Uint8Array(await response.arrayBuffer())) + errorBody = decodeMsgPack(new Uint8Array(await response.arrayBuffer()), { + useMap: false, + rawBinaryStringKeys: false, + rawBinaryStringValues: false, + }) } else if (ct.includes('application/json')) { errorBody = JSON.parse(await response.text()) } else { diff --git a/packages/indexer_client/src/core/serialization.ts b/packages/indexer_client/src/core/serialization.ts deleted file mode 100644 index 6be05428..00000000 --- a/packages/indexer_client/src/core/serialization.ts +++ /dev/null @@ -1,26 +0,0 @@ -export function toBase64(bytes: Uint8Array): string { - if (typeof Buffer !== 'undefined') { - return Buffer.from(bytes).toString('base64') - } - const globalRef: Record = globalThis as unknown as Record - const btoaFn = globalRef.btoa as ((value: string) => string) | undefined - if (typeof btoaFn === 'function') { - return btoaFn(String.fromCharCode(...bytes)) - } - throw new Error('Base64 encoding not supported in this environment') -} - -export function fromBase64(s: string): Uint8Array { - if (typeof Buffer !== 'undefined') { - return new Uint8Array(Buffer.from(s, 'base64')) - } - const globalRef: Record = globalThis as unknown as Record - const atobFn = globalRef.atob as ((value: string) => string) | undefined - if (typeof atobFn === 'function') { - const bin = atobFn(s) - const out = new Uint8Array(bin.length) - for (let i = 0; i < bin.length; i += 1) out[i] = bin.charCodeAt(i) - return out - } - throw new Error('Base64 decoding not supported in this environment') -} diff --git a/packages/indexer_client/src/index.ts b/packages/indexer_client/src/index.ts index 915506d5..58a6412d 100644 --- a/packages/indexer_client/src/index.ts +++ b/packages/indexer_client/src/index.ts @@ -2,7 +2,6 @@ export * from './core/client-config' export * from './core/base-http-request' export * from './core/fetch-http-request' export * from './core/api-error' -export * from './core/serialization' export * from './core/codecs' export * from './core/model-runtime' diff --git a/packages/indexer_client/src/models/account-state-delta.ts b/packages/indexer_client/src/models/account-state-delta.ts index ad93395f..d7ddbc6a 100644 --- a/packages/indexer_client/src/models/account-state-delta.ts +++ b/packages/indexer_client/src/models/account-state-delta.ts @@ -26,7 +26,7 @@ export const AccountStateDeltaMeta: ModelMetadata = { wireKey: 'delta', optional: false, nullable: false, - type: { kind: 'model', meta: () => StateDeltaMeta }, + type: { kind: 'model', meta: StateDeltaMeta }, }, ], } diff --git a/packages/indexer_client/src/models/account.ts b/packages/indexer_client/src/models/account.ts index 3323de01..b22108b8 100644 --- a/packages/indexer_client/src/models/account.ts +++ b/packages/indexer_client/src/models/account.ts @@ -216,14 +216,14 @@ export const AccountMeta: ModelMetadata = { wireKey: 'apps-local-state', optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => ApplicationLocalStateMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: ApplicationLocalStateMeta } }, }, { name: 'appsTotalSchema', wireKey: 'apps-total-schema', optional: true, nullable: false, - type: { kind: 'model', meta: () => ApplicationStateSchemaMeta }, + type: { kind: 'model', meta: ApplicationStateSchemaMeta }, }, { name: 'appsTotalExtraPages', @@ -237,28 +237,28 @@ export const AccountMeta: ModelMetadata = { wireKey: 'assets', optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => AssetHoldingMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: AssetHoldingMeta } }, }, { name: 'createdApps', wireKey: 'created-apps', optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => ApplicationMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: ApplicationMeta } }, }, { name: 'createdAssets', wireKey: 'created-assets', optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => AssetMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: AssetMeta } }, }, { name: 'participation', wireKey: 'participation', optional: true, nullable: false, - type: { kind: 'model', meta: () => AccountParticipationMeta }, + type: { kind: 'model', meta: AccountParticipationMeta }, }, { name: 'incentiveEligible', diff --git a/packages/indexer_client/src/models/application-local-state.ts b/packages/indexer_client/src/models/application-local-state.ts index 5de31364..a1f72cc4 100644 --- a/packages/indexer_client/src/models/application-local-state.ts +++ b/packages/indexer_client/src/models/application-local-state.ts @@ -68,14 +68,14 @@ export const ApplicationLocalStateMeta: ModelMetadata = { wireKey: 'schema', optional: false, nullable: false, - type: { kind: 'model', meta: () => ApplicationStateSchemaMeta }, + type: { kind: 'model', meta: ApplicationStateSchemaMeta }, }, { name: 'keyValue', wireKey: 'key-value', optional: true, nullable: false, - type: { kind: 'model', meta: () => TealKeyValueStoreMeta }, + type: { kind: 'model', meta: TealKeyValueStoreMeta }, }, ], } diff --git a/packages/indexer_client/src/models/application-params.ts b/packages/indexer_client/src/models/application-params.ts index 093fdb71..8fa1d959 100644 --- a/packages/indexer_client/src/models/application-params.ts +++ b/packages/indexer_client/src/models/application-params.ts @@ -74,21 +74,21 @@ export const ApplicationParamsMeta: ModelMetadata = { wireKey: 'local-state-schema', optional: true, nullable: false, - type: { kind: 'model', meta: () => ApplicationStateSchemaMeta }, + type: { kind: 'model', meta: ApplicationStateSchemaMeta }, }, { name: 'globalStateSchema', wireKey: 'global-state-schema', optional: true, nullable: false, - type: { kind: 'model', meta: () => ApplicationStateSchemaMeta }, + type: { kind: 'model', meta: ApplicationStateSchemaMeta }, }, { name: 'globalState', wireKey: 'global-state', optional: true, nullable: false, - type: { kind: 'model', meta: () => TealKeyValueStoreMeta }, + type: { kind: 'model', meta: TealKeyValueStoreMeta }, }, { name: 'version', diff --git a/packages/indexer_client/src/models/application.ts b/packages/indexer_client/src/models/application.ts index afc04d8f..3bd1fc93 100644 --- a/packages/indexer_client/src/models/application.ts +++ b/packages/indexer_client/src/models/application.ts @@ -65,7 +65,7 @@ export const ApplicationMeta: ModelMetadata = { wireKey: 'params', optional: false, nullable: false, - type: { kind: 'model', meta: () => ApplicationParamsMeta }, + type: { kind: 'model', meta: ApplicationParamsMeta }, }, ], } diff --git a/packages/indexer_client/src/models/asset.ts b/packages/indexer_client/src/models/asset.ts index e5984148..06f49960 100644 --- a/packages/indexer_client/src/models/asset.ts +++ b/packages/indexer_client/src/models/asset.ts @@ -9,7 +9,7 @@ export type Asset = { /** * unique asset identifier */ - index: bigint + id: bigint /** * Whether or not this asset is currently deleted. @@ -33,7 +33,7 @@ export const AssetMeta: ModelMetadata = { kind: 'object', fields: [ { - name: 'index', + name: 'id', wireKey: 'index', optional: false, nullable: false, @@ -65,7 +65,7 @@ export const AssetMeta: ModelMetadata = { wireKey: 'params', optional: false, nullable: false, - type: { kind: 'model', meta: () => AssetParamsMeta }, + type: { kind: 'model', meta: AssetParamsMeta }, }, ], } diff --git a/packages/indexer_client/src/models/block.ts b/packages/indexer_client/src/models/block.ts index aadd3b22..235d9661 100644 --- a/packages/indexer_client/src/models/block.ts +++ b/packages/indexer_client/src/models/block.ts @@ -176,7 +176,7 @@ export const BlockMeta: ModelMetadata = { wireKey: 'rewards', optional: true, nullable: false, - type: { kind: 'model', meta: () => BlockRewardsMeta }, + type: { kind: 'model', meta: BlockRewardsMeta }, }, { name: 'round', @@ -197,7 +197,7 @@ export const BlockMeta: ModelMetadata = { wireKey: 'state-proof-tracking', optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => StateProofTrackingMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: StateProofTrackingMeta } }, }, { name: 'timestamp', @@ -211,7 +211,7 @@ export const BlockMeta: ModelMetadata = { wireKey: 'transactions', optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => TransactionMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: TransactionMeta } }, }, { name: 'transactionsRoot', @@ -246,21 +246,21 @@ export const BlockMeta: ModelMetadata = { wireKey: 'upgrade-state', optional: true, nullable: false, - type: { kind: 'model', meta: () => BlockUpgradeStateMeta }, + type: { kind: 'model', meta: BlockUpgradeStateMeta }, }, { name: 'upgradeVote', wireKey: 'upgrade-vote', optional: true, nullable: false, - type: { kind: 'model', meta: () => BlockUpgradeVoteMeta }, + type: { kind: 'model', meta: BlockUpgradeVoteMeta }, }, { name: 'participationUpdates', wireKey: 'participation-updates', optional: true, nullable: false, - type: { kind: 'model', meta: () => ParticipationUpdatesMeta }, + type: { kind: 'model', meta: ParticipationUpdatesMeta }, }, ], } diff --git a/packages/indexer_client/src/models/eval-delta-key-value.ts b/packages/indexer_client/src/models/eval-delta-key-value.ts index 80097c50..59b8f609 100644 --- a/packages/indexer_client/src/models/eval-delta-key-value.ts +++ b/packages/indexer_client/src/models/eval-delta-key-value.ts @@ -26,7 +26,7 @@ export const EvalDeltaKeyValueMeta: ModelMetadata = { wireKey: 'value', optional: false, nullable: false, - type: { kind: 'model', meta: () => EvalDeltaMeta }, + type: { kind: 'model', meta: EvalDeltaMeta }, }, ], } diff --git a/packages/indexer_client/src/models/health-check.ts b/packages/indexer_client/src/models/health-check.ts index 8b4d632c..34695a47 100644 --- a/packages/indexer_client/src/models/health-check.ts +++ b/packages/indexer_client/src/models/health-check.ts @@ -1,5 +1,7 @@ import type { ModelMetadata } from '../core/model-runtime' +const HealthCheckDataMeta: ModelMetadata = { name: 'HealthCheckDataMeta', kind: 'object', fields: [] } + /** * A health check response. */ @@ -32,7 +34,7 @@ export const HealthCheckMeta: ModelMetadata = { wireKey: 'data', optional: true, nullable: false, - type: { kind: 'scalar' }, + type: { kind: 'model', meta: HealthCheckDataMeta }, }, { name: 'round', diff --git a/packages/indexer_client/src/models/lookup-account-app-local-states.ts b/packages/indexer_client/src/models/lookup-account-app-local-states.ts index d5ce57fb..0c6c288c 100644 --- a/packages/indexer_client/src/models/lookup-account-app-local-states.ts +++ b/packages/indexer_client/src/models/lookup-account-app-local-states.ts @@ -25,7 +25,7 @@ export const LookupAccountAppLocalStatesMeta: ModelMetadata = { wireKey: 'apps-local-states', optional: false, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => ApplicationLocalStateMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: ApplicationLocalStateMeta } }, }, { name: 'currentRound', diff --git a/packages/indexer_client/src/models/lookup-account-assets.ts b/packages/indexer_client/src/models/lookup-account-assets.ts index 6c59fccd..dc8f9740 100644 --- a/packages/indexer_client/src/models/lookup-account-assets.ts +++ b/packages/indexer_client/src/models/lookup-account-assets.ts @@ -38,7 +38,7 @@ export const LookupAccountAssetsMeta: ModelMetadata = { wireKey: 'assets', optional: false, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => AssetHoldingMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: AssetHoldingMeta } }, }, ], } diff --git a/packages/indexer_client/src/models/lookup-account-by-id.ts b/packages/indexer_client/src/models/lookup-account-by-id.ts index 5e0e7e0a..caaf10e8 100644 --- a/packages/indexer_client/src/models/lookup-account-by-id.ts +++ b/packages/indexer_client/src/models/lookup-account-by-id.ts @@ -20,7 +20,7 @@ export const LookupAccountByIdMeta: ModelMetadata = { wireKey: 'account', optional: false, nullable: false, - type: { kind: 'model', meta: () => AccountMeta }, + type: { kind: 'model', meta: AccountMeta }, }, { name: 'currentRound', diff --git a/packages/indexer_client/src/models/lookup-account-created-applications.ts b/packages/indexer_client/src/models/lookup-account-created-applications.ts index e7b81b9a..87ee351b 100644 --- a/packages/indexer_client/src/models/lookup-account-created-applications.ts +++ b/packages/indexer_client/src/models/lookup-account-created-applications.ts @@ -25,7 +25,7 @@ export const LookupAccountCreatedApplicationsMeta: ModelMetadata = { wireKey: 'applications', optional: false, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => ApplicationMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: ApplicationMeta } }, }, { name: 'currentRound', diff --git a/packages/indexer_client/src/models/lookup-account-created-assets.ts b/packages/indexer_client/src/models/lookup-account-created-assets.ts index 533c848b..6bc9c7f9 100644 --- a/packages/indexer_client/src/models/lookup-account-created-assets.ts +++ b/packages/indexer_client/src/models/lookup-account-created-assets.ts @@ -25,7 +25,7 @@ export const LookupAccountCreatedAssetsMeta: ModelMetadata = { wireKey: 'assets', optional: false, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => AssetMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: AssetMeta } }, }, { name: 'currentRound', diff --git a/packages/indexer_client/src/models/lookup-account-transactions.ts b/packages/indexer_client/src/models/lookup-account-transactions.ts index dde018d4..0ebdcde6 100644 --- a/packages/indexer_client/src/models/lookup-account-transactions.ts +++ b/packages/indexer_client/src/models/lookup-account-transactions.ts @@ -38,7 +38,7 @@ export const LookupAccountTransactionsMeta: ModelMetadata = { wireKey: 'transactions', optional: false, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => TransactionMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: TransactionMeta } }, }, ], } diff --git a/packages/indexer_client/src/models/lookup-application-by-id.ts b/packages/indexer_client/src/models/lookup-application-by-id.ts index a1ad544c..4c95fda4 100644 --- a/packages/indexer_client/src/models/lookup-application-by-id.ts +++ b/packages/indexer_client/src/models/lookup-application-by-id.ts @@ -20,7 +20,7 @@ export const LookupApplicationByIdMeta: ModelMetadata = { wireKey: 'application', optional: true, nullable: false, - type: { kind: 'model', meta: () => ApplicationMeta }, + type: { kind: 'model', meta: ApplicationMeta }, }, { name: 'currentRound', diff --git a/packages/indexer_client/src/models/lookup-application-logs-by-id.ts b/packages/indexer_client/src/models/lookup-application-logs-by-id.ts index f50e3e30..c80f393c 100644 --- a/packages/indexer_client/src/models/lookup-application-logs-by-id.ts +++ b/packages/indexer_client/src/models/lookup-application-logs-by-id.ts @@ -50,7 +50,7 @@ export const LookupApplicationLogsByIdMeta: ModelMetadata = { wireKey: 'log-data', optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => ApplicationLogDataMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: ApplicationLogDataMeta } }, }, ], } diff --git a/packages/indexer_client/src/models/lookup-asset-balances.ts b/packages/indexer_client/src/models/lookup-asset-balances.ts index d1821577..c8e679d3 100644 --- a/packages/indexer_client/src/models/lookup-asset-balances.ts +++ b/packages/indexer_client/src/models/lookup-asset-balances.ts @@ -25,7 +25,7 @@ export const LookupAssetBalancesMeta: ModelMetadata = { wireKey: 'balances', optional: false, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => MiniAssetHoldingMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: MiniAssetHoldingMeta } }, }, { name: 'currentRound', diff --git a/packages/indexer_client/src/models/lookup-asset-by-id.ts b/packages/indexer_client/src/models/lookup-asset-by-id.ts index ea8bd0fb..9e8e5922 100644 --- a/packages/indexer_client/src/models/lookup-asset-by-id.ts +++ b/packages/indexer_client/src/models/lookup-asset-by-id.ts @@ -20,7 +20,7 @@ export const LookupAssetByIdMeta: ModelMetadata = { wireKey: 'asset', optional: false, nullable: false, - type: { kind: 'model', meta: () => AssetMeta }, + type: { kind: 'model', meta: AssetMeta }, }, { name: 'currentRound', diff --git a/packages/indexer_client/src/models/lookup-asset-transactions.ts b/packages/indexer_client/src/models/lookup-asset-transactions.ts index a5890f37..2b167843 100644 --- a/packages/indexer_client/src/models/lookup-asset-transactions.ts +++ b/packages/indexer_client/src/models/lookup-asset-transactions.ts @@ -38,7 +38,7 @@ export const LookupAssetTransactionsMeta: ModelMetadata = { wireKey: 'transactions', optional: false, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => TransactionMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: TransactionMeta } }, }, ], } diff --git a/packages/indexer_client/src/models/lookup-transaction.ts b/packages/indexer_client/src/models/lookup-transaction.ts index 8cab3ce4..23475dec 100644 --- a/packages/indexer_client/src/models/lookup-transaction.ts +++ b/packages/indexer_client/src/models/lookup-transaction.ts @@ -20,7 +20,7 @@ export const LookupTransactionMeta: ModelMetadata = { wireKey: 'transaction', optional: false, nullable: false, - type: { kind: 'model', meta: () => TransactionMeta }, + type: { kind: 'model', meta: TransactionMeta }, }, { name: 'currentRound', diff --git a/packages/indexer_client/src/models/merkle-array-proof.ts b/packages/indexer_client/src/models/merkle-array-proof.ts index e94c01f7..59df1474 100644 --- a/packages/indexer_client/src/models/merkle-array-proof.ts +++ b/packages/indexer_client/src/models/merkle-array-proof.ts @@ -31,7 +31,7 @@ export const MerkleArrayProofMeta: ModelMetadata = { wireKey: 'hash-factory', optional: true, nullable: false, - type: { kind: 'model', meta: () => HashFactoryMeta }, + type: { kind: 'model', meta: HashFactoryMeta }, }, { name: 'treeDepth', diff --git a/packages/indexer_client/src/models/resource-ref.ts b/packages/indexer_client/src/models/resource-ref.ts index 928a64bb..92a82fd5 100644 --- a/packages/indexer_client/src/models/resource-ref.ts +++ b/packages/indexer_client/src/models/resource-ref.ts @@ -61,21 +61,21 @@ export const ResourceRefMeta: ModelMetadata = { wireKey: 'box', optional: true, nullable: false, - type: { kind: 'model', meta: () => BoxReferenceMeta }, + type: { kind: 'model', meta: BoxReferenceMeta }, }, { name: 'holding', wireKey: 'holding', optional: true, nullable: false, - type: { kind: 'model', meta: () => HoldingRefMeta }, + type: { kind: 'model', meta: HoldingRefMeta }, }, { name: 'local', wireKey: 'local', optional: true, nullable: false, - type: { kind: 'model', meta: () => LocalsRefMeta }, + type: { kind: 'model', meta: LocalsRefMeta }, }, ], } diff --git a/packages/indexer_client/src/models/search-for-accounts.ts b/packages/indexer_client/src/models/search-for-accounts.ts index 7f38113e..7b6a37d9 100644 --- a/packages/indexer_client/src/models/search-for-accounts.ts +++ b/packages/indexer_client/src/models/search-for-accounts.ts @@ -25,7 +25,7 @@ export const SearchForAccountsMeta: ModelMetadata = { wireKey: 'accounts', optional: false, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => AccountMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: AccountMeta } }, }, { name: 'currentRound', diff --git a/packages/indexer_client/src/models/search-for-application-boxes.ts b/packages/indexer_client/src/models/search-for-application-boxes.ts index 7035587c..32b5355c 100644 --- a/packages/indexer_client/src/models/search-for-application-boxes.ts +++ b/packages/indexer_client/src/models/search-for-application-boxes.ts @@ -31,7 +31,7 @@ export const SearchForApplicationBoxesMeta: ModelMetadata = { wireKey: 'boxes', optional: false, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => BoxDescriptorMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: BoxDescriptorMeta } }, }, { name: 'nextToken', diff --git a/packages/indexer_client/src/models/search-for-applications.ts b/packages/indexer_client/src/models/search-for-applications.ts index 5a4e05b5..ceb6f76d 100644 --- a/packages/indexer_client/src/models/search-for-applications.ts +++ b/packages/indexer_client/src/models/search-for-applications.ts @@ -25,7 +25,7 @@ export const SearchForApplicationsMeta: ModelMetadata = { wireKey: 'applications', optional: false, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => ApplicationMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: ApplicationMeta } }, }, { name: 'currentRound', diff --git a/packages/indexer_client/src/models/search-for-assets.ts b/packages/indexer_client/src/models/search-for-assets.ts index 77d6d592..b6a17a18 100644 --- a/packages/indexer_client/src/models/search-for-assets.ts +++ b/packages/indexer_client/src/models/search-for-assets.ts @@ -25,7 +25,7 @@ export const SearchForAssetsMeta: ModelMetadata = { wireKey: 'assets', optional: false, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => AssetMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: AssetMeta } }, }, { name: 'currentRound', diff --git a/packages/indexer_client/src/models/search-for-block-headers.ts b/packages/indexer_client/src/models/search-for-block-headers.ts index 33e09c5b..cf2c6f19 100644 --- a/packages/indexer_client/src/models/search-for-block-headers.ts +++ b/packages/indexer_client/src/models/search-for-block-headers.ts @@ -38,7 +38,7 @@ export const SearchForBlockHeadersMeta: ModelMetadata = { wireKey: 'blocks', optional: false, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => BlockMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: BlockMeta } }, }, ], } diff --git a/packages/indexer_client/src/models/search-for-transactions.ts b/packages/indexer_client/src/models/search-for-transactions.ts index 9af103f2..f87c8440 100644 --- a/packages/indexer_client/src/models/search-for-transactions.ts +++ b/packages/indexer_client/src/models/search-for-transactions.ts @@ -38,7 +38,7 @@ export const SearchForTransactionsMeta: ModelMetadata = { wireKey: 'transactions', optional: false, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => TransactionMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: TransactionMeta } }, }, ], } diff --git a/packages/indexer_client/src/models/state-delta.ts b/packages/indexer_client/src/models/state-delta.ts index ef811cfe..4563bbf8 100644 --- a/packages/indexer_client/src/models/state-delta.ts +++ b/packages/indexer_client/src/models/state-delta.ts @@ -10,5 +10,5 @@ export type StateDelta = EvalDeltaKeyValue[] export const StateDeltaMeta: ModelMetadata = { name: 'StateDelta', kind: 'array', - arrayItems: { kind: 'model', meta: () => EvalDeltaKeyValueMeta }, + arrayItems: { kind: 'model', meta: EvalDeltaKeyValueMeta }, } diff --git a/packages/indexer_client/src/models/state-proof-fields.ts b/packages/indexer_client/src/models/state-proof-fields.ts index e19175ee..ff52a035 100644 --- a/packages/indexer_client/src/models/state-proof-fields.ts +++ b/packages/indexer_client/src/models/state-proof-fields.ts @@ -62,14 +62,14 @@ export const StateProofFieldsMeta: ModelMetadata = { wireKey: 'sig-proofs', optional: true, nullable: false, - type: { kind: 'model', meta: () => MerkleArrayProofMeta }, + type: { kind: 'model', meta: MerkleArrayProofMeta }, }, { name: 'partProofs', wireKey: 'part-proofs', optional: true, nullable: false, - type: { kind: 'model', meta: () => MerkleArrayProofMeta }, + type: { kind: 'model', meta: MerkleArrayProofMeta }, }, { name: 'saltVersion', @@ -83,7 +83,7 @@ export const StateProofFieldsMeta: ModelMetadata = { wireKey: 'reveals', optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => StateProofRevealMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: StateProofRevealMeta } }, }, { name: 'positionsToReveal', diff --git a/packages/indexer_client/src/models/state-proof-participant.ts b/packages/indexer_client/src/models/state-proof-participant.ts index f1db65ce..651bd043 100644 --- a/packages/indexer_client/src/models/state-proof-participant.ts +++ b/packages/indexer_client/src/models/state-proof-participant.ts @@ -20,7 +20,7 @@ export const StateProofParticipantMeta: ModelMetadata = { wireKey: 'verifier', optional: true, nullable: false, - type: { kind: 'model', meta: () => StateProofVerifierMeta }, + type: { kind: 'model', meta: StateProofVerifierMeta }, }, { name: 'weight', diff --git a/packages/indexer_client/src/models/state-proof-reveal.ts b/packages/indexer_client/src/models/state-proof-reveal.ts index 12a1f117..52b121be 100644 --- a/packages/indexer_client/src/models/state-proof-reveal.ts +++ b/packages/indexer_client/src/models/state-proof-reveal.ts @@ -29,14 +29,14 @@ export const StateProofRevealMeta: ModelMetadata = { wireKey: 'sig-slot', optional: true, nullable: false, - type: { kind: 'model', meta: () => StateProofSigSlotMeta }, + type: { kind: 'model', meta: StateProofSigSlotMeta }, }, { name: 'participant', wireKey: 'participant', optional: true, nullable: false, - type: { kind: 'model', meta: () => StateProofParticipantMeta }, + type: { kind: 'model', meta: StateProofParticipantMeta }, }, ], } diff --git a/packages/indexer_client/src/models/state-proof-sig-slot.ts b/packages/indexer_client/src/models/state-proof-sig-slot.ts index b69d3281..79c45d26 100644 --- a/packages/indexer_client/src/models/state-proof-sig-slot.ts +++ b/packages/indexer_client/src/models/state-proof-sig-slot.ts @@ -20,7 +20,7 @@ export const StateProofSigSlotMeta: ModelMetadata = { wireKey: 'signature', optional: true, nullable: false, - type: { kind: 'model', meta: () => StateProofSignatureMeta }, + type: { kind: 'model', meta: StateProofSignatureMeta }, }, { name: 'lowerSigWeight', diff --git a/packages/indexer_client/src/models/state-proof-signature.ts b/packages/indexer_client/src/models/state-proof-signature.ts index 3f03e57c..ce761001 100644 --- a/packages/indexer_client/src/models/state-proof-signature.ts +++ b/packages/indexer_client/src/models/state-proof-signature.ts @@ -36,7 +36,7 @@ export const StateProofSignatureMeta: ModelMetadata = { wireKey: 'proof', optional: true, nullable: false, - type: { kind: 'model', meta: () => MerkleArrayProofMeta }, + type: { kind: 'model', meta: MerkleArrayProofMeta }, }, { name: 'verifyingKey', diff --git a/packages/indexer_client/src/models/teal-key-value-store.ts b/packages/indexer_client/src/models/teal-key-value-store.ts index d0ad997b..99dd316d 100644 --- a/packages/indexer_client/src/models/teal-key-value-store.ts +++ b/packages/indexer_client/src/models/teal-key-value-store.ts @@ -10,5 +10,5 @@ export type TealKeyValueStore = TealKeyValue[] export const TealKeyValueStoreMeta: ModelMetadata = { name: 'TealKeyValueStore', kind: 'array', - arrayItems: { kind: 'model', meta: () => TealKeyValueMeta }, + arrayItems: { kind: 'model', meta: TealKeyValueMeta }, } diff --git a/packages/indexer_client/src/models/teal-key-value.ts b/packages/indexer_client/src/models/teal-key-value.ts index 73575a78..085f5551 100644 --- a/packages/indexer_client/src/models/teal-key-value.ts +++ b/packages/indexer_client/src/models/teal-key-value.ts @@ -26,7 +26,7 @@ export const TealKeyValueMeta: ModelMetadata = { wireKey: 'value', optional: false, nullable: false, - type: { kind: 'model', meta: () => TealValueMeta }, + type: { kind: 'model', meta: TealValueMeta }, }, ], } diff --git a/packages/indexer_client/src/models/transaction-application.ts b/packages/indexer_client/src/models/transaction-application.ts index 69c8fe82..91de10ea 100644 --- a/packages/indexer_client/src/models/transaction-application.ts +++ b/packages/indexer_client/src/models/transaction-application.ts @@ -90,7 +90,7 @@ export const TransactionApplicationMeta: ModelMetadata = { wireKey: 'on-completion', optional: false, nullable: false, - type: { kind: 'model', meta: () => OnCompletionMeta }, + type: { kind: 'model', meta: OnCompletionMeta }, }, { name: 'applicationArgs', @@ -104,7 +104,7 @@ export const TransactionApplicationMeta: ModelMetadata = { wireKey: 'access', optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => ResourceRefMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: ResourceRefMeta } }, }, { name: 'accounts', @@ -118,7 +118,7 @@ export const TransactionApplicationMeta: ModelMetadata = { wireKey: 'box-references', optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => BoxReferenceMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: BoxReferenceMeta } }, }, { name: 'foreignApps', @@ -139,14 +139,14 @@ export const TransactionApplicationMeta: ModelMetadata = { wireKey: 'local-state-schema', optional: true, nullable: false, - type: { kind: 'model', meta: () => StateSchemaMeta }, + type: { kind: 'model', meta: StateSchemaMeta }, }, { name: 'globalStateSchema', wireKey: 'global-state-schema', optional: true, nullable: false, - type: { kind: 'model', meta: () => StateSchemaMeta }, + type: { kind: 'model', meta: StateSchemaMeta }, }, { name: 'approvalProgram', diff --git a/packages/indexer_client/src/models/transaction-asset-config.ts b/packages/indexer_client/src/models/transaction-asset-config.ts index 6de8eb53..413943b9 100644 --- a/packages/indexer_client/src/models/transaction-asset-config.ts +++ b/packages/indexer_client/src/models/transaction-asset-config.ts @@ -36,7 +36,7 @@ export const TransactionAssetConfigMeta: ModelMetadata = { wireKey: 'params', optional: true, nullable: false, - type: { kind: 'model', meta: () => AssetParamsMeta }, + type: { kind: 'model', meta: AssetParamsMeta }, }, ], } diff --git a/packages/indexer_client/src/models/transaction-heartbeat.ts b/packages/indexer_client/src/models/transaction-heartbeat.ts index b0c665ea..8098610f 100644 --- a/packages/indexer_client/src/models/transaction-heartbeat.ts +++ b/packages/indexer_client/src/models/transaction-heartbeat.ts @@ -47,7 +47,7 @@ export const TransactionHeartbeatMeta: ModelMetadata = { wireKey: 'hb-proof', optional: false, nullable: false, - type: { kind: 'model', meta: () => HbProofFieldsMeta }, + type: { kind: 'model', meta: HbProofFieldsMeta }, }, { name: 'hbSeed', diff --git a/packages/indexer_client/src/models/transaction-signature-logicsig.ts b/packages/indexer_client/src/models/transaction-signature-logicsig.ts index d5f43cab..5cd658cf 100644 --- a/packages/indexer_client/src/models/transaction-signature-logicsig.ts +++ b/packages/indexer_client/src/models/transaction-signature-logicsig.ts @@ -50,14 +50,14 @@ export const TransactionSignatureLogicsigMeta: ModelMetadata = { wireKey: 'multisig-signature', optional: true, nullable: false, - type: { kind: 'model', meta: () => TransactionSignatureMultisigMeta }, + type: { kind: 'model', meta: TransactionSignatureMultisigMeta }, }, { name: 'logicMultisigSignature', wireKey: 'logic-multisig-signature', optional: true, nullable: false, - type: { kind: 'model', meta: () => TransactionSignatureMultisigMeta }, + type: { kind: 'model', meta: TransactionSignatureMultisigMeta }, }, { name: 'signature', diff --git a/packages/indexer_client/src/models/transaction-signature-multisig.ts b/packages/indexer_client/src/models/transaction-signature-multisig.ts index 0ba916dd..33a494c9 100644 --- a/packages/indexer_client/src/models/transaction-signature-multisig.ts +++ b/packages/indexer_client/src/models/transaction-signature-multisig.ts @@ -34,7 +34,7 @@ export const TransactionSignatureMultisigMeta: ModelMetadata = { wireKey: 'subsignature', optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => TransactionSignatureMultisigSubsignatureMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: TransactionSignatureMultisigSubsignatureMeta } }, }, { name: 'threshold', diff --git a/packages/indexer_client/src/models/transaction-signature.ts b/packages/indexer_client/src/models/transaction-signature.ts index 679d8f70..bddfc1e3 100644 --- a/packages/indexer_client/src/models/transaction-signature.ts +++ b/packages/indexer_client/src/models/transaction-signature.ts @@ -26,14 +26,14 @@ export const TransactionSignatureMeta: ModelMetadata = { wireKey: 'logicsig', optional: true, nullable: false, - type: { kind: 'model', meta: () => TransactionSignatureLogicsigMeta }, + type: { kind: 'model', meta: TransactionSignatureLogicsigMeta }, }, { name: 'multisig', wireKey: 'multisig', optional: true, nullable: false, - type: { kind: 'model', meta: () => TransactionSignatureMultisigMeta }, + type: { kind: 'model', meta: TransactionSignatureMultisigMeta }, }, { name: 'sig', diff --git a/packages/indexer_client/src/models/transaction-state-proof.ts b/packages/indexer_client/src/models/transaction-state-proof.ts index a254402f..514da0e8 100644 --- a/packages/indexer_client/src/models/transaction-state-proof.ts +++ b/packages/indexer_client/src/models/transaction-state-proof.ts @@ -35,14 +35,14 @@ export const TransactionStateProofMeta: ModelMetadata = { wireKey: 'state-proof', optional: true, nullable: false, - type: { kind: 'model', meta: () => StateProofFieldsMeta }, + type: { kind: 'model', meta: StateProofFieldsMeta }, }, { name: 'message', wireKey: 'message', optional: true, nullable: false, - type: { kind: 'model', meta: () => IndexerStateProofMessageMeta }, + type: { kind: 'model', meta: IndexerStateProofMessageMeta }, }, ], } diff --git a/packages/indexer_client/src/models/transaction.ts b/packages/indexer_client/src/models/transaction.ts index 86f2222b..03930f9b 100644 --- a/packages/indexer_client/src/models/transaction.ts +++ b/packages/indexer_client/src/models/transaction.ts @@ -186,42 +186,42 @@ export const TransactionMeta: ModelMetadata = { wireKey: 'application-transaction', optional: true, nullable: false, - type: { kind: 'model', meta: () => TransactionApplicationMeta }, + type: { kind: 'model', meta: TransactionApplicationMeta }, }, { name: 'assetConfigTransaction', wireKey: 'asset-config-transaction', optional: true, nullable: false, - type: { kind: 'model', meta: () => TransactionAssetConfigMeta }, + type: { kind: 'model', meta: TransactionAssetConfigMeta }, }, { name: 'assetFreezeTransaction', wireKey: 'asset-freeze-transaction', optional: true, nullable: false, - type: { kind: 'model', meta: () => TransactionAssetFreezeMeta }, + type: { kind: 'model', meta: TransactionAssetFreezeMeta }, }, { name: 'assetTransferTransaction', wireKey: 'asset-transfer-transaction', optional: true, nullable: false, - type: { kind: 'model', meta: () => TransactionAssetTransferMeta }, + type: { kind: 'model', meta: TransactionAssetTransferMeta }, }, { name: 'stateProofTransaction', wireKey: 'state-proof-transaction', optional: true, nullable: false, - type: { kind: 'model', meta: () => TransactionStateProofMeta }, + type: { kind: 'model', meta: TransactionStateProofMeta }, }, { name: 'heartbeatTransaction', wireKey: 'heartbeat-transaction', optional: true, nullable: false, - type: { kind: 'model', meta: () => TransactionHeartbeatMeta }, + type: { kind: 'model', meta: TransactionHeartbeatMeta }, }, { name: 'authAddr', @@ -319,7 +319,7 @@ export const TransactionMeta: ModelMetadata = { wireKey: 'keyreg-transaction', optional: true, nullable: false, - type: { kind: 'model', meta: () => TransactionKeyregMeta }, + type: { kind: 'model', meta: TransactionKeyregMeta }, }, { name: 'lastValid', @@ -347,7 +347,7 @@ export const TransactionMeta: ModelMetadata = { wireKey: 'payment-transaction', optional: true, nullable: false, - type: { kind: 'model', meta: () => TransactionPaymentMeta }, + type: { kind: 'model', meta: TransactionPaymentMeta }, }, { name: 'receiverRewards', @@ -389,7 +389,7 @@ export const TransactionMeta: ModelMetadata = { wireKey: 'signature', optional: true, nullable: false, - type: { kind: 'model', meta: () => TransactionSignatureMeta }, + type: { kind: 'model', meta: TransactionSignatureMeta }, }, { name: 'txType', @@ -403,14 +403,14 @@ export const TransactionMeta: ModelMetadata = { wireKey: 'local-state-delta', optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => AccountStateDeltaMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: AccountStateDeltaMeta } }, }, { name: 'globalStateDelta', wireKey: 'global-state-delta', optional: true, nullable: false, - type: { kind: 'model', meta: () => StateDeltaMeta }, + type: { kind: 'model', meta: StateDeltaMeta }, }, { name: 'logs', diff --git a/packages/kmd_client/src/apis/api.service.ts b/packages/kmd_client/src/apis/api.service.ts index a1858bd8..73895498 100644 --- a/packages/kmd_client/src/apis/api.service.ts +++ b/packages/kmd_client/src/apis/api.service.ts @@ -112,9 +112,9 @@ export class KmdApi { const bodyMeta = CreateWalletRequestMeta const mediaType = bodyMeta ? KmdApi.mediaFor(responseFormat) : undefined if (mediaType) headers['Content-Type'] = mediaType - const serializedBody = bodyMeta && body !== undefined ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : body + const serializedBody = body ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : undefined - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'POST', url: '/v1/wallet', path: {}, @@ -124,11 +124,7 @@ export class KmdApi { mediaType: mediaType, }) - const responseMeta = PostWalletResponseMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as PostWalletResponse + return AlgorandSerializer.decode(payload, PostWalletResponseMeta, responseFormat) } /** @@ -142,9 +138,9 @@ export class KmdApi { const bodyMeta = DeleteKeyRequestMeta const mediaType = bodyMeta ? KmdApi.mediaFor(responseFormat) : undefined if (mediaType) headers['Content-Type'] = mediaType - const serializedBody = bodyMeta && body !== undefined ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : body + const serializedBody = body ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : undefined - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'DELETE', url: '/v1/key', path: {}, @@ -154,11 +150,7 @@ export class KmdApi { mediaType: mediaType, }) - const responseMeta = DeleteKeyResponseMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as DeleteKeyResponse + return AlgorandSerializer.decode(payload, DeleteKeyResponseMeta, responseFormat) } /** @@ -172,9 +164,9 @@ export class KmdApi { const bodyMeta = DeleteMultisigRequestMeta const mediaType = bodyMeta ? KmdApi.mediaFor(responseFormat) : undefined if (mediaType) headers['Content-Type'] = mediaType - const serializedBody = bodyMeta && body !== undefined ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : body + const serializedBody = body ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : undefined - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'DELETE', url: '/v1/multisig', path: {}, @@ -184,11 +176,7 @@ export class KmdApi { mediaType: mediaType, }) - const responseMeta = DeleteMultisigResponseMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as DeleteMultisigResponse + return AlgorandSerializer.decode(payload, DeleteMultisigResponseMeta, responseFormat) } /** @@ -202,9 +190,9 @@ export class KmdApi { const bodyMeta = ExportKeyRequestMeta const mediaType = bodyMeta ? KmdApi.mediaFor(responseFormat) : undefined if (mediaType) headers['Content-Type'] = mediaType - const serializedBody = bodyMeta && body !== undefined ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : body + const serializedBody = body ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : undefined - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'POST', url: '/v1/key/export', path: {}, @@ -214,11 +202,7 @@ export class KmdApi { mediaType: mediaType, }) - const responseMeta = PostKeyExportResponseMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as PostKeyExportResponse + return AlgorandSerializer.decode(payload, PostKeyExportResponseMeta, responseFormat) } /** @@ -232,9 +216,9 @@ export class KmdApi { const bodyMeta = ExportMasterKeyRequestMeta const mediaType = bodyMeta ? KmdApi.mediaFor(responseFormat) : undefined if (mediaType) headers['Content-Type'] = mediaType - const serializedBody = bodyMeta && body !== undefined ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : body + const serializedBody = body ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : undefined - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'POST', url: '/v1/master-key/export', path: {}, @@ -244,11 +228,7 @@ export class KmdApi { mediaType: mediaType, }) - const responseMeta = PostMasterKeyExportResponseMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as PostMasterKeyExportResponse + return AlgorandSerializer.decode(payload, PostMasterKeyExportResponseMeta, responseFormat) } /** @@ -262,9 +242,9 @@ export class KmdApi { const bodyMeta = ExportMultisigRequestMeta const mediaType = bodyMeta ? KmdApi.mediaFor(responseFormat) : undefined if (mediaType) headers['Content-Type'] = mediaType - const serializedBody = bodyMeta && body !== undefined ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : body + const serializedBody = body ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : undefined - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'POST', url: '/v1/multisig/export', path: {}, @@ -274,11 +254,7 @@ export class KmdApi { mediaType: mediaType, }) - const responseMeta = PostMultisigExportResponseMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as PostMultisigExportResponse + return AlgorandSerializer.decode(payload, PostMultisigExportResponseMeta, responseFormat) } /** @@ -292,9 +268,9 @@ export class KmdApi { const bodyMeta = GenerateKeyRequestMeta const mediaType = bodyMeta ? KmdApi.mediaFor(responseFormat) : undefined if (mediaType) headers['Content-Type'] = mediaType - const serializedBody = bodyMeta && body !== undefined ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : body + const serializedBody = body ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : undefined - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'POST', url: '/v1/key', path: {}, @@ -304,11 +280,7 @@ export class KmdApi { mediaType: mediaType, }) - const responseMeta = PostKeyResponseMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as PostKeyResponse + return AlgorandSerializer.decode(payload, PostKeyResponseMeta, responseFormat) } async getVersion(): Promise { @@ -316,7 +288,7 @@ export class KmdApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = KmdApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/versions', path: {}, @@ -326,11 +298,7 @@ export class KmdApi { mediaType: undefined, }) - const responseMeta = VersionsResponseMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as VersionsResponse + return AlgorandSerializer.decode(payload, VersionsResponseMeta, responseFormat) } /** @@ -344,9 +312,9 @@ export class KmdApi { const bodyMeta = WalletInfoRequestMeta const mediaType = bodyMeta ? KmdApi.mediaFor(responseFormat) : undefined if (mediaType) headers['Content-Type'] = mediaType - const serializedBody = bodyMeta && body !== undefined ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : body + const serializedBody = body ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : undefined - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'POST', url: '/v1/wallet/info', path: {}, @@ -356,11 +324,7 @@ export class KmdApi { mediaType: mediaType, }) - const responseMeta = PostWalletInfoResponseMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as PostWalletInfoResponse + return AlgorandSerializer.decode(payload, PostWalletInfoResponseMeta, responseFormat) } /** @@ -374,9 +338,9 @@ export class KmdApi { const bodyMeta = ImportKeyRequestMeta const mediaType = bodyMeta ? KmdApi.mediaFor(responseFormat) : undefined if (mediaType) headers['Content-Type'] = mediaType - const serializedBody = bodyMeta && body !== undefined ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : body + const serializedBody = body ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : undefined - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'POST', url: '/v1/key/import', path: {}, @@ -386,11 +350,7 @@ export class KmdApi { mediaType: mediaType, }) - const responseMeta = PostKeyImportResponseMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as PostKeyImportResponse + return AlgorandSerializer.decode(payload, PostKeyImportResponseMeta, responseFormat) } /** @@ -404,9 +364,9 @@ export class KmdApi { const bodyMeta = ImportMultisigRequestMeta const mediaType = bodyMeta ? KmdApi.mediaFor(responseFormat) : undefined if (mediaType) headers['Content-Type'] = mediaType - const serializedBody = bodyMeta && body !== undefined ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : body + const serializedBody = body ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : undefined - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'POST', url: '/v1/multisig/import', path: {}, @@ -416,11 +376,7 @@ export class KmdApi { mediaType: mediaType, }) - const responseMeta = PostMultisigImportResponseMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as PostMultisigImportResponse + return AlgorandSerializer.decode(payload, PostMultisigImportResponseMeta, responseFormat) } /** @@ -434,9 +390,9 @@ export class KmdApi { const bodyMeta = InitWalletHandleTokenRequestMeta const mediaType = bodyMeta ? KmdApi.mediaFor(responseFormat) : undefined if (mediaType) headers['Content-Type'] = mediaType - const serializedBody = bodyMeta && body !== undefined ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : body + const serializedBody = body ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : undefined - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'POST', url: '/v1/wallet/init', path: {}, @@ -446,11 +402,7 @@ export class KmdApi { mediaType: mediaType, }) - const responseMeta = PostWalletInitResponseMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as PostWalletInitResponse + return AlgorandSerializer.decode(payload, PostWalletInitResponseMeta, responseFormat) } /** @@ -464,9 +416,9 @@ export class KmdApi { const bodyMeta = ListKeysRequestMeta const mediaType = bodyMeta ? KmdApi.mediaFor(responseFormat) : undefined if (mediaType) headers['Content-Type'] = mediaType - const serializedBody = bodyMeta && body !== undefined ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : body + const serializedBody = body ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : undefined - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'POST', url: '/v1/key/list', path: {}, @@ -476,11 +428,7 @@ export class KmdApi { mediaType: mediaType, }) - const responseMeta = PostKeyListResponseMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as PostKeyListResponse + return AlgorandSerializer.decode(payload, PostKeyListResponseMeta, responseFormat) } /** @@ -494,9 +442,9 @@ export class KmdApi { const bodyMeta = ListMultisigRequestMeta const mediaType = bodyMeta ? KmdApi.mediaFor(responseFormat) : undefined if (mediaType) headers['Content-Type'] = mediaType - const serializedBody = bodyMeta && body !== undefined ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : body + const serializedBody = body ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : undefined - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'POST', url: '/v1/multisig/list', path: {}, @@ -506,11 +454,7 @@ export class KmdApi { mediaType: mediaType, }) - const responseMeta = PostMultisigListResponseMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as PostMultisigListResponse + return AlgorandSerializer.decode(payload, PostMultisigListResponseMeta, responseFormat) } /** @@ -521,7 +465,7 @@ export class KmdApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = KmdApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/v1/wallets', path: {}, @@ -531,11 +475,7 @@ export class KmdApi { mediaType: undefined, }) - const responseMeta = GetWalletsResponseMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as GetWalletsResponse + return AlgorandSerializer.decode(payload, GetWalletsResponseMeta, responseFormat) } /** @@ -549,9 +489,9 @@ export class KmdApi { const bodyMeta = ReleaseWalletHandleTokenRequestMeta const mediaType = bodyMeta ? KmdApi.mediaFor(responseFormat) : undefined if (mediaType) headers['Content-Type'] = mediaType - const serializedBody = bodyMeta && body !== undefined ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : body + const serializedBody = body ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : undefined - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'POST', url: '/v1/wallet/release', path: {}, @@ -561,11 +501,7 @@ export class KmdApi { mediaType: mediaType, }) - const responseMeta = PostWalletReleaseResponseMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as PostWalletReleaseResponse + return AlgorandSerializer.decode(payload, PostWalletReleaseResponseMeta, responseFormat) } /** @@ -579,9 +515,9 @@ export class KmdApi { const bodyMeta = RenameWalletRequestMeta const mediaType = bodyMeta ? KmdApi.mediaFor(responseFormat) : undefined if (mediaType) headers['Content-Type'] = mediaType - const serializedBody = bodyMeta && body !== undefined ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : body + const serializedBody = body ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : undefined - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'POST', url: '/v1/wallet/rename', path: {}, @@ -591,11 +527,7 @@ export class KmdApi { mediaType: mediaType, }) - const responseMeta = PostWalletRenameResponseMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as PostWalletRenameResponse + return AlgorandSerializer.decode(payload, PostWalletRenameResponseMeta, responseFormat) } /** @@ -609,9 +541,9 @@ export class KmdApi { const bodyMeta = RenewWalletHandleTokenRequestMeta const mediaType = bodyMeta ? KmdApi.mediaFor(responseFormat) : undefined if (mediaType) headers['Content-Type'] = mediaType - const serializedBody = bodyMeta && body !== undefined ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : body + const serializedBody = body ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : undefined - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'POST', url: '/v1/wallet/renew', path: {}, @@ -621,11 +553,7 @@ export class KmdApi { mediaType: mediaType, }) - const responseMeta = PostWalletRenewResponseMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as PostWalletRenewResponse + return AlgorandSerializer.decode(payload, PostWalletRenewResponseMeta, responseFormat) } /** @@ -639,9 +567,9 @@ export class KmdApi { const bodyMeta = SignProgramMultisigRequestMeta const mediaType = bodyMeta ? KmdApi.mediaFor(responseFormat) : undefined if (mediaType) headers['Content-Type'] = mediaType - const serializedBody = bodyMeta && body !== undefined ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : body + const serializedBody = body ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : undefined - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'POST', url: '/v1/multisig/signprogram', path: {}, @@ -651,11 +579,7 @@ export class KmdApi { mediaType: mediaType, }) - const responseMeta = PostMultisigProgramSignResponseMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as PostMultisigProgramSignResponse + return AlgorandSerializer.decode(payload, PostMultisigProgramSignResponseMeta, responseFormat) } /** @@ -669,9 +593,9 @@ export class KmdApi { const bodyMeta = SignMultisigRequestMeta const mediaType = bodyMeta ? KmdApi.mediaFor(responseFormat) : undefined if (mediaType) headers['Content-Type'] = mediaType - const serializedBody = bodyMeta && body !== undefined ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : body + const serializedBody = body ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : undefined - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'POST', url: '/v1/multisig/sign', path: {}, @@ -681,11 +605,7 @@ export class KmdApi { mediaType: mediaType, }) - const responseMeta = PostMultisigTransactionSignResponseMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as PostMultisigTransactionSignResponse + return AlgorandSerializer.decode(payload, PostMultisigTransactionSignResponseMeta, responseFormat) } /** @@ -699,9 +619,9 @@ export class KmdApi { const bodyMeta = SignProgramRequestMeta const mediaType = bodyMeta ? KmdApi.mediaFor(responseFormat) : undefined if (mediaType) headers['Content-Type'] = mediaType - const serializedBody = bodyMeta && body !== undefined ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : body + const serializedBody = body ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : undefined - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'POST', url: '/v1/program/sign', path: {}, @@ -711,11 +631,7 @@ export class KmdApi { mediaType: mediaType, }) - const responseMeta = PostProgramSignResponseMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as PostProgramSignResponse + return AlgorandSerializer.decode(payload, PostProgramSignResponseMeta, responseFormat) } /** @@ -729,9 +645,9 @@ export class KmdApi { const bodyMeta = SignTransactionRequestMeta const mediaType = bodyMeta ? KmdApi.mediaFor(responseFormat) : undefined if (mediaType) headers['Content-Type'] = mediaType - const serializedBody = bodyMeta && body !== undefined ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : body + const serializedBody = body ? AlgorandSerializer.encode(body, bodyMeta, responseFormat) : undefined - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'POST', url: '/v1/transaction/sign', path: {}, @@ -741,11 +657,7 @@ export class KmdApi { mediaType: mediaType, }) - const responseMeta = PostTransactionSignResponseMeta - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as PostTransactionSignResponse + return AlgorandSerializer.decode(payload, PostTransactionSignResponseMeta, responseFormat) } /** @@ -756,7 +668,7 @@ export class KmdApi { const responseFormat: BodyFormat = 'json' headers['Accept'] = KmdApi.acceptFor(responseFormat) - const payload = await this.httpRequest.request({ + const payload = await this.httpRequest.request({ method: 'GET', url: '/swagger.json', path: {}, @@ -766,10 +678,6 @@ export class KmdApi { mediaType: undefined, }) - const responseMeta = undefined - if (responseMeta) { - return AlgorandSerializer.decode(payload, responseMeta, responseFormat) - } - return payload as string + return payload } } diff --git a/packages/kmd_client/src/core/codecs.ts b/packages/kmd_client/src/core/codecs.ts index 829dcd7b..214a543d 100644 --- a/packages/kmd_client/src/core/codecs.ts +++ b/packages/kmd_client/src/core/codecs.ts @@ -1,42 +1,28 @@ import { decode as msgpackDecode, encode as msgpackEncode } from 'algorand-msgpack' -export function encodeMsgPack(data: T): Uint8Array { +export function encodeMsgPack(data: ApiData): Uint8Array { return new Uint8Array(msgpackEncode(data, { sortKeys: true, ignoreUndefined: true })) } -export function decodeMsgPack(buffer: Uint8Array): T { - const map = msgpackDecode(buffer, { useMap: true }) as unknown - return mapToObject(map) as T +type MsgPackDecodeOptions = { + useMap: boolean + rawBinaryStringKeys: boolean + rawBinaryStringValues: boolean } -/** - * Converts a Map structure from msgpack decoding to a plain object structure. - * Maps are converted to objects recursively, except for the special case - * where the field name is "r" which remains as a Map. - */ -function mapToObject(value: unknown, fieldName?: string): unknown { - // Preserve Uint8Array as-is - if (value instanceof Uint8Array) { - return value - } else if (value instanceof Map) { - // Special case: keep "r" field as Map - if (fieldName === 'r') { - const newMap = new Map() - for (const [k, v] of value.entries()) { - newMap.set(k, mapToObject(v)) - } - return newMap - } - - // Convert Map to object - const obj: Record = {} - for (const [k, v] of value.entries()) { - obj[k] = mapToObject(v, k) - } - return obj - } else if (Array.isArray(value)) { - return value.map((item) => mapToObject(item)) - } - - return value +export function decodeMsgPack( + buffer: Uint8Array, + options: MsgPackDecodeOptions = { useMap: true, rawBinaryStringKeys: true, rawBinaryStringValues: true }, +): Map { + return msgpackDecode(buffer, options) as Map } +export type ApiData = + | null + | undefined + | string + | number + | bigint + | boolean + | Uint8Array + | object + | Map // TODO: NC - Do we ever have a string key? diff --git a/packages/kmd_client/src/core/model-runtime.ts b/packages/kmd_client/src/core/model-runtime.ts index ed41c188..07f6d681 100644 --- a/packages/kmd_client/src/core/model-runtime.ts +++ b/packages/kmd_client/src/core/model-runtime.ts @@ -1,19 +1,24 @@ import { - encodeSignedTransaction as transactEncodeSignedTransaction, - decodeSignedTransaction as transactDecodeSignedTransaction, + addressFromPublicKey, + decodedTransactionMapToObject, + fromSignedTransactionDto, + toSignedTransactionDto, type SignedTransaction, } from '@algorandfoundation/algokit-transact' -import { encodeMsgPack, decodeMsgPack } from './codecs' -import { toBase64, fromBase64 } from './serialization' +import { Buffer } from 'buffer' +import { ApiData, decodeMsgPack, encodeMsgPack } from './codecs' export type BodyFormat = 'json' | 'msgpack' | 'map' export interface ScalarFieldType { readonly kind: 'scalar' + // TODO: NC - Make this a type field readonly isBytes?: boolean readonly isBigint?: boolean + readonly isAddress?: boolean } +// TODO: NC - Needs to be renamed export interface CodecFieldType { readonly kind: 'codec' readonly codecKey: string @@ -34,7 +39,13 @@ export interface RecordFieldType { readonly value: FieldType } -export type FieldType = ScalarFieldType | CodecFieldType | ModelFieldType | ArrayFieldType | RecordFieldType +export interface MapFieldType { + readonly kind: 'map' + readonly keyType: 'number' | 'bigint' | 'bytes' + readonly value: FieldType +} + +export type FieldType = ScalarFieldType | CodecFieldType | ModelFieldType | ArrayFieldType | RecordFieldType | MapFieldType export interface FieldMetadata { readonly name: string @@ -61,39 +72,26 @@ export interface ModelMetadata { readonly passThrough?: FieldType } -// Registry for model metadata to avoid direct circular imports between model files -const modelMetaRegistry = new Map() - -export function registerModelMeta(name: string, meta: ModelMetadata): void { - modelMetaRegistry.set(name, meta) -} - -export function getModelMeta(name: string): ModelMetadata { - const meta = modelMetaRegistry.get(name) - if (!meta) throw new Error(`Model metadata not registered: ${name}`) - return meta -} - -export interface TypeCodec { - encode(value: TValue, format: BodyFormat): unknown - decode(value: unknown, format: BodyFormat): TValue +export interface EncodeableTypeConverter> { + beforeEncoding(value: T, format: BodyFormat): Record + afterDecoding(decoded: Record | Map, format: BodyFormat): T } -const codecRegistry = new Map>() - -export function registerCodec(key: string, codec: TypeCodec): void { - codecRegistry.set(key, codec as TypeCodec) -} +const encodeableTypeConverterRegistry = new Map>>() -export function getCodec(key: string): TypeCodec | undefined { - return codecRegistry.get(key) as TypeCodec | undefined +export function registerEncodeableTypeConverter(key: string, codec: EncodeableTypeConverter>): void { + encodeableTypeConverterRegistry.set(key, codec) } export class AlgorandSerializer { - static encode(value: unknown, meta: ModelMetadata, format: 'map'): Map - static encode(value: unknown, meta: ModelMetadata, format: 'json'): string - static encode(value: unknown, meta: ModelMetadata, format?: 'msgpack'): Uint8Array - static encode(value: unknown, meta: ModelMetadata, format: BodyFormat = 'msgpack'): Uint8Array | string | Map { + static encode(value: Record, meta: ModelMetadata, format: 'map'): Map + static encode(value: Record, meta: ModelMetadata, format: 'json'): string + static encode(value: Record, meta: ModelMetadata, format?: 'msgpack'): Uint8Array + static encode( + value: Record, + meta: ModelMetadata, + format: BodyFormat = 'msgpack', + ): Uint8Array | string | Map { if (format === 'map') { // For map format, use msgpack transformation to preserve types like bigint, then convert to nested Maps const wire = this.transform(value, meta, { direction: 'encode', format: 'msgpack' }) @@ -107,25 +105,25 @@ export class AlgorandSerializer { return typeof wire === 'string' ? wire : JSON.stringify(wire) } - static decode(payload: unknown, meta: ModelMetadata, format: BodyFormat = 'msgpack'): T { - let wire: unknown = payload + static decode(value: Uint8Array | string, meta: ModelMetadata, format: BodyFormat = 'msgpack'): T { + let wire: ApiData = value if (format === 'msgpack') { - if (payload instanceof Uint8Array) { - wire = decodeMsgPack(payload) + if (value instanceof Uint8Array) { + wire = decodeMsgPack(value) } - } else if (typeof payload === 'string') { - wire = JSON.parse(payload) + } else if (typeof value === 'string') { + wire = JSON.parse(value) } return this.transform(wire, meta, { direction: 'decode', format }) as T } - private static transform(value: unknown, meta: ModelMetadata, ctx: TransformContext): unknown { + private static transform(value: ApiData, meta: ModelMetadata, ctx: TransformContext): ApiData { if (value === undefined || value === null) { return value } if (meta.codecKey) { - return this.applyCodec(value, meta.codecKey, ctx) + return this.applyEncodeableTypeConversion(value, meta.codecKey, ctx) } switch (meta.kind) { @@ -139,20 +137,20 @@ export class AlgorandSerializer { } } - private static transformObject(value: unknown, meta: ModelMetadata, ctx: TransformContext): unknown { + private static transformObject(value: ApiData, meta: ModelMetadata, ctx: TransformContext): ApiData { const fields = meta.fields ?? [] - const hasFlattenedSignedTxn = fields.some((f) => f.flattened && f.type.kind === 'codec' && f.type.codecKey === 'SignedTransaction') + const hasFlattenedField = fields.some((f) => f.flattened) if (ctx.direction === 'encode') { - const src = value as Record - const out: Record = {} + const src = value as Record + const out: Record = {} for (const field of fields) { const fieldValue = src[field.name] if (fieldValue === undefined) continue const encoded = this.transformType(fieldValue, field.type, ctx) if (encoded === undefined && fieldValue === undefined) continue - if (field.flattened && field.type.kind === 'codec' && field.type.codecKey === 'SignedTransaction') { - // Merge signed transaction map into parent - const mapValue = encoded as Record + if (field.flattened) { + // Merge flattened field into parent + const mapValue = encoded as Record for (const [k, v] of Object.entries(mapValue ?? {})) out[k] = v continue } @@ -167,66 +165,206 @@ export class AlgorandSerializer { return out } - const src = value as Record - const out: Record = {} + // Decoding + const out: Record = {} const fieldByWire = new Map(fields.filter((f) => !!f.wireKey).map((field) => [field.wireKey as string, field])) - for (const [wireKey, wireValue] of Object.entries(src)) { - const field = fieldByWire.get(wireKey) + // Build a map of wire keys for each flattened field + const flattenedFieldWireKeys = new Map>() + if (hasFlattenedField) { + for (const field of fields) { + if (field.flattened && field.type.kind === 'model') { + const modelMeta = typeof field.type.meta === 'function' ? field.type.meta() : field.type.meta + const wireKeys = this.collectWireKeys(modelMeta) + flattenedFieldWireKeys.set(field, wireKeys) + } + } + } + + const entries = value instanceof Map ? Array.from(value.entries()) : Object.entries(value as Record) + const unmatchedEntries = new Map() + + for (const [key, wireValue] of entries) { + const wireKey = key instanceof Uint8Array ? Buffer.from(key).toString('utf-8') : key + const isStringKey = typeof wireKey === 'string' + const field = isStringKey ? fieldByWire.get(wireKey) : undefined + if (field) { const decoded = this.transformType(wireValue, field.type, ctx) - out[field.name] = decoded + out[field.name] = decoded === null && !field.nullable ? undefined : decoded continue } - if (meta.additionalProperties) { + + if (isStringKey && meta.additionalProperties) { out[wireKey] = this.transformType(wireValue, meta.additionalProperties, ctx) continue } - // If we have a flattened SignedTransaction, skip unknown keys (e.g., 'sig', 'txn') - if (!hasFlattenedSignedTxn) { - out[wireKey] = wireValue + + // Store unmatched entries for potential flattened field reconstruction + if (isStringKey) { + unmatchedEntries.set(wireKey, wireValue) + } + } + + // Reconstruct flattened fields from unmatched entries + if (hasFlattenedField) { + for (const field of fields) { + if (out[field.name] !== undefined) continue + if (field.flattened) { + if (field.type.kind === 'codec') { + // Reconstruct codec from entire object map + out[field.name] = this.applyEncodeableTypeConversion(value, field.type.codecKey, ctx) + } else if (field.type.kind === 'model') { + const modelMeta = typeof field.type.meta === 'function' ? field.type.meta() : field.type.meta + + // Check if this flattened model contains nested flattened codecs + const hasNestedCodec = this.hasNestedFlattenedCodec(modelMeta) + + let decoded: ApiData + if (hasNestedCodec) { + // If the model has nested flattened codecs, we need to pass the original value + // so the nested model can reconstruct its flattened codec fields + decoded = this.transform(value, modelMeta, ctx) + } else { + // Filter the wire data to only include keys belonging to this flattened model + const modelWireKeys = flattenedFieldWireKeys.get(field) + if (modelWireKeys) { + const filteredData: Record = {} + for (const [k, v] of unmatchedEntries.entries()) { + if (modelWireKeys.has(k)) { + filteredData[k] = v + } + } + // Also check if the original value is a Map and filter it + if (value instanceof Map) { + const filteredMap = new Map() + for (const [k, v] of value.entries()) { + const keyStr = k instanceof Uint8Array ? Buffer.from(k).toString('utf-8') : String(k) + if (typeof keyStr === 'string' && modelWireKeys.has(keyStr)) { + filteredMap.set(k as string | Uint8Array, v) + } + } + decoded = this.transform(filteredMap, modelMeta, ctx) + } else { + decoded = this.transform(filteredData, modelMeta, ctx) + } + } else { + decoded = undefined + } + } + + // If the field is optional and the decoded object is empty, set it to undefined + if (field.optional && decoded !== undefined && this.isEmptyObject(decoded)) { + out[field.name] = undefined + } else { + out[field.name] = decoded + } + } + } } } - // If there are flattened fields, attempt to reconstruct them from remaining keys by decoding - for (const field of fields) { - if (out[field.name] !== undefined) continue - if (field.flattened && field.type.kind === 'codec' && field.type.codecKey === 'SignedTransaction') { - // Reconstruct from entire object map - out[field.name] = this.applyCodec(src, 'SignedTransaction', ctx) + // Add any remaining unmatched entries if there are no flattened fields + if (!hasFlattenedField) { + for (const [k, v] of unmatchedEntries.entries()) { + out[k] = v } } return out } - private static transformType(value: unknown, type: FieldType, ctx: TransformContext): unknown { + private static collectWireKeys(meta: ModelMetadata): Set { + const wireKeys = new Set() + if (meta.kind !== 'object' || !meta.fields) return wireKeys + + for (const field of meta.fields) { + if (field.wireKey) { + wireKeys.add(field.wireKey) + } + if (field.flattened && field.type.kind === 'model') { + const childMeta = typeof field.type.meta === 'function' ? field.type.meta() : field.type.meta + const childKeys = this.collectWireKeys(childMeta) + for (const key of childKeys) { + wireKeys.add(key) + } + } + // Note: flattened codec fields don't have predictable wire keys, + // so they need to be handled differently during reconstruction + } + + return wireKeys + } + + private static hasNestedFlattenedCodec(meta: ModelMetadata): boolean { + if (meta.kind !== 'object' || !meta.fields) return false + + for (const field of meta.fields) { + if (field.flattened) { + if (field.type.kind === 'codec') { + return true + } + if (field.type.kind === 'model') { + const childMeta = typeof field.type.meta === 'function' ? field.type.meta() : field.type.meta + if (this.hasNestedFlattenedCodec(childMeta)) { + return true + } + } + } + } + + return false + } + + private static isEmptyObject(value: ApiData): boolean { + if (value === null || value === undefined) return true + if (typeof value !== 'object') return false + if (Array.isArray(value)) return false + if (value instanceof Uint8Array) return false + if (value instanceof Map) return value.size === 0 + + // Check if it's a plain object with no own properties (excluding undefined values) + const keys = Object.keys(value) + if (keys.length === 0) return true + + // Check if all properties are undefined + return keys.every((key) => (value as Record)[key] === undefined) + } + + private static transformType(value: ApiData, type: FieldType, ctx: TransformContext): ApiData { if (value === undefined || value === null) return value switch (type.kind) { case 'scalar': return this.transformScalar(value, type, ctx) case 'codec': - return this.applyCodec(value, type.codecKey, ctx) + return this.applyEncodeableTypeConversion(value, type.codecKey, ctx) case 'model': return this.transform(value, typeof type.meta === 'function' ? type.meta() : type.meta, ctx) case 'array': if (!Array.isArray(value)) return value return value.map((item) => this.transformType(item, type.item, ctx)) - case 'record': - if (typeof value !== 'object' || value === null) return value + case 'record': { + if ((!(value instanceof Map) && typeof value !== 'object') || value === null) return value + const entries = value instanceof Map ? Array.from(value.entries()) : Object.entries(value as Record) return Object.fromEntries( - Object.entries(value as Record).map(([k, v]) => [k, this.transformType(v, type.value, ctx)]), + entries.map(([k, v]) => { + const key = k instanceof Uint8Array ? Buffer.from(k).toString('utf-8') : k + return [key, this.transformType(v, type.value, ctx)] + }), ) + } + case 'map': + return this.transformMap(value, type, ctx) default: return value } } - private static transformScalar(value: unknown, meta: ScalarFieldType, ctx: TransformContext): unknown { + private static transformScalar(value: ApiData, meta: ScalarFieldType, ctx: TransformContext): ApiData { if (ctx.direction === 'encode') { if (meta.isBytes && ctx.format === 'json') { - if (value instanceof Uint8Array) return toBase64(value) + if (value instanceof Uint8Array) return Buffer.from(value).toString('base64') } if (meta.isBigint && ctx.format === 'json') { if (typeof value === 'bigint') return value.toString() @@ -237,7 +375,17 @@ export class AlgorandSerializer { } if (meta.isBytes && ctx.format === 'json' && typeof value === 'string') { - return fromBase64(value) + return new Uint8Array(Buffer.from(value, 'base64')) + } + + if (value instanceof Uint8Array) { + if (meta.isAddress) { + // TODO: NC - Fix all the address models to have this on it. + return addressFromPublicKey(value) + } else if (!meta.isBytes) { + return Buffer.from(value).toString('utf-8') + } + return value } if (meta.isBigint) { @@ -253,18 +401,61 @@ export class AlgorandSerializer { } } + if (value instanceof Map) { + const out: Record = {} + for (const [k, v] of value.entries()) { + const key = k instanceof Uint8Array ? Buffer.from(k).toString('utf-8') : k.toString() + out[key] = this.transformType(v, { kind: 'scalar', isBytes: v instanceof Uint8Array }, ctx) + } + return out + } + + if (Array.isArray(value)) { + return value.map((item) => this.transformType(item, { kind: 'scalar', isBytes: item instanceof Uint8Array }, ctx)) + } + return value } - private static applyCodec(value: unknown, codecKey: string, ctx: TransformContext): unknown { - const codec = codecRegistry.get(codecKey) + private static applyEncodeableTypeConversion(value: ApiData, typeKey: string, ctx: TransformContext): ApiData { + const codec = encodeableTypeConverterRegistry.get(typeKey) if (!codec) { - throw new Error(`Codec for "${codecKey}" is not registered`) + throw new Error(`Type converter for "${typeKey}" is not registered`) + } + + // TODO: NC - Need to properly guard against these conditions + if (ctx.direction === 'encode') { + if (value instanceof Map) { + throw new Error(`Cannot encode Map with type converter "${typeKey}"`) + } + return codec.beforeEncoding(value as Parameters[0], ctx.format) } - return ctx.direction === 'encode' ? codec.encode(value, ctx.format) : codec.decode(value, ctx.format) + + return codec.afterDecoding(value as Parameters[0], ctx.format) } - private static convertToNestedMaps(value: unknown): Map | unknown[] | unknown { + private static transformMap(value: ApiData, meta: MapFieldType, ctx: TransformContext): ApiData { + if (ctx.direction === 'encode') { + if (!(value instanceof Map)) return value + const result = new Map() + for (const [k, v] of value.entries()) { + const transformedValue = this.transformType(v, meta.value, ctx) + result.set(k, transformedValue) + } + return result + } + // Decoding + if ((!(value instanceof Map) && typeof value !== 'object') || value === null) return value + const entries = value instanceof Map ? Array.from(value.entries()) : Object.entries(value as Record) + const result = new Map() + for (const [k, v] of entries) { + const transformedValue = this.transformType(v, meta.value, ctx) + result.set(k, transformedValue) + } + return result + } + + private static convertToNestedMaps(value: ApiData): Map | ApiData[] | ApiData { if (value === null || value === undefined) { return value } @@ -282,8 +473,8 @@ export class AlgorandSerializer { } if (typeof value === 'object' && value !== null && !(value instanceof Uint8Array)) { - const map = new Map() - Object.entries(value as Record).forEach(([key, val]) => { + const map = new Map() + Object.entries(value as Record).forEach(([key, val]) => { map.set(key, this.convertToNestedMaps(val)) }) return map @@ -301,39 +492,23 @@ interface TransformContext { readonly format: BodyFormat } -const encodeSignedTransactionImpl = (value: unknown): Uint8Array => transactEncodeSignedTransaction(value as SignedTransaction) -const decodeSignedTransactionImpl = (value: Uint8Array): SignedTransaction => transactDecodeSignedTransaction(value) - -class SignedTransactionCodec implements TypeCodec { - encode(value: unknown, format: BodyFormat): unknown { - if (value == null) return value +class SignedTransactionConverter implements EncodeableTypeConverter { + beforeEncoding(value: SignedTransaction, format: BodyFormat): Record { if (format === 'json') { - if (value instanceof Uint8Array) return toBase64(value) - return toBase64(encodeSignedTransactionImpl(value)) - } - if (value instanceof Uint8Array) { - // Already canonical bytes; decode to structured map so parent encoding keeps map semantics - return decodeMsgPack(value) + throw new Error('JSON format not supported for SignedTransaction encoding') } - // Convert signed transaction object into canonical map representation - return decodeMsgPack(encodeSignedTransactionImpl(value)) + return toSignedTransactionDto(value) } - - decode(value: unknown, format: BodyFormat): unknown { - if (value == null) return value - if (format === 'json') { - if (typeof value === 'string') return decodeSignedTransactionImpl(fromBase64(value)) - if (value instanceof Uint8Array) return decodeSignedTransactionImpl(value) - return value + afterDecoding(value: Record | Map, format: BodyFormat): SignedTransaction { + if (format === 'json' || !(value instanceof Map)) { + throw new Error('JSON format not supported for SignedTransaction decoding') } - if (value instanceof Uint8Array) return decodeSignedTransactionImpl(value) - // Value is a decoded map; re-encode to bytes before handing to transact decoder - try { - return decodeSignedTransactionImpl(encodeMsgPack(value)) - } catch { - return value + if (!(value instanceof Map)) { + throw new Error('Invalid decoded msgpack format for SignedTransaction') } + const stxnDto = decodedTransactionMapToObject(value) as Parameters[0] + return fromSignedTransactionDto(stxnDto) } } -registerCodec('SignedTransaction', new SignedTransactionCodec()) +registerEncodeableTypeConverter('SignedTransaction', new SignedTransactionConverter()) diff --git a/packages/kmd_client/src/core/request.ts b/packages/kmd_client/src/core/request.ts index 706e60f7..0fedd516 100644 --- a/packages/kmd_client/src/core/request.ts +++ b/packages/kmd_client/src/core/request.ts @@ -85,7 +85,11 @@ export async function request( try { const ct = response.headers.get('content-type') ?? '' if (ct.includes('application/msgpack')) { - errorBody = decodeMsgPack(new Uint8Array(await response.arrayBuffer())) + errorBody = decodeMsgPack(new Uint8Array(await response.arrayBuffer()), { + useMap: false, + rawBinaryStringKeys: false, + rawBinaryStringValues: false, + }) } else if (ct.includes('application/json')) { errorBody = JSON.parse(await response.text()) } else { diff --git a/packages/kmd_client/src/core/serialization.ts b/packages/kmd_client/src/core/serialization.ts deleted file mode 100644 index 6be05428..00000000 --- a/packages/kmd_client/src/core/serialization.ts +++ /dev/null @@ -1,26 +0,0 @@ -export function toBase64(bytes: Uint8Array): string { - if (typeof Buffer !== 'undefined') { - return Buffer.from(bytes).toString('base64') - } - const globalRef: Record = globalThis as unknown as Record - const btoaFn = globalRef.btoa as ((value: string) => string) | undefined - if (typeof btoaFn === 'function') { - return btoaFn(String.fromCharCode(...bytes)) - } - throw new Error('Base64 encoding not supported in this environment') -} - -export function fromBase64(s: string): Uint8Array { - if (typeof Buffer !== 'undefined') { - return new Uint8Array(Buffer.from(s, 'base64')) - } - const globalRef: Record = globalThis as unknown as Record - const atobFn = globalRef.atob as ((value: string) => string) | undefined - if (typeof atobFn === 'function') { - const bin = atobFn(s) - const out = new Uint8Array(bin.length) - for (let i = 0; i < bin.length; i += 1) out[i] = bin.charCodeAt(i) - return out - } - throw new Error('Base64 decoding not supported in this environment') -} diff --git a/packages/kmd_client/src/index.ts b/packages/kmd_client/src/index.ts index 915506d5..58a6412d 100644 --- a/packages/kmd_client/src/index.ts +++ b/packages/kmd_client/src/index.ts @@ -2,7 +2,6 @@ export * from './core/client-config' export * from './core/base-http-request' export * from './core/fetch-http-request' export * from './core/api-error' -export * from './core/serialization' export * from './core/codecs' export * from './core/model-runtime' diff --git a/packages/kmd_client/src/models/create-wallet-request.ts b/packages/kmd_client/src/models/create-wallet-request.ts index 364921bf..d9f1adc8 100644 --- a/packages/kmd_client/src/models/create-wallet-request.ts +++ b/packages/kmd_client/src/models/create-wallet-request.ts @@ -21,7 +21,7 @@ export const CreateWalletRequestMeta: ModelMetadata = { wireKey: 'master_derivation_key', optional: true, nullable: false, - type: { kind: 'model', meta: () => MasterDerivationKeyMeta }, + type: { kind: 'model', meta: MasterDerivationKeyMeta }, }, { name: 'walletDriverName', diff --git a/packages/kmd_client/src/models/get-wallets-response.ts b/packages/kmd_client/src/models/get-wallets-response.ts index b25dcb26..0f99759b 100644 --- a/packages/kmd_client/src/models/get-wallets-response.ts +++ b/packages/kmd_client/src/models/get-wallets-response.ts @@ -35,7 +35,7 @@ export const GetWalletsResponseMeta: ModelMetadata = { wireKey: 'wallets', optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => WalletMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: WalletMeta } }, }, ], } diff --git a/packages/kmd_client/src/models/import-multisig-request.ts b/packages/kmd_client/src/models/import-multisig-request.ts index 0b174d49..595d0777 100644 --- a/packages/kmd_client/src/models/import-multisig-request.ts +++ b/packages/kmd_client/src/models/import-multisig-request.ts @@ -28,7 +28,7 @@ export const ImportMultisigRequestMeta: ModelMetadata = { wireKey: 'pks', optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => PublicKeyMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: PublicKeyMeta } }, }, { name: 'threshold', diff --git a/packages/kmd_client/src/models/multisig-sig.ts b/packages/kmd_client/src/models/multisig-sig.ts index fed03784..721ee287 100644 --- a/packages/kmd_client/src/models/multisig-sig.ts +++ b/packages/kmd_client/src/models/multisig-sig.ts @@ -20,7 +20,7 @@ export const MultisigSigMeta: ModelMetadata = { wireKey: 'Subsigs', optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => MultisigSubsigMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: MultisigSubsigMeta } }, }, { name: 'threshold', diff --git a/packages/kmd_client/src/models/multisig-subsig.ts b/packages/kmd_client/src/models/multisig-subsig.ts index 2f425082..8b44c4c7 100644 --- a/packages/kmd_client/src/models/multisig-subsig.ts +++ b/packages/kmd_client/src/models/multisig-subsig.ts @@ -22,14 +22,14 @@ export const MultisigSubsigMeta: ModelMetadata = { wireKey: 'Key', optional: true, nullable: false, - type: { kind: 'model', meta: () => PublicKeyMeta }, + type: { kind: 'model', meta: PublicKeyMeta }, }, { name: 'sig', wireKey: 'Sig', optional: true, nullable: false, - type: { kind: 'model', meta: () => SignatureMeta }, + type: { kind: 'model', meta: SignatureMeta }, }, ], } diff --git a/packages/kmd_client/src/models/post-master-key-export-response.ts b/packages/kmd_client/src/models/post-master-key-export-response.ts index dbf36727..0df944a0 100644 --- a/packages/kmd_client/src/models/post-master-key-export-response.ts +++ b/packages/kmd_client/src/models/post-master-key-export-response.ts @@ -28,7 +28,7 @@ export const PostMasterKeyExportResponseMeta: ModelMetadata = { wireKey: 'master_derivation_key', optional: true, nullable: false, - type: { kind: 'model', meta: () => MasterDerivationKeyMeta }, + type: { kind: 'model', meta: MasterDerivationKeyMeta }, }, { name: 'message', diff --git a/packages/kmd_client/src/models/post-multisig-export-response.ts b/packages/kmd_client/src/models/post-multisig-export-response.ts index fd9243db..da3fceee 100644 --- a/packages/kmd_client/src/models/post-multisig-export-response.ts +++ b/packages/kmd_client/src/models/post-multisig-export-response.ts @@ -44,7 +44,7 @@ export const PostMultisigExportResponseMeta: ModelMetadata = { wireKey: 'pks', optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => PublicKeyMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: PublicKeyMeta } }, }, { name: 'threshold', diff --git a/packages/kmd_client/src/models/post-wallet-info-response.ts b/packages/kmd_client/src/models/post-wallet-info-response.ts index 6c30f05a..99477d8c 100644 --- a/packages/kmd_client/src/models/post-wallet-info-response.ts +++ b/packages/kmd_client/src/models/post-wallet-info-response.ts @@ -35,7 +35,7 @@ export const PostWalletInfoResponseMeta: ModelMetadata = { wireKey: 'wallet_handle', optional: true, nullable: false, - type: { kind: 'model', meta: () => WalletHandleMeta }, + type: { kind: 'model', meta: WalletHandleMeta }, }, ], } diff --git a/packages/kmd_client/src/models/post-wallet-rename-response.ts b/packages/kmd_client/src/models/post-wallet-rename-response.ts index 43ab2bf7..53875dbc 100644 --- a/packages/kmd_client/src/models/post-wallet-rename-response.ts +++ b/packages/kmd_client/src/models/post-wallet-rename-response.ts @@ -35,7 +35,7 @@ export const PostWalletRenameResponseMeta: ModelMetadata = { wireKey: 'wallet', optional: true, nullable: false, - type: { kind: 'model', meta: () => WalletMeta }, + type: { kind: 'model', meta: WalletMeta }, }, ], } diff --git a/packages/kmd_client/src/models/post-wallet-renew-response.ts b/packages/kmd_client/src/models/post-wallet-renew-response.ts index 078061e4..bf9e5026 100644 --- a/packages/kmd_client/src/models/post-wallet-renew-response.ts +++ b/packages/kmd_client/src/models/post-wallet-renew-response.ts @@ -35,7 +35,7 @@ export const PostWalletRenewResponseMeta: ModelMetadata = { wireKey: 'wallet_handle', optional: true, nullable: false, - type: { kind: 'model', meta: () => WalletHandleMeta }, + type: { kind: 'model', meta: WalletHandleMeta }, }, ], } diff --git a/packages/kmd_client/src/models/post-wallet-response.ts b/packages/kmd_client/src/models/post-wallet-response.ts index cb91a883..a471bddb 100644 --- a/packages/kmd_client/src/models/post-wallet-response.ts +++ b/packages/kmd_client/src/models/post-wallet-response.ts @@ -35,7 +35,7 @@ export const PostWalletResponseMeta: ModelMetadata = { wireKey: 'wallet', optional: true, nullable: false, - type: { kind: 'model', meta: () => WalletMeta }, + type: { kind: 'model', meta: WalletMeta }, }, ], } diff --git a/packages/kmd_client/src/models/sign-multisig-request.ts b/packages/kmd_client/src/models/sign-multisig-request.ts index 2f798e25..1e3bcb4f 100644 --- a/packages/kmd_client/src/models/sign-multisig-request.ts +++ b/packages/kmd_client/src/models/sign-multisig-request.ts @@ -27,21 +27,21 @@ export const SignMultisigRequestMeta: ModelMetadata = { wireKey: 'partial_multisig', optional: true, nullable: false, - type: { kind: 'model', meta: () => MultisigSigMeta }, + type: { kind: 'model', meta: MultisigSigMeta }, }, { name: 'publicKey', wireKey: 'public_key', optional: true, nullable: false, - type: { kind: 'model', meta: () => PublicKeyMeta }, + type: { kind: 'model', meta: PublicKeyMeta }, }, { name: 'signer', wireKey: 'signer', optional: true, nullable: false, - type: { kind: 'model', meta: () => DigestMeta }, + type: { kind: 'model', meta: DigestMeta }, }, { name: 'transaction', diff --git a/packages/kmd_client/src/models/sign-program-multisig-request.ts b/packages/kmd_client/src/models/sign-program-multisig-request.ts index f92243e2..ed404d5c 100644 --- a/packages/kmd_client/src/models/sign-program-multisig-request.ts +++ b/packages/kmd_client/src/models/sign-program-multisig-request.ts @@ -40,14 +40,14 @@ export const SignProgramMultisigRequestMeta: ModelMetadata = { wireKey: 'partial_multisig', optional: true, nullable: false, - type: { kind: 'model', meta: () => MultisigSigMeta }, + type: { kind: 'model', meta: MultisigSigMeta }, }, { name: 'publicKey', wireKey: 'public_key', optional: true, nullable: false, - type: { kind: 'model', meta: () => PublicKeyMeta }, + type: { kind: 'model', meta: PublicKeyMeta }, }, { name: 'useLegacyMsig', diff --git a/packages/kmd_client/src/models/sign-transaction-request.ts b/packages/kmd_client/src/models/sign-transaction-request.ts index 14d4cf48..e0b6b727 100644 --- a/packages/kmd_client/src/models/sign-transaction-request.ts +++ b/packages/kmd_client/src/models/sign-transaction-request.ts @@ -28,7 +28,7 @@ export const SignTransactionRequestMeta: ModelMetadata = { wireKey: 'public_key', optional: true, nullable: false, - type: { kind: 'model', meta: () => PublicKeyMeta }, + type: { kind: 'model', meta: PublicKeyMeta }, }, { name: 'transaction', diff --git a/packages/kmd_client/src/models/wallet-handle.ts b/packages/kmd_client/src/models/wallet-handle.ts index 650c2b2c..6e170673 100644 --- a/packages/kmd_client/src/models/wallet-handle.ts +++ b/packages/kmd_client/src/models/wallet-handle.ts @@ -27,7 +27,7 @@ export const WalletHandleMeta: ModelMetadata = { wireKey: 'wallet', optional: true, nullable: false, - type: { kind: 'model', meta: () => WalletMeta }, + type: { kind: 'model', meta: WalletMeta }, }, ], } diff --git a/packages/kmd_client/src/models/wallet.ts b/packages/kmd_client/src/models/wallet.ts index f558a0e2..b96229af 100644 --- a/packages/kmd_client/src/models/wallet.ts +++ b/packages/kmd_client/src/models/wallet.ts @@ -58,7 +58,7 @@ export const WalletMeta: ModelMetadata = { wireKey: 'supported_txs', optional: true, nullable: false, - type: { kind: 'array', item: { kind: 'model', meta: () => TxTypeMeta } }, + type: { kind: 'array', item: { kind: 'model', meta: TxTypeMeta } }, }, ], } diff --git a/packages/transact/src/encoding/codecs.ts b/packages/transact/src/encoding/codecs.ts index e9bc4c14..7dbcbbc9 100644 --- a/packages/transact/src/encoding/codecs.ts +++ b/packages/transact/src/encoding/codecs.ts @@ -101,6 +101,20 @@ class BytesCodec extends Codec { } } +class FixedBytesCodec extends Codec { + constructor(private length: number) { + super() + } + + public defaultValue(): Uint8Array { + return new Uint8Array(this.length) + } + + protected isDefaultValue(value: Uint8Array): boolean { + return value.byteLength === this.length && value.every((byte) => byte === 0) + } +} + class BooleanCodec extends Codec { public defaultValue(): boolean { return false @@ -150,6 +164,9 @@ export const bigIntCodec = new BigIntCodec() export const stringCodec = new StringCodec() export const addressCodec = new AddressCodec() export const bytesCodec = new BytesCodec() +export const fixedBytes32Codec = new FixedBytesCodec(32) +export const fixedBytes64Codec = new FixedBytesCodec(64) +export const fixedBytes1793Codec = new FixedBytesCodec(0x701) export const booleanCodec = new BooleanCodec() export const bytesArrayCodec = new ArrayCodec(bytesCodec) export const addressArrayCodec = new ArrayCodec(addressCodec) diff --git a/packages/transact/src/encoding/msgpack.ts b/packages/transact/src/encoding/msgpack.ts index d47d8a7b..815419c3 100644 --- a/packages/transact/src/encoding/msgpack.ts +++ b/packages/transact/src/encoding/msgpack.ts @@ -1,31 +1,38 @@ -import { encode as msgpackEncode, decode as msgpackDecode } from 'algorand-msgpack' +import { decode as msgpackDecode, encode as msgpackEncode } from 'algorand-msgpack' +import { SignedTransactionDto } from './signed-transaction-dto' +import { TransactionDto } from './transaction-dto' -export function encodeMsgpack(data: T): Uint8Array { +export function encodeMsgpack(data: T): Uint8Array { return new Uint8Array(msgpackEncode(data, { sortKeys: true, ignoreUndefined: true })) } -export function decodeMsgpack(encoded: Uint8Array): T { - // The message pack needs to be decoded into map first to support Maps with bigint as key +export function decodeMsgpack(encoded: Uint8Array): T { + // The message pack needs to be decoded into map, so we support number, bigint and Uint8Array keys. + // Additionally we need to use rawBinaryStrings for both keys and values to avoid incorrect utf-8 decoding. // After that, the map is converted to the targeted object - const map = msgpackDecode(encoded, { useMap: true }) as unknown - return mapToObject(map) as T + const map = msgpackDecode(encoded, { useMap: true, rawBinaryStringKeys: true, rawBinaryStringValues: true }) as unknown + return decodedMapToObject(map) as T } /** - * Converts a Map structure from msgpack decoding to a plain object structure. + * Converts a decoded msgpack Map structure to a plain object structure. * Maps are converted to objects recursively, except for the special case * where the field name is "r" which remains as a Map. */ -export function mapToObject(value: unknown, fieldName?: string): unknown { - // Preserve Uint8Array as-is +export function decodedMapToObject(value: unknown, fieldName?: string): unknown { + // Convert Uint8Array to string for specific fields, otherwise preserve as-is if (value instanceof Uint8Array) { + if (fieldName && ['type', 'gen', 'un', 'an', 'au'].includes(fieldName)) { + return Buffer.from(value).toString('utf-8') + } return value } else if (value instanceof Map) { // Special case: keep "r" field as Map if (fieldName === 'r') { const newMap = new Map() for (const [k, v] of value.entries()) { - newMap.set(k, mapToObject(v)) + const normalisedKey = k instanceof Uint8Array ? Buffer.from(k).toString('utf-8') : k + newMap.set(normalisedKey, decodedMapToObject(v, normalisedKey)) } return newMap } @@ -33,11 +40,12 @@ export function mapToObject(value: unknown, fieldName?: string): unknown { // Convert Map to object const obj: Record = {} for (const [k, v] of value.entries()) { - obj[k] = mapToObject(v, k) + const normalisedKey = k instanceof Uint8Array ? Buffer.from(k).toString('utf-8') : k + obj[normalisedKey] = decodedMapToObject(v, normalisedKey) } return obj } else if (Array.isArray(value)) { - return value.map((item) => mapToObject(item)) + return value.map((item) => decodedMapToObject(item, fieldName)) } return value diff --git a/packages/transact/src/encoding/signed-transaction-dto.ts b/packages/transact/src/encoding/signed-transaction-dto.ts index 7cac0328..894110a0 100644 --- a/packages/transact/src/encoding/signed-transaction-dto.ts +++ b/packages/transact/src/encoding/signed-transaction-dto.ts @@ -59,6 +59,9 @@ export type LogicSignatureDto = { /** Signature for delegated logic sig (optional) */ sig?: Uint8Array - /** Multisig for delegated logic sig (optional) */ + /** Legacy multisig for delegated logic sig (optional) */ msig?: MultisigSignatureDto + + /** Multisig for delegated logic sig (optional) */ + lmsig?: MultisigSignatureDto } diff --git a/packages/transact/src/index.ts b/packages/transact/src/index.ts index b7bb5f29..53d94fc8 100644 --- a/packages/transact/src/index.ts +++ b/packages/transact/src/index.ts @@ -20,6 +20,8 @@ export { decodeSignedTransactions, encodeSignedTransaction, encodeSignedTransactions, + fromSignedTransactionDto, + toSignedTransactionDto, type LogicSignature, type MultisigSignature, type MultisigSubsignature, @@ -42,3 +44,5 @@ export { newMultisigSignature, participantsFromMultisigSignature, } from './multisig' + +export { decodedMapToObject as decodedTransactionMapToObject } from './encoding/msgpack' diff --git a/packages/transact/src/transactions/signed-transaction.ts b/packages/transact/src/transactions/signed-transaction.ts index 1de7c85e..1b7845da 100644 --- a/packages/transact/src/transactions/signed-transaction.ts +++ b/packages/transact/src/transactions/signed-transaction.ts @@ -1,4 +1,4 @@ -import { addressCodec, bytesCodec, numberCodec, OmitEmptyObjectCodec } from '../encoding/codecs' +import { addressCodec, bytesCodec, fixedBytes64Codec, numberCodec, OmitEmptyObjectCodec } from '../encoding/codecs' import { decodeMsgpack, encodeMsgpack } from '../encoding/msgpack' import { LogicSignatureDto, MultisigSignatureDto, SignedTransactionDto } from '../encoding/signed-transaction-dto' import { fromTransactionDto, toTransactionDto, Transaction, validateTransaction } from './transaction' @@ -94,9 +94,14 @@ export type LogicSignature = { signature?: Uint8Array /** - * Multisig for delegated logic sig + * Legacy multisig for delegated logic sig */ multiSignature?: MultisigSignature + + /** + * Multisig for delegated logic sig + */ + logicMultiSignature?: MultisigSignature } /** @@ -156,9 +161,6 @@ function validateSignedTransaction(signedTransaction: SignedTransaction): void { const sigTypes = [signedTransaction.signature, signedTransaction.multiSignature, signedTransaction.logicSignature] const setSigCount = sigTypes.filter((sig) => sig !== undefined).length - if (setSigCount === 0) { - throw new Error('At least one signature type must be set') - } if (setSigCount > 1) { throw new Error(`Only one signature type can be set, found ${setSigCount}`) } @@ -179,18 +181,18 @@ function toMultisigSignatureDto(multisigSignature: MultisigSignature): MultisigS thr: numberCodec.encode(multisigSignature.threshold), subsig: multisigSignature.subsignatures.map((subsig) => ({ pk: addressCodec.encode(subsig.address), - s: bytesCodec.encode(subsig.signature), + s: fixedBytes64Codec.encode(subsig.signature), })), }) } -function toSignedTransactionDto(signedTransaction: SignedTransaction): SignedTransactionDto { +export function toSignedTransactionDto(signedTransaction: SignedTransaction): SignedTransactionDto { const stx_dto: SignedTransactionDto = { txn: toTransactionDto(signedTransaction.txn), } if (signedTransaction.signature) { - stx_dto.sig = bytesCodec.encode(signedTransaction.signature) + stx_dto.sig = fixedBytes64Codec.encode(signedTransaction.signature) } if (signedTransaction.multiSignature) { @@ -201,10 +203,13 @@ function toSignedTransactionDto(signedTransaction: SignedTransaction): SignedTra stx_dto.lsig = logicSignatureDtoCodec.encode({ l: bytesCodec.encode(signedTransaction.logicSignature.logic), arg: signedTransaction.logicSignature.args?.map((arg) => bytesCodec.encode(arg) ?? bytesCodec.defaultValue()), - sig: bytesCodec.encode(signedTransaction.logicSignature.signature), - ...(signedTransaction.logicSignature.multiSignature - ? { msig: toMultisigSignatureDto(signedTransaction.logicSignature.multiSignature) } - : undefined), + sig: fixedBytes64Codec.encode(signedTransaction.logicSignature.signature), + ...(signedTransaction.logicSignature.multiSignature && { + msig: toMultisigSignatureDto(signedTransaction.logicSignature.multiSignature), + }), + ...(signedTransaction.logicSignature.logicMultiSignature && { + lmsig: toMultisigSignatureDto(signedTransaction.logicSignature.logicMultiSignature), + }), }) } @@ -223,36 +228,48 @@ function fromMultisigSignatureDto(msigDto: MultisigSignatureDto): MultisigSignat msigDto.subsig?.map((subsigData) => { return { address: addressCodec.decode(subsigData.pk), - signature: bytesCodec.decodeOptional(subsigData.s), + signature: fixedBytes64Codec.decodeOptional(subsigData.s), } satisfies MultisigSubsignature }) ?? [], }) } -function fromSignedTransactionDto(signedTransactionDto: SignedTransactionDto): SignedTransaction { +export function fromSignedTransactionDto(signedTransactionDto: SignedTransactionDto): SignedTransaction { const stx: SignedTransaction = { txn: fromTransactionDto(signedTransactionDto.txn), } - if (signedTransactionDto.sig) { - stx.signature = bytesCodec.decodeOptional(signedTransactionDto.sig) + const signature = signedTransactionDto.sig && fixedBytes64Codec.decodeOptional(signedTransactionDto.sig) + if (signature) { + stx.signature = signature } - if (signedTransactionDto.msig) { - stx.multiSignature = fromMultisigSignatureDto(signedTransactionDto.msig) + const multiSignature = signedTransactionDto.msig && fromMultisigSignatureDto(signedTransactionDto.msig) + if (multiSignature) { + stx.multiSignature = multiSignature } if (signedTransactionDto.lsig) { - stx.logicSignature = logicSignatureCodec.decodeOptional({ + const args = signedTransactionDto.lsig.arg?.map((arg) => bytesCodec.decode(arg)) + const signature = fixedBytes64Codec.decodeOptional(signedTransactionDto.lsig.sig) + const multiSignature = signedTransactionDto.lsig.msig && fromMultisigSignatureDto(signedTransactionDto.lsig.msig) + const logicMultiSignature = signedTransactionDto.lsig.lmsig && fromMultisigSignatureDto(signedTransactionDto.lsig.lmsig) + + const logicSignature = logicSignatureCodec.decodeOptional({ logic: bytesCodec.decode(signedTransactionDto.lsig.l), - args: signedTransactionDto.lsig.arg?.map((arg) => bytesCodec.decode(arg)), - signature: bytesCodec.decodeOptional(signedTransactionDto.lsig.sig), - ...(signedTransactionDto.lsig.msig ? { multiSignature: fromMultisigSignatureDto(signedTransactionDto.lsig.msig) } : undefined), + ...(args && { args }), + ...(signature && { signature }), + ...(multiSignature && { multiSignature }), + ...(logicMultiSignature && { logicMultiSignature }), }) + if (logicSignature) { + stx.logicSignature = logicSignature + } } - if (signedTransactionDto.sgnr) { - stx.authAddress = addressCodec.decodeOptional(signedTransactionDto.sgnr) + const authAddress = signedTransactionDto.sgnr && addressCodec.decodeOptional(signedTransactionDto.sgnr) + if (authAddress) { + stx.authAddress = authAddress } return stx diff --git a/packages/transact/src/transactions/transaction.ts b/packages/transact/src/transactions/transaction.ts index df08ccea..4ba14971 100644 --- a/packages/transact/src/transactions/transaction.ts +++ b/packages/transact/src/transactions/transaction.ts @@ -18,6 +18,9 @@ import { booleanCodec, bytesArrayCodec, bytesCodec, + fixedBytes1793Codec, + fixedBytes32Codec, + fixedBytes64Codec, numberCodec, stringCodec, } from '../encoding/codecs' @@ -308,8 +311,8 @@ export function validateTransaction(transaction: Transaction): void { */ export function encodeTransactionRaw(transaction: Transaction): Uint8Array { validateTransaction(transaction) - const encodingData = toTransactionDto(transaction) - return encodeMsgpack(encodingData) + const transactionDto = toTransactionDto(transaction) + return encodeMsgpack(transactionDto) } /** @@ -558,12 +561,12 @@ export function toTransactionDto(transaction: Transaction): TransactionDto { lv: bigIntCodec.encode(transaction.lastValid), snd: addressCodec.encode(transaction.sender), gen: stringCodec.encode(transaction.genesisId), - gh: bytesCodec.encode(transaction.genesisHash), + gh: fixedBytes32Codec.encode(transaction.genesisHash), fee: bigIntCodec.encode(transaction.fee), note: bytesCodec.encode(transaction.note), - lx: bytesCodec.encode(transaction.lease), + lx: fixedBytes32Codec.encode(transaction.lease), rekey: addressCodec.encode(transaction.rekeyTo), - grp: bytesCodec.encode(transaction.group), + grp: fixedBytes32Codec.encode(transaction.group), } // Add transaction type specific fields @@ -591,7 +594,7 @@ export function toTransactionDto(transaction: Transaction): TransactionDto { un: stringCodec.encode(transaction.assetConfig.unitName), an: stringCodec.encode(transaction.assetConfig.assetName), au: stringCodec.encode(transaction.assetConfig.url), - am: bytesCodec.encode(transaction.assetConfig.metadataHash), + am: fixedBytes32Codec.encode(transaction.assetConfig.metadataHash), m: addressCodec.encode(transaction.assetConfig.manager), f: addressCodec.encode(transaction.assetConfig.freeze), c: addressCodec.encode(transaction.assetConfig.clawback), @@ -748,12 +751,12 @@ export function toTransactionDto(transaction: Transaction): TransactionDto { } if (transaction.keyRegistration) { - txDto.votekey = bytesCodec.encode(transaction.keyRegistration.voteKey) - txDto.selkey = bytesCodec.encode(transaction.keyRegistration.selectionKey) + txDto.votekey = fixedBytes32Codec.encode(transaction.keyRegistration.voteKey) + txDto.selkey = fixedBytes32Codec.encode(transaction.keyRegistration.selectionKey) txDto.votefst = bigIntCodec.encode(transaction.keyRegistration.voteFirst) txDto.votelst = bigIntCodec.encode(transaction.keyRegistration.voteLast) txDto.votekd = bigIntCodec.encode(transaction.keyRegistration.voteKeyDilution) - txDto.sprfkey = bytesCodec.encode(transaction.keyRegistration.stateProofKey) + txDto.sprfkey = fixedBytes64Codec.encode(transaction.keyRegistration.stateProofKey) txDto.nonpart = booleanCodec.encode(transaction.keyRegistration.nonParticipation) } @@ -761,14 +764,14 @@ export function toTransactionDto(transaction: Transaction): TransactionDto { txDto.hb = heartbeatParamsDtoCodec.encode({ a: addressCodec.encode(transaction.heartbeat.address), prf: heartbeatProofDtoCodec.encode({ - s: bytesCodec.encode(transaction.heartbeat.proof.sig), - p: bytesCodec.encode(transaction.heartbeat.proof.pk), - p2: bytesCodec.encode(transaction.heartbeat.proof.pk2), - p1s: bytesCodec.encode(transaction.heartbeat.proof.pk1Sig), - p2s: bytesCodec.encode(transaction.heartbeat.proof.pk2Sig), + s: fixedBytes64Codec.encode(transaction.heartbeat.proof.sig), + p: fixedBytes32Codec.encode(transaction.heartbeat.proof.pk), + p2: fixedBytes32Codec.encode(transaction.heartbeat.proof.pk2), + p1s: fixedBytes64Codec.encode(transaction.heartbeat.proof.pk1Sig), + p2s: fixedBytes64Codec.encode(transaction.heartbeat.proof.pk2Sig), }), sd: bytesCodec.encode(transaction.heartbeat.seed), - vid: bytesCodec.encode(transaction.heartbeat.voteId), + vid: fixedBytes32Codec.encode(transaction.heartbeat.voteId), kd: bigIntCodec.encode(transaction.heartbeat.keyDilution), }) } @@ -795,14 +798,14 @@ export function toTransactionDto(transaction: Transaction): TransactionDto { idx: bigIntCodec.encode(reveal.sigslot.sig.vectorCommitmentIndex), prf: toMerkleArrayProofDto(reveal.sigslot.sig.proof), vkey: { - k: bytesCodec.encode(reveal.sigslot.sig.verifyingKey.publicKey), + k: fixedBytes1793Codec.encode(reveal.sigslot.sig.verifyingKey.publicKey), }, }, l: bigIntCodec.encode(reveal.sigslot.lowerSigWeight), }, p: { p: { - cmt: bytesCodec.encode(reveal.participant.verifier.commitment), + cmt: fixedBytes64Codec.encode(reveal.participant.verifier.commitment), lf: bigIntCodec.encode(reveal.participant.verifier.keyLifetime), }, w: bigIntCodec.encode(reveal.participant.weight), @@ -831,170 +834,206 @@ export function toTransactionDto(transaction: Transaction): TransactionDto { export function fromTransactionDto(transactionDto: TransactionDto): Transaction { const transactionType = fromTransactionTypeDto(transactionDto.type) + const fee = bigIntCodec.decodeOptional(transactionDto.fee) + const genesisId = stringCodec.decodeOptional(transactionDto.gen) + const genesisHash = fixedBytes32Codec.decodeOptional(transactionDto.gh) + const note = bytesCodec.decodeOptional(transactionDto.note) + const lease = fixedBytes32Codec.decodeOptional(transactionDto.lx) + const rekeyTo = addressCodec.decodeOptional(transactionDto.rekey) + const group = fixedBytes32Codec.decodeOptional(transactionDto.grp) + const tx: Transaction = { type: transactionType, sender: addressCodec.decode(transactionDto.snd), firstValid: bigIntCodec.decode(transactionDto.fv), lastValid: bigIntCodec.decode(transactionDto.lv), - fee: bigIntCodec.decodeOptional(transactionDto.fee), - genesisId: stringCodec.decodeOptional(transactionDto.gen), - genesisHash: bytesCodec.decodeOptional(transactionDto.gh), - note: bytesCodec.decodeOptional(transactionDto.note), - lease: bytesCodec.decodeOptional(transactionDto.lx), - rekeyTo: addressCodec.decodeOptional(transactionDto.rekey), - group: bytesCodec.decodeOptional(transactionDto.grp), + ...(fee && { fee }), + ...(genesisId && { genesisId }), + ...(genesisHash && { genesisHash }), + ...(note && { note }), + ...(lease && { lease }), + ...(rekeyTo && { rekeyTo }), + ...(group && { group }), } // Add transaction type specific fields switch (transactionType) { - case TransactionType.Payment: + case TransactionType.Payment: { + const paymentCloseRemainderTo = addressCodec.decodeOptional(transactionDto.close) tx.payment = { amount: bigIntCodec.decode(transactionDto.amt), receiver: addressCodec.decode(transactionDto.rcv), - closeRemainderTo: addressCodec.decodeOptional(transactionDto.close), + ...(paymentCloseRemainderTo && { closeRemainderTo: paymentCloseRemainderTo }), } break - case TransactionType.AssetTransfer: + } + case TransactionType.AssetTransfer: { + const assetTransferCloseRemainderTo = addressCodec.decodeOptional(transactionDto.aclose) + const assetSender = addressCodec.decodeOptional(transactionDto.asnd) tx.assetTransfer = { assetId: bigIntCodec.decode(transactionDto.xaid), amount: bigIntCodec.decode(transactionDto.aamt), receiver: addressCodec.decode(transactionDto.arcv), - closeRemainderTo: addressCodec.decodeOptional(transactionDto.aclose), - assetSender: addressCodec.decodeOptional(transactionDto.asnd), + ...(assetTransferCloseRemainderTo && { closeRemainderTo: assetTransferCloseRemainderTo }), + ...(assetSender && { assetSender }), } break - case TransactionType.AssetConfig: + } + case TransactionType.AssetConfig: { + const assetParams = transactionDto.apar + let assetConfigParams: Omit | undefined = undefined + + if (assetParams) { + const total = bigIntCodec.decodeOptional(assetParams.t) + const decimals = numberCodec.decodeOptional(assetParams.dc) + const defaultFrozen = booleanCodec.decodeOptional(assetParams.df) + const unitName = stringCodec.decodeOptional(assetParams.un) + const assetName = stringCodec.decodeOptional(assetParams.an) + const url = stringCodec.decodeOptional(assetParams.au) + const metadataHash = fixedBytes32Codec.decodeOptional(assetParams.am) + const manager = addressCodec.decodeOptional(assetParams.m) + const reserve = addressCodec.decodeOptional(assetParams.r) + const freeze = addressCodec.decodeOptional(assetParams.f) + const clawback = addressCodec.decodeOptional(assetParams.c) + + assetConfigParams = { + ...(total !== undefined && { total }), + ...(decimals !== undefined && { decimals }), + ...(defaultFrozen !== undefined && { defaultFrozen }), + ...(unitName && { unitName }), + ...(assetName && { assetName }), + ...(url && { url }), + ...(metadataHash && { metadataHash }), + ...(manager && { manager }), + ...(reserve && { reserve }), + ...(freeze && { freeze }), + ...(clawback && { clawback }), + } + } + tx.assetConfig = { assetId: bigIntCodec.decode(transactionDto.caid), - ...(transactionDto.apar !== undefined - ? { - total: bigIntCodec.decodeOptional(transactionDto.apar.t), - decimals: numberCodec.decodeOptional(transactionDto.apar.dc), - defaultFrozen: booleanCodec.decodeOptional(transactionDto.apar.df), - unitName: stringCodec.decodeOptional(transactionDto.apar.un), - assetName: stringCodec.decodeOptional(transactionDto.apar.an), - url: stringCodec.decodeOptional(transactionDto.apar.au), - metadataHash: bytesCodec.decodeOptional(transactionDto.apar.am), - manager: addressCodec.decodeOptional(transactionDto.apar.m), - reserve: addressCodec.decodeOptional(transactionDto.apar.r), - freeze: addressCodec.decodeOptional(transactionDto.apar.f), - clawback: addressCodec.decodeOptional(transactionDto.apar.c), - } - : undefined), + ...(assetConfigParams !== undefined && Object.keys(assetConfigParams).length > 0 && assetConfigParams), } break - case TransactionType.AssetFreeze: + } + case TransactionType.AssetFreeze: { tx.assetFreeze = { assetId: bigIntCodec.decode(transactionDto.faid), freezeTarget: addressCodec.decode(transactionDto.fadd), frozen: booleanCodec.decode(transactionDto.afrz), } break - case TransactionType.AppCall: - tx.appCall = { - appId: bigIntCodec.decode(transactionDto.apid), - onComplete: fromOnApplicationCompleteDto(transactionDto.apan), - approvalProgram: bytesCodec.decodeOptional(transactionDto.apap), - clearStateProgram: bytesCodec.decodeOptional(transactionDto.apsu), - args: transactionDto.apaa?.map((arg) => bytesCodec.decode(arg)), - accountReferences: transactionDto.apat?.map((addr) => addressCodec.decode(addr)), - appReferences: transactionDto.apfa?.map((id) => bigIntCodec.decode(id)), - assetReferences: transactionDto.apas?.map((id) => bigIntCodec.decode(id)), - boxReferences: transactionDto.apbx?.map((box) => { - const index = typeof box.i === 'bigint' ? Number(box.i) : (box.i ?? 0) - let appId: bigint - if (index === 0) { - // 0 means current app - appId = 0n - } else { - // 1-based index into foreignApps array - const foreignAppId = transactionDto.apfa?.[index - 1] - if (foreignAppId === undefined) { - throw new Error(`Failed to find the app reference at index ${index - 1}`) + } + case TransactionType.AppCall: { + const approvalProgram = bytesCodec.decodeOptional(transactionDto.apap) + const clearStateProgram = bytesCodec.decodeOptional(transactionDto.apsu) + const args = transactionDto.apaa?.map((arg) => bytesCodec.decode(arg)) + const accountReferences = transactionDto.apat?.map((addr) => addressCodec.decode(addr)) + const appReferences = transactionDto.apfa?.map((id) => bigIntCodec.decode(id)) + const assetReferences = transactionDto.apas?.map((id) => bigIntCodec.decode(id)) + const extraProgramPages = numberCodec.decodeOptional(transactionDto.apep) + const boxReferences = transactionDto.apbx?.map((box) => { + const index = typeof box.i === 'bigint' ? Number(box.i) : (box.i ?? 0) + let appId: bigint + if (index === 0) { + // 0 means current app + appId = 0n + } else { + // 1-based index into foreignApps array + const foreignAppId = transactionDto.apfa?.[index - 1] + if (foreignAppId === undefined) { + throw new Error(`Failed to find the app reference at index ${index - 1}`) + } + appId = bigIntCodec.decode(foreignAppId) + } + return { + appId: appId, + name: bytesCodec.decode(box.n), + } + }) + const accessReferences: AccessReference[] = [] + if (transactionDto.al) { + for (const ref of transactionDto.al) { + if (ref.d) { + accessReferences.push({ address: addressCodec.decode(ref.d) }) + continue + } + if (ref.s !== undefined) { + accessReferences.push({ assetId: bigIntCodec.decode(ref.s) }) + continue + } + if (ref.p !== undefined) { + accessReferences.push({ appId: bigIntCodec.decode(ref.p) }) + continue + } + if (ref.h) { + const addrIdx = ref.h.d ?? 0 + const assetIdx = ref.h.s + + if (assetIdx === undefined) { + throw new Error(`Holding missing asset index: ${JSON.stringify(ref.h)}`) } - appId = bigIntCodec.decode(foreignAppId) + + const holdingAddress = addrIdx === 0 ? ZERO_ADDRESS : transactionDto.al[addrIdx - 1].d! + const holdingAssetId = transactionDto.al[assetIdx - 1].s! + + accessReferences.push({ + holding: { + address: typeof holdingAddress === 'string' ? holdingAddress : addressCodec.decode(holdingAddress), + assetId: bigIntCodec.decode(holdingAssetId), + }, + }) + continue } - return { - appId: appId, - name: bytesCodec.decode(box.n), + + if (ref.l) { + const addrIdx = ref.l.d ?? 0 + const appIdx = ref.l.p ?? 0 + + const localsAddress = addrIdx === 0 ? ZERO_ADDRESS : transactionDto.al[addrIdx - 1].d! + const localsAppId = appIdx === 0 ? BigInt(0) : transactionDto.al[appIdx - 1].p! + + accessReferences.push({ + locals: { + address: typeof localsAddress === 'string' ? localsAddress : addressCodec.decode(localsAddress), + appId: bigIntCodec.decode(localsAppId), + }, + }) + continue } - }), - accessReferences: transactionDto.al - ? (() => { - const accessList = transactionDto.al! - const result: AccessReference[] = [] - - for (const ref of accessList) { - if (ref.d) { - result.push({ address: addressCodec.decode(ref.d) }) - continue - } - if (ref.s !== undefined) { - result.push({ assetId: bigIntCodec.decode(ref.s) }) - continue - } - if (ref.p !== undefined) { - result.push({ appId: bigIntCodec.decode(ref.p) }) - continue - } - if (ref.h) { - const addrIdx = ref.h.d ?? 0 - const assetIdx = ref.h.s - - if (assetIdx === undefined) { - throw new Error(`Holding missing asset index: ${JSON.stringify(ref.h)}`) - } - - const holdingAddress = addrIdx === 0 ? ZERO_ADDRESS : accessList[addrIdx - 1].d! - const holdingAssetId = accessList[assetIdx - 1].s! - - result.push({ - holding: { - address: typeof holdingAddress === 'string' ? holdingAddress : addressCodec.decode(holdingAddress), - assetId: bigIntCodec.decode(holdingAssetId), - }, - }) - continue - } + if (ref.b) { + const boxAppIdx = ref.b.i ?? 0 + const name = ref.b.n - if (ref.l) { - const addrIdx = ref.l.d ?? 0 - const appIdx = ref.l.p ?? 0 + if (!name) { + throw new Error(`Box missing name: ${JSON.stringify(ref.b)}`) + } - const localsAddress = addrIdx === 0 ? ZERO_ADDRESS : accessList[addrIdx - 1].d! - const localsAppId = appIdx === 0 ? BigInt(0) : accessList[appIdx - 1].p! + const boxAppId = boxAppIdx === 0 ? BigInt(0) : transactionDto.al[boxAppIdx - 1].p! - result.push({ - locals: { - address: typeof localsAddress === 'string' ? localsAddress : addressCodec.decode(localsAddress), - appId: bigIntCodec.decode(localsAppId), - }, - }) - continue - } - if (ref.b) { - const boxAppIdx = ref.b.i ?? 0 - const name = ref.b.n - - if (!name) { - throw new Error(`Box missing name: ${JSON.stringify(ref.b)}`) - } - - const boxAppId = boxAppIdx === 0 ? BigInt(0) : accessList[boxAppIdx - 1].p! - - result.push({ - box: { - appId: bigIntCodec.decode(boxAppId), - name: bytesCodec.decode(name), - }, - }) - } - } + accessReferences.push({ + box: { + appId: bigIntCodec.decode(boxAppId), + name: bytesCodec.decode(name), + }, + }) + } + } + } - return result - })() - : undefined, - extraProgramPages: numberCodec.decodeOptional(transactionDto.apep), + tx.appCall = { + appId: bigIntCodec.decode(transactionDto.apid), + onComplete: fromOnApplicationCompleteDto(transactionDto.apan), + ...(approvalProgram && { approvalProgram }), + ...(clearStateProgram && { clearStateProgram }), + ...(args && { args }), + ...(accountReferences && { accountReferences }), + ...(appReferences && { appReferences }), + ...(assetReferences && { assetReferences }), + ...(extraProgramPages !== undefined && { extraProgramPages }), + ...(boxReferences && boxReferences.length > 0 && { boxReferences }), + ...(accessReferences && accessReferences.length > 0 && { accessReferences }), ...(transactionDto.apgs !== undefined ? { globalStateSchema: stateSchemaCodec.decodeOptional({ @@ -1013,35 +1052,46 @@ export function fromTransactionDto(transactionDto: TransactionDto): Transaction : undefined), } break - case TransactionType.KeyRegistration: + } + case TransactionType.KeyRegistration: { + const voteKey = fixedBytes32Codec.decodeOptional(transactionDto.votekey) + const selectionKey = fixedBytes32Codec.decodeOptional(transactionDto.selkey) + const voteFirst = bigIntCodec.decodeOptional(transactionDto.votefst) + const voteLast = bigIntCodec.decodeOptional(transactionDto.votelst) + const voteKeyDilution = bigIntCodec.decodeOptional(transactionDto.votekd) + const stateProofKey = fixedBytes64Codec.decodeOptional(transactionDto.sprfkey) + const nonParticipation = booleanCodec.decodeOptional(transactionDto.nonpart) + tx.keyRegistration = { - voteKey: bytesCodec.decodeOptional(transactionDto.votekey), - selectionKey: bytesCodec.decodeOptional(transactionDto.selkey), - voteFirst: bigIntCodec.decodeOptional(transactionDto.votefst), - voteLast: bigIntCodec.decodeOptional(transactionDto.votelst), - voteKeyDilution: bigIntCodec.decodeOptional(transactionDto.votekd), - stateProofKey: bytesCodec.decodeOptional(transactionDto.sprfkey), - nonParticipation: booleanCodec.decodeOptional(transactionDto.nonpart), + ...(voteKey && { voteKey }), + ...(selectionKey && { selectionKey }), + ...(voteFirst !== undefined && { voteFirst }), + ...(voteLast !== undefined && { voteLast }), + ...(voteKeyDilution !== undefined && { voteKeyDilution }), + ...(stateProofKey && { stateProofKey }), + ...(nonParticipation !== undefined && { nonParticipation }), } break - case TransactionType.Heartbeat: + } + case TransactionType.Heartbeat: { if (transactionDto.hb) { tx.heartbeat = { address: addressCodec.decode(transactionDto.hb.a), proof: { - sig: bytesCodec.decode(transactionDto.hb.prf?.s), - pk: bytesCodec.decode(transactionDto.hb.prf?.p), - pk2: bytesCodec.decode(transactionDto.hb.prf?.p2), - pk1Sig: bytesCodec.decode(transactionDto.hb.prf?.p1s), - pk2Sig: bytesCodec.decode(transactionDto.hb.prf?.p2s), + sig: fixedBytes64Codec.decode(transactionDto.hb.prf?.s), + pk: fixedBytes32Codec.decode(transactionDto.hb.prf?.p), + pk2: fixedBytes32Codec.decode(transactionDto.hb.prf?.p2), + pk1Sig: fixedBytes64Codec.decode(transactionDto.hb.prf?.p1s), + pk2Sig: fixedBytes64Codec.decode(transactionDto.hb.prf?.p2s), }, seed: bytesCodec.decode(transactionDto.hb.sd), - voteId: bytesCodec.decode(transactionDto.hb.vid), + voteId: fixedBytes32Codec.decode(transactionDto.hb.vid), keyDilution: bigIntCodec.decode(transactionDto.hb.kd), } } break - case TransactionType.StateProof: + } + case TransactionType.StateProof: { tx.stateProof = { stateProofType: transactionDto.sptype ?? 0, stateProof: transactionDto.sp @@ -1061,14 +1111,14 @@ export function fromTransactionDto(transactionDto: TransactionDto): Transaction vectorCommitmentIndex: bigIntCodec.decode(reveal.s?.s?.idx), proof: fromMerkleArrayProofDto(reveal.s?.s?.prf), verifyingKey: { - publicKey: bytesCodec.decode(reveal.s?.s?.vkey?.k), + publicKey: fixedBytes1793Codec.decode(reveal.s?.s?.vkey?.k), }, }, lowerSigWeight: bigIntCodec.decode(reveal.s?.l), }, participant: { verifier: { - commitment: bytesCodec.decode(reveal.p?.p?.cmt), + commitment: fixedBytes64Codec.decode(reveal.p?.p?.cmt), keyLifetime: bigIntCodec.decode(reveal.p?.p?.lf), }, weight: bigIntCodec.decode(reveal.p?.w), @@ -1089,6 +1139,7 @@ export function fromTransactionDto(transactionDto: TransactionDto): Transaction : undefined, } break + } } return tx diff --git a/src/transaction/transaction.ts b/src/transaction/transaction.ts index c824c628..0f8b972a 100644 --- a/src/transaction/transaction.ts +++ b/src/transaction/transaction.ts @@ -947,7 +947,7 @@ export const sendAtomicTransactionComposer = async function (atcSend: AtomicTran if (simulate && simulate.txnGroups[0].failedAt) { for (const txn of simulate.txnGroups[0].txnResults) { err.traces.push({ - trace: AlgorandSerializer.encode(txn.execTrace, SimulationTransactionExecTraceMeta, 'map'), + trace: txn.execTrace ? AlgorandSerializer.encode(txn.execTrace, SimulationTransactionExecTraceMeta, 'map') : undefined, appBudget: txn.appBudgetConsumed, logicSigBudget: txn.logicSigBudgetConsumed, logs: txn.txnResult.logs, diff --git a/src/types/asset-manager.ts b/src/types/asset-manager.ts index 5146fc32..070e8e02 100644 --- a/src/types/asset-manager.ts +++ b/src/types/asset-manager.ts @@ -169,7 +169,7 @@ export class AssetManager { const asset = await this._algod.getAssetById(assetId) return { - assetId: BigInt(asset.index), + assetId: BigInt(asset.id), total: BigInt(asset.params.total), decimals: Number(asset.params.decimals), assetName: asset.params.name, diff --git a/tsconfig.base.json b/tsconfig.base.json index e90dc13b..6048b823 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -12,6 +12,7 @@ "resolveJsonModule": true, "skipLibCheck": true, "declarationMap": true, + "strict": true, "baseUrl": ".", "paths": { "@algorandfoundation/algokit-abi": ["packages/abi/src"],