From ea7f4f8a0ae30bce3c7f271d4a3e46ebd1c05e9a Mon Sep 17 00:00:00 2001 From: Michael Feher Date: Mon, 9 Sep 2024 15:00:34 -0400 Subject: [PATCH 1/2] fix: payment schema --- lib/algorand.transaction.pay.ts | 2 +- lib/schemas/pay.transaction.json | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/algorand.transaction.pay.ts b/lib/algorand.transaction.pay.ts index 28a8861..a0e8885 100644 --- a/lib/algorand.transaction.pay.ts +++ b/lib/algorand.transaction.pay.ts @@ -9,7 +9,7 @@ export class PayTransaction { fv: number lv: number note?: Uint8Array - gen: string + gen?: string gh: Uint8Array // encode the transaction diff --git a/lib/schemas/pay.transaction.json b/lib/schemas/pay.transaction.json index 55dcce5..6a762ea 100644 --- a/lib/schemas/pay.transaction.json +++ b/lib/schemas/pay.transaction.json @@ -7,8 +7,11 @@ "gen": { "type": "string" }, + "close": { + "$ref": "http://algo-models.com/schemas/bytes32.json" + }, "gh": { - "$ref": "bytes32.json" + "$ref": "http://algo-models.com/schemas/bytes32.json" }, "type": { "type": "string", @@ -21,10 +24,10 @@ "type": "integer" }, "snd": { - "$ref": "bytes32.json" + "$ref": "http://algo-models.com/schemas/bytes32.json" }, "rcv": { - "$ref": "bytes32.json" + "$ref": "http://algo-models.com/schemas/bytes32.json" }, "fv": { "type": "integer", @@ -36,7 +39,6 @@ } }, "required": [ - "gen", "gh", "type", "fee", From b4316859d0ae342034d1aee0689b8e68940570b8 Mon Sep 17 00:00:00 2001 From: Michael Feher Date: Mon, 9 Sep 2024 16:43:41 -0400 Subject: [PATCH 2/2] feat: basic transaction models and schemas --- lib/algorand.asset.params.ts | 150 +++++ lib/algorand.encoder.spec.ts | 91 +++ lib/algorand.encoder.ts | 9 + lib/algorand.transaction.acfg.ts | 126 ++++ lib/algorand.transaction.afrz.ts | 127 ++++ lib/algorand.transaction.axfer.ts | 163 +++++ lib/algorand.transaction.crafter.spec.ts | 288 ++++++--- lib/algorand.transaction.crafter.ts | 107 +++- lib/algorand.transaction.keyreg.ts | 195 ++++-- lib/algorand.transaction.pay.ts | 121 ++-- lib/algorand.transaction.ts | 170 +++++ lib/index.ts | 16 +- lib/schemas/acfg.transaction.json | 24 + lib/schemas/afrz.transaction.json | 29 + lib/schemas/asset.params.json | 52 ++ lib/schemas/axfer.transaction.json | 37 ++ lib/schemas/bytes32.json | 202 ++++++ lib/schemas/bytes64.json | 328 ++++++++++ .../keyreg.transaction.nonparticipation.json | 250 +------- lib/schemas/keyreg.transaction.offline.json | 589 +---------------- lib/schemas/keyreg.transaction.online.json | 605 +----------------- lib/schemas/pay.transaction.json | 254 +------- lib/schemas/transaction.header.json | 56 ++ package-lock.json | 192 +++++- package.json | 5 +- typedoc.json | 8 + 26 files changed, 2376 insertions(+), 1818 deletions(-) create mode 100644 lib/algorand.asset.params.ts create mode 100644 lib/algorand.transaction.acfg.ts create mode 100644 lib/algorand.transaction.afrz.ts create mode 100644 lib/algorand.transaction.axfer.ts create mode 100644 lib/algorand.transaction.ts create mode 100644 lib/schemas/acfg.transaction.json create mode 100644 lib/schemas/afrz.transaction.json create mode 100644 lib/schemas/asset.params.json create mode 100644 lib/schemas/axfer.transaction.json create mode 100644 lib/schemas/bytes32.json create mode 100644 lib/schemas/bytes64.json create mode 100644 lib/schemas/transaction.header.json create mode 100644 typedoc.json diff --git a/lib/algorand.asset.params.ts b/lib/algorand.asset.params.ts new file mode 100644 index 0000000..184d1ff --- /dev/null +++ b/lib/algorand.asset.params.ts @@ -0,0 +1,150 @@ +import {AlgorandEncoder} from "./algorand.encoder.js"; + +/** + * @category Common + */ +export class AssetParams { + /** + * Total + * + * The total number of base units of the asset to create. This number cannot be changed. + */ + t?: number | bigint | undefined + /** + * Decimals + * + * The number of digits to use after the decimal point when displaying the asset. If 0, the asset is not divisible. If 1, the base unit of the asset is in tenths. + * If 2, the base unit of the asset is in hundredths, if 3, the base unit of the asset is in thousandths, and so on up to 19 decimal places + */ + dc?: number | bigint + /** + * Default Frozen + * + * True to freeze holdings for this asset by default. + */ + df?: boolean + /** + * Unit Name + * + * The name of a unit of this asset. Supplied on creation. Max size is 8 bytes. Example: USDT + */ + un?: string + /** + * Asset Name + * + * The name of the asset. Supplied on creation. Max size is 32 bytes. Example: Tether + */ + an?: string + /** + * URL + * + * Specifies a URL where more information about the asset can be retrieved. Max size is 96 bytes. + */ + au?: string + /** + * MetaDataHash + * + * This field is intended to be a 32-byte hash of some metadata that is relevant to your asset and/or asset holders. The format of this metadata is up to the application. This field can only be specified upon creation. + * An example might be the hash of some certificate that acknowledges the digitized asset as the official representation of a particular real-world asset. + */ + am?: Uint8Array + /** + * Manager Address + * + * The address of the account that can manage the configuration of the asset and destroy it. + */ + m?: Uint8Array + /** + * Reserve Address + * + * The address of the account that holds the reserve (non-minted) units of the asset. This address has no specific authority in the protocol itself. + * It is used in the case where you want to signal to holders of your asset that the non-minted units of the asset reside in an account that is different from the default creator account (the sender). + */ + r?: Uint8Array + /** + * Freeze Address + * The address of the account used to freeze holdings of this asset. If empty, freezing is not permitted. + */ + f?: Uint8Array + /** + * Clawback Address + * + * The address of the account that can clawback holdings of this asset. If empty, clawback is not permitted. + */ + c?: Uint8Array +} + +/** + * @category Builders + * @internal + */ +export interface IAssetParamsBuilder { + addTotal(total: number): IAssetParamsBuilder + addDecimals(decimals: number): IAssetParamsBuilder + addDefaultFrozen(frozen: boolean): IAssetParamsBuilder + addUnitName(unitName: string): IAssetParamsBuilder + addAssetName(assetName: string): IAssetParamsBuilder + addMetadataHash(hash: Uint8Array): IAssetParamsBuilder + addManagerAddress(address: string): IAssetParamsBuilder + addReserveAddress(address: string): IAssetParamsBuilder + addFreezeAddress(address: string): IAssetParamsBuilder + addClawbackAddress(address: string): IAssetParamsBuilder + get(): AssetParams +} + +/** + * @category Builders + * + */ +export class AssetParamsBuilder implements IAssetParamsBuilder { + private params: AssetParams + private readonly encoder: AlgorandEncoder + constructor() { + this.params = new AssetParams() + this.encoder = new AlgorandEncoder() + } + + addTotal(total: number): IAssetParamsBuilder { + this.params.t = total + return this + } + addDecimals(decimals: number): IAssetParamsBuilder { + this.params.dc = decimals + return this + } + addDefaultFrozen(frozen: boolean): IAssetParamsBuilder { + this.params.df = frozen + return this + } + addUnitName(unitName: string): IAssetParamsBuilder { + this.params.un = unitName + return this + } + addAssetName(assetName: string): IAssetParamsBuilder { + this.params.an = assetName + return this + } + addMetadataHash(hash: Uint8Array): IAssetParamsBuilder { + this.params.am = hash + return this + } + addManagerAddress(address: string): IAssetParamsBuilder { + this.params.m = this.encoder.decodeAddress(address) + return this + } + addReserveAddress(address: string): IAssetParamsBuilder { + this.params.r = this.encoder.decodeAddress(address) + return this + } + addFreezeAddress(address: string): IAssetParamsBuilder { + this.params.f = this.encoder.decodeAddress(address) + return this + } + addClawbackAddress(address: string): IAssetParamsBuilder { + this.params.c = this.encoder.decodeAddress(address) + return this + } + get() { + return this.params + } +} \ No newline at end of file diff --git a/lib/algorand.encoder.spec.ts b/lib/algorand.encoder.spec.ts index fe96ad3..de6d39a 100644 --- a/lib/algorand.encoder.spec.ts +++ b/lib/algorand.encoder.spec.ts @@ -6,6 +6,10 @@ import * as msgpack from "algo-msgpack-with-bigint" import { PayTransaction } from "./algorand.transaction.pay" import { KeyregTransaction } from "./algorand.transaction.keyreg" import { AlgorandTransactionCrafter } from "./algorand.transaction.crafter" +import {AssetParamsBuilder} from "./algorand.asset.params"; +import {AssetConfigTransaction} from "./algorand.transaction.acfg"; +import {AssetFreezeTransaction} from "./algorand.transaction.afrz"; +import {AssetTransferTransaction} from "./algorand.transaction.axfer"; export function concatArrays(...arrs: ArrayLike[]) { const size = arrs.reduce((sum, arr) => sum + arr.length, 0) @@ -135,7 +139,94 @@ describe("Algorand Encoding", () => { const encoded: Uint8Array = txn.encode() expect(encoded).toEqual(algoEncoder.encodeTransaction(txn)) }) + it("(OK) Encoding of asset config transaction", async () => { + // from algorand address + const from: string = algoEncoder.encodeAddress(Buffer.from(randomBytes(32))) + + // note + const note: string = Buffer.from(randomBytes(32)).toString("base64") + const grp = randomBytes(32) + const lx = randomBytes(32) + const params = new AssetParamsBuilder() + .addTotal(1) + .addDecimals(1) + .addDefaultFrozen(false) + .addAssetName("Big Yeetus") + .addUnitName("YEET") + .addMetadataHash(randomBytes(32)) + .addClawbackAddress(from) + .addFreezeAddress(from) + .addManagerAddress(from) + .addReserveAddress(from) + .get() + + // create keyreg transaction + const txn: AssetConfigTransaction = algorandCrafter + .createAsset(from, params) + .addFirstValidRound(1000) + .addLastValidRound(2000) + .addNote(note, "base64") + .addFee(1000) + .addGroup(grp) + .addRekey(from) + .addLease(lx) + .get() + + const encoded: Uint8Array = txn.encode() + expect(encoded).toEqual(algoEncoder.encodeTransaction(txn)) + }) + it("(OK) Encoding of asset freeze transaction", async () => { + // from algorand address + const from: string = algoEncoder.encodeAddress(Buffer.from(randomBytes(32))) + + // note + const note: string = Buffer.from(randomBytes(32)).toString("base64") + const grp = randomBytes(32) + const lx = randomBytes(32) + + // create keyreg transaction + const txn: AssetFreezeTransaction = algorandCrafter + .freezeAsset(from, 1, true) + .addSender(from) + .addFirstValidRound(1000) + .addLastValidRound(2000) + .addNote(note, "base64") + .addFee(1000) + .addGroup(grp) + .addRekey(from) + .addLease(lx) + .get() + + const encoded: Uint8Array = txn.encode() + expect(encoded).toEqual(algoEncoder.encodeTransaction(txn)) + }) + it("(OK) Encoding of asset transfer transaction", async () => { + // from algorand address + const from: string = algoEncoder.encodeAddress(Buffer.from(randomBytes(32))) + const to: string = algoEncoder.encodeAddress(Buffer.from(randomBytes(32))) + // note + const note: string = Buffer.from(randomBytes(32)).toString("base64") + const grp = randomBytes(32) + const lx = randomBytes(32) + + // create keyreg transaction + const txn: AssetTransferTransaction = algorandCrafter + .transferAsset(from, 1, to, 1) + .addAssetCloseTo(from) + .addAssetSender(from) + .addFirstValidRound(1000) + .addLastValidRound(2000) + .addNote(note, "base64") + .addFee(1000) + .addGroup(grp) + .addRekey(from) + .addLease(lx) + .get() + + const encoded: Uint8Array = txn.encode() + expect(encoded).toEqual(algoEncoder.encodeTransaction(txn)) + }) it("(OK) Encode & Decode Address ", async () => { const keyPair: SignKeyPair = { publicKey: Uint8Array.from([ diff --git a/lib/algorand.encoder.ts b/lib/algorand.encoder.ts index fc32756..7d51d17 100644 --- a/lib/algorand.encoder.ts +++ b/lib/algorand.encoder.ts @@ -10,9 +10,18 @@ const ALGORAND_ADDRESS_BYTE_LENGTH = 36 const ALGORAND_CHECKSUM_BYTE_LENGTH = 4 const ALGORAND_ADDRESS_LENGTH = 58 const HASH_BYTES_LENGTH = 32 +/** + * @internal + */ export const MALFORMED_ADDRESS_ERROR_MSG = "Malformed address" +/** + * @internal + */ export const ALGORAND_ADDRESS_BAD_CHECKSUM_ERROR_MSG = "Bad checksum" +/** + * @category Encoding + */ export class AlgorandEncoder extends Encoder{ /** * decodeAddress takes an Algorand address in string form and decodes it into a Uint8Array. diff --git a/lib/algorand.transaction.acfg.ts b/lib/algorand.transaction.acfg.ts new file mode 100644 index 0000000..95a33b0 --- /dev/null +++ b/lib/algorand.transaction.acfg.ts @@ -0,0 +1,126 @@ +import {AlgorandEncoder} from "./algorand.encoder.js" +import {AssetParams} from "./algorand.asset.params.js"; +import {ITransactionHeaderBuilder, TransactionHeader} from "./algorand.transaction.js"; + +/** + * This is used to create, configure and destroy an asset depending on which fields are set. + * + * @category Transactions + * @see {@link AlgorandTransactionCrafter} + * @see {@link AssetConfigTxBuilder} + * @example // Manual + * const txn = new AssetConfigTransaction() + */ +export class AssetConfigTransaction extends TransactionHeader { + declare type: "acfg" + /** + * For re-configure or destroy transactions, this is the unique asset ID. On asset creation, the ID is set to zero. + * @type {number | bigint} + */ + caid?: number | bigint + /** + * See {@link AssetParams} for all available fields. + * @type {AssetParams} + */ + apar?: AssetParams + /** + * Encode the {@link AssetConfigTransaction} + */ + encode(): Uint8Array { + return new AlgorandEncoder().encodeTransaction(this) + } +} +/** + * Builder Interface for Asset Config Transaction + * @category Builders + * @see {@link AlgorandTransactionCrafter} + * @see {@link AssetConfigTxBuilder} + * @internal + */ +export interface IAssetConfigTxBuilder extends ITransactionHeaderBuilder{ + /** + * Add Asset ID + * + * @remarks required, except on create + * @param caid For re-configure or destroy transactions, this is the unique asset ID. On asset creation, the ID is set to zero. + */ + addAssetId(caid: number | bigint): IAssetConfigTxBuilder + /** + * Add Asset Parameters + * + * @remarks required, except on destroy + * @param params + */ + addAssetParams(params: AssetParams): IAssetConfigTxBuilder + /** + * Validate the model and return the instance + */ + get(): AssetConfigTransaction +} +/** + * This is used to create, configure and destroy an asset depending on which fields are set. + * + * @category Builders + * @see {@link AlgorandTransactionCrafter} + * @example // Builder + * const tx = new AssetConfigTxBuilder("GENESIS_ID", "GENESIS_HASH") + * .addAssetId(1234) + * .get() + */ +export class AssetConfigTxBuilder implements IAssetConfigTxBuilder { + private readonly tx: AssetConfigTransaction + private readonly encoder: AlgorandEncoder + + constructor(genesisId: string, genesisHash: string) { + this.encoder = new AlgorandEncoder() + + this.tx = new AssetConfigTransaction() + this.tx.gen = genesisId + this.tx.gh = new Uint8Array(Buffer.from(genesisHash, "base64")) + this.tx.type = "acfg" + this.tx.fee = 1000 + } + addAssetId(caid: number | bigint): IAssetConfigTxBuilder { + this.tx.caid = caid + return this + } + addAssetParams(params: AssetParams): IAssetConfigTxBuilder{ + this.tx.apar = params + return this + } + addSender(sender: string): IAssetConfigTxBuilder { + this.tx.snd = this.encoder.decodeAddress(sender) + return this + } + addFee(fee: number): IAssetConfigTxBuilder { + this.tx.fee = fee + return this + } + addFirstValidRound(fv: number): IAssetConfigTxBuilder { + this.tx.fv = fv + return this + } + addLastValidRound(lv: number): IAssetConfigTxBuilder { + this.tx.lv = lv + return this + } + addNote(note: string, encoding: BufferEncoding = "utf8"): IAssetConfigTxBuilder { + this.tx.note = new Uint8Array(Buffer.from(note, encoding)) + return this + } + addRekey(rekey: string): IAssetConfigTxBuilder { + this.tx.rekey = this.encoder.decodeAddress(rekey) + return this + } + addLease(lx: Uint8Array): IAssetConfigTxBuilder { + this.tx.lx = lx + return this + } + addGroup(grp: Uint8Array): IAssetConfigTxBuilder { + this.tx.grp = grp + return this + } + get(): AssetConfigTransaction { + return this.tx + } +} diff --git a/lib/algorand.transaction.afrz.ts b/lib/algorand.transaction.afrz.ts new file mode 100644 index 0000000..80dc5b6 --- /dev/null +++ b/lib/algorand.transaction.afrz.ts @@ -0,0 +1,127 @@ +import {AlgorandEncoder} from "./algorand.encoder.js" +import {ITransactionHeaderBuilder, TransactionHeader} from "./algorand.transaction.js"; + +/** + * Includes all fields in {@link TransactionHeader} and "type" is "axfer". + * + * @category Transactions + * @see {@link AlgorandTransactionCrafter} + * @see {@link AssetFreezeTxBuilder} + * @example // Manual + * const txn = new AssetFreezeTransaction() + */ +export class AssetFreezeTransaction extends TransactionHeader { + declare type: "afrz" + /** + * The address of the account whose asset is being frozen or unfrozen. + */ + fadd: Uint8Array + /** + * The asset ID being frozen or unfrozen. + */ + faid: number | bigint + /** + * True to freeze the asset. + */ + afrz: boolean + /** + * Encode the {@link AssetFreezeTransaction} + */ + encode(): Uint8Array { + return new AlgorandEncoder().encodeTransaction(this) + } +} +/** + * Builder Interface for Asset Freeze Transaction + * @category Builders + * @internal + */ +export interface IAssetFreezeTxBuilder extends ITransactionHeaderBuilder{ + /** + * Add Freeze Account + * + * @param fadd The address of the account whose asset is being frozen or unfrozen. + */ + addFreezeAccount(fadd: string): IAssetFreezeTxBuilder + /** + * Add Freeze Asset ID + * + * @param faid The asset ID being frozen or unfrozen. + */ + addFreezeAsset(faid: number): IAssetFreezeTxBuilder + /** + * Add Asset Frozen + * + * @param afrz True to freeze the asset. + */ + addAssetFrozen(afrz: boolean): IAssetFreezeTxBuilder + /** + * Validate the model and return the instance + */ + get(): AssetFreezeTransaction +} + +/** + * @category Builders + */ +export class AssetFreezeTxBuilder implements IAssetFreezeTxBuilder { + private readonly tx: AssetFreezeTransaction + private readonly encoder: AlgorandEncoder + + constructor(genesisId: string, genesisHash: string) { + this.encoder = new AlgorandEncoder() + + this.tx = new AssetFreezeTransaction() + this.tx.gen = genesisId + this.tx.gh = new Uint8Array(Buffer.from(genesisHash, "base64")) + this.tx.type = "afrz" + this.tx.fee = 1000 + } + addFreezeAccount(fadd: string): IAssetFreezeTxBuilder { + this.tx.fadd = this.encoder.decodeAddress(fadd) + return this + } + addFreezeAsset(faid: number): IAssetFreezeTxBuilder { + this.tx.faid = faid + return this + } + addAssetFrozen(afrz: boolean): IAssetFreezeTxBuilder { + this.tx.afrz = afrz + return this + } + addSender(sender: string): IAssetFreezeTxBuilder { + this.tx.snd = this.encoder.decodeAddress(sender) + return this + } + addFee(fee: number): IAssetFreezeTxBuilder { + this.tx.fee = fee + return this + } + addFirstValidRound(firstValid: number): IAssetFreezeTxBuilder { + this.tx.fv = firstValid + return this + } + addLastValidRound(lastValid: number): IAssetFreezeTxBuilder { + this.tx.lv = lastValid + return this + } + addNote(note: string, encoding: BufferEncoding = "utf8"): IAssetFreezeTxBuilder { + this.tx.note = new Uint8Array(Buffer.from(note, encoding)) + return this + } + addRekey(address: string): IAssetFreezeTxBuilder { + this.tx.rekey = this.encoder.decodeAddress(address) + return this + } + addLease(lease: Uint8Array): IAssetFreezeTxBuilder { + this.tx.lx = lease + return this + } + addGroup(group: Uint8Array): IAssetFreezeTxBuilder { + this.tx.grp = group + return this + } + get(): AssetFreezeTransaction { + return this.tx + } +} diff --git a/lib/algorand.transaction.axfer.ts b/lib/algorand.transaction.axfer.ts new file mode 100644 index 0000000..6b58276 --- /dev/null +++ b/lib/algorand.transaction.axfer.ts @@ -0,0 +1,163 @@ +import {AlgorandEncoder} from "./algorand.encoder.js" +import {TransactionHeader, type ITransactionHeaderBuilder} from "./algorand.transaction.js"; + +/** + * Asset Transfer Transaction + * + * @category Transactions + * @see {@link AlgorandTransactionCrafter} + * @see {@link AssetFreezeTxBuilder} + */ +export class AssetTransferTransaction extends TransactionHeader { + /** + * Transfer Asset + * + * The unique ID of the asset to be transferred. + */ + xaid: number | bigint + /** + * Asset Amount + * + * The amount of the asset to be transferred. + * A zero amount transferred to self allocates that asset in the account's Asset map. + */ + aamt: number | bigint + /** + * Asset Sender + * + * The sender of the transfer. The regular sender field should be used and this one set to the zero + * value for regular transfers between accounts. If this value is nonzero, it indicates a clawback + * transaction where the sender is the asset's clawback address and the asset sender is the address + * from which the funds will be withdrawn. + */ + asnd?: Uint8Array + /** + * Asset Receiver + * + * The recipient of the asset transfer. + */ + arcv: Uint8Array + /** + * Specify this field to remove the asset holding from the sender account and reduce the account's + * minimum balance (i.e. opt-out of the asset). + */ + aclose?: Uint8Array + + encode(): Uint8Array { + return new AlgorandEncoder().encodeTransaction(this) + } +} +/** + * Builder Interface for Asset Transfer Transaction + * @category Builders + * @internal + */ +export interface IAssetTransferTxBuilder extends ITransactionHeaderBuilder{ + /** + * Add Asset ID + * + * @param xaid The unique ID of the asset to be transferred. + */ + addAssetId(xaid: number): IAssetTransferTxBuilder + /** + * Add Asset Amount + * + * @param aamt The amount of the asset to be transferred. + */ + addAssetAmount(aamt: number | bigint): IAssetTransferTxBuilder + /** + * Add Asset Receiver + * + * @param arcv The recipient of the asset transfer. + */ + addAssetReceiver(arcv: string): IAssetTransferTxBuilder + /** + * Add Asset Close To + * + * @param aclose Specify this field to remove the asset holding from the sender account. + */ + addAssetCloseTo(aclose: string): IAssetTransferTxBuilder + /** + * Add Asset Sender + * + * @param asnd This should usually be undefined. It indicates a clawback transaction where the sender is the + * asset's clawback address and the asset sender is the address from which the funds will be withdrawn. + */ + addAssetSender(asnd: string): IAssetTransferTxBuilder + // Getter + get(): AssetTransferTransaction +} + +/** + * Asset Transfer Transaction Builder + * @category Builders + */ +export class AssetTransferTxBuilder implements IAssetTransferTxBuilder { + private readonly tx: AssetTransferTransaction + private readonly encoder: AlgorandEncoder + + constructor(genesisId: string, genesisHash: string) { + this.encoder = new AlgorandEncoder() + + this.tx = new AssetTransferTransaction() + this.tx.gen = genesisId + this.tx.gh = new Uint8Array(Buffer.from(genesisHash, "base64")) + this.tx.type = "axfer" + this.tx.fee = 1000 + } + addAssetId(xaid: number | bigint): IAssetTransferTxBuilder { + this.tx.xaid = xaid + return this + } + addAssetAmount(aamt: number | bigint): IAssetTransferTxBuilder { + this.tx.aamt = aamt + return this + } + addAssetSender(asnd: string): IAssetTransferTxBuilder { + this.tx.asnd = this.encoder.decodeAddress(asnd) + return this + } + addAssetReceiver(arcv: string): IAssetTransferTxBuilder { + this.tx.arcv = this.encoder.decodeAddress(arcv) + return this + } + addAssetCloseTo(aclose: string): IAssetTransferTxBuilder { + this.tx.aclose = this.encoder.decodeAddress(aclose) + return this + } + addSender(sender: string): IAssetTransferTxBuilder { + this.tx.snd = this.encoder.decodeAddress(sender) + return this + } + addFee(fee: number): IAssetTransferTxBuilder { + this.tx.fee = fee + return this + } + addFirstValidRound(firstValid: number): IAssetTransferTxBuilder { + this.tx.fv = firstValid + return this + } + addLastValidRound(lastValid: number): IAssetTransferTxBuilder { + this.tx.lv = lastValid + return this + } + addNote(note: string, encoding: BufferEncoding = "utf8"): IAssetTransferTxBuilder { + this.tx.note = new Uint8Array(Buffer.from(note, encoding)) + return this + } + addRekey(address: string): IAssetTransferTxBuilder { + this.tx.rekey = this.encoder.decodeAddress(address) + return this + } + addLease(lease: Uint8Array): IAssetTransferTxBuilder { + this.tx.lx = lease + return this + } + addGroup(group: Uint8Array): IAssetTransferTxBuilder { + this.tx.grp = group + return this + } + get(): AssetTransferTransaction { + return this.tx + } +} diff --git a/lib/algorand.transaction.crafter.spec.ts b/lib/algorand.transaction.crafter.spec.ts index 844240d..eab6047 100644 --- a/lib/algorand.transaction.crafter.spec.ts +++ b/lib/algorand.transaction.crafter.spec.ts @@ -7,18 +7,33 @@ import { KeyregTransaction } from "./algorand.transaction.keyreg" import Ajv, {type JSONSchemaType} from "ajv" import path from "path" import fs from 'fs' +import {AssetConfigTransaction} from "./algorand.transaction.acfg"; +import {AssetParamsBuilder} from "./algorand.asset.params"; +import {AssetTransferTransaction} from "./algorand.transaction.axfer"; +import {AssetFreezeTransaction} from "./algorand.transaction.afrz"; +import {ITransactionHeaderBuilder, TransactionHeader} from "./algorand.transaction"; -export function concatArrays(...arrs: ArrayLike[]) { - const size = arrs.reduce((sum, arr) => sum + arr.length, 0) - const c = new Uint8Array(size) - let offset = 0 - for (let i = 0; i < arrs.length; i++) { - c.set(arrs[i], offset) - offset += arrs[i].length - } +// Setup Validator +const ajv = new Ajv() +ajv.addSchema(JSON.parse(fs.readFileSync(path.resolve(__dirname, "schemas/bytes32.json"), "utf8"))) +ajv.addSchema(JSON.parse(fs.readFileSync(path.resolve(__dirname, "schemas/bytes64.json"), "utf8"))) +ajv.addSchema(JSON.parse(fs.readFileSync(path.resolve(__dirname, "schemas/transaction.header.json"), "utf8"))) +ajv.addSchema(JSON.parse(fs.readFileSync(path.resolve(__dirname, "schemas/asset.params.json"), "utf8"))) + + +type TestTransactionHeader = { + snd: Uint8Array, + note: Uint8Array, + grp: Uint8Array, + lx: Uint8Array, - return c + gen: string + gh: Uint8Array + fee: number + fv: number + lv: number + rekey: Uint8Array } describe("Algorand Transaction Crafter", () => { @@ -29,9 +44,38 @@ describe("Algorand Transaction Crafter", () => { // genesis in base64 const genesisHash: string = Buffer.from(randomBytes(32)).toString("base64") + let transactionHeader: Omit + function withTestTransactionHeader>( + builder: ITransactionHeaderBuilder + ){ + const {snd, note, grp, lx, fee, fv, lv} = transactionHeader + return builder + .addSender(algoEncoder.encodeAddress(Buffer.from(snd))) + .addFirstValidRound(fv) + .addLastValidRound(lv) + .addNote(Buffer.from(note!!).toString("base64"), "base64") + .addFee(fee) + .addGroup(grp!!) + .addRekey(algoEncoder.encodeAddress(Buffer.from(snd))) + .addLease(lx!!) + } beforeEach(async () => { algorandCrafter = new AlgorandTransactionCrafter(genesisId, genesisHash) algoEncoder = new AlgorandEncoder() + const sender = randomBytes(32) + // Default Header + transactionHeader = { + snd: sender, + note: randomBytes(128), + grp: randomBytes(32), + lx: randomBytes(32), + gen: genesisId, + gh: new Uint8Array(Buffer.from(genesisHash, "base64")), + fee: 1000, + fv: 1000, + lv: 2000, + rekey: sender + } }) afterEach(() => { @@ -64,38 +108,27 @@ describe("Algorand Transaction Crafter", () => { it("(OK) Craft Pay Transaction", async () => { // from algorand address - const from: string = algoEncoder.encodeAddress(Buffer.from(randomBytes(32))) + const from: string = algoEncoder.encodeAddress(Buffer.from(transactionHeader.snd)) // to algorand address const to: string = algoEncoder.encodeAddress(Buffer.from(randomBytes(32))) - // note - const note: string = Buffer.from(randomBytes(128)).toString("base64") - // create pay transaction - const txn: PayTransaction = algorandCrafter - .pay(1000, from, to) - .addFirstValidRound(1000) - .addLastValidRound(2000) - .addNote(note, "base64") - .addFee(1000) - .get() + const txn: PayTransaction = withTestTransactionHeader( + algorandCrafter + .pay(1000, from, to) + .addCloseTo(from) + ).get() expect(txn).toBeDefined() expect(txn).toBeInstanceOf(PayTransaction) expect(txn).toEqual({ rcv: algoEncoder.decodeAddress(to), - snd: algoEncoder.decodeAddress(from), - amt: 1000, - fv: 1000, - lv: 2000, - gen: genesisId, - gh: new Uint8Array(Buffer.from(genesisHash, "base64")), - note: new Uint8Array(Buffer.from(note, "base64")), - fee: 1000, type: "pay", + amt: 1000, + close: algoEncoder.decodeAddress(from), + ...transactionHeader, }) - const ajv = new Ajv() const validate = ajv.compile(paySchema) expect(validate(txn)).toBe(true) }) @@ -106,10 +139,7 @@ describe("Algorand Transaction Crafter", () => { it("(OK) Craft Keyreg change-online transaction", async () => { // from algorand address - const from: string = algoEncoder.encodeAddress(Buffer.from(randomBytes(32))) - - // note - const note: string = Buffer.from(randomBytes(32)).toString("base64") + const from: string = algoEncoder.encodeAddress(Buffer.from(transactionHeader.snd)) // vote key const voteKey: string = Buffer.from(randomBytes(32)).toString("base64") @@ -121,35 +151,26 @@ describe("Algorand Transaction Crafter", () => { const stateProofKey: string = Buffer.from(randomBytes(64)).toString("base64") // create keyreg transaction - const txn: KeyregTransaction = algorandCrafter - .changeOnline(from, voteKey, selectionKey, stateProofKey, 1000, 2000, 32) - .addFirstValidRound(1000) - .addLastValidRound(2000) - .addNote(note, "base64") - .addFee(1000) - .get() + const txn: KeyregTransaction = withTestTransactionHeader( + algorandCrafter + .changeOnline(from, voteKey, selectionKey, stateProofKey, 1000, 2000, 32) + ).get() expect(txn).toBeDefined() expect(txn).toBeInstanceOf(KeyregTransaction) - const ajv = new Ajv() const validate = ajv.compile(keyRegSchema) expect(validate(txn)).toBe(true) expect(txn).toEqual({ - snd: algoEncoder.decodeAddress(from), votekey: new Uint8Array(Buffer.from(voteKey, "base64")), selkey: new Uint8Array(Buffer.from(selectionKey, "base64")), sprfkey: new Uint8Array(Buffer.from(stateProofKey, "base64")), votefst: 1000, votelst: 2000, votekd: 32, - fv: 1000, - lv: 2000, - gh: new Uint8Array(Buffer.from(genesisHash, "base64")), - note: new Uint8Array(Buffer.from(note, "base64")), - fee: 1000, type: "keyreg", + ...transactionHeader, }) }) }) @@ -159,33 +180,20 @@ describe("Algorand Transaction Crafter", () => { it("(OK) Craft Keyreg change-offline transaction", async () => { // from algorand address - const from: string = algoEncoder.encodeAddress(Buffer.from(randomBytes(32))) - - // note - const note: string = Buffer.from(randomBytes(32)).toString("base64") + const from: string = algoEncoder.encodeAddress(Buffer.from(transactionHeader.snd)) // create keyreg transaction - const txn: KeyregTransaction = algorandCrafter + const txn: KeyregTransaction = withTestTransactionHeader(algorandCrafter .changeOffline(from) - .addFirstValidRound(1000) - .addLastValidRound(2000) - .addNote(note, "base64") - .addFee(1000) - .get() + ).get() expect(txn).toBeDefined() expect(txn).toBeInstanceOf(KeyregTransaction) expect(txn).toEqual({ - snd: algoEncoder.decodeAddress(from), - fv: 1000, - lv: 2000, - gh: new Uint8Array(Buffer.from(genesisHash, "base64")), - note: new Uint8Array(Buffer.from(note, "base64")), - fee: 1000, type: "keyreg", + ...transactionHeader, }) - const ajv = new Ajv() const validate = ajv.compile(keyRegSchema) expect(validate(txn)).toBe(true) }) @@ -199,36 +207,158 @@ describe("Algorand Transaction Crafter", () => { }) it("(OK) Craft Keyreg non-participation transaction", async () => { // from algorand address - const from: string = algoEncoder.encodeAddress(Buffer.from(randomBytes(32))) + const from: string = algoEncoder.encodeAddress(Buffer.from(transactionHeader.snd)) // note const note: string = Buffer.from(randomBytes(32)).toString("base64") // create keyreg transaction - const txn: KeyregTransaction = algorandCrafter - .markNonParticipation(from) - .addFirstValidRound(1000) - .addLastValidRound(2000) - .addNote(note, "base64") - .addFee(1000) - .get() + const txn: KeyregTransaction = withTestTransactionHeader( + algorandCrafter + .markNonParticipation(from) + ).get() expect(txn).toBeDefined() expect(txn).toBeInstanceOf(KeyregTransaction) expect(txn).toEqual({ - snd: algoEncoder.decodeAddress(from), - fv: 1000, - lv: 2000, - gh: new Uint8Array(Buffer.from(genesisHash, "base64")), - note: new Uint8Array(Buffer.from(note, "base64")), - fee: 1000, type: "keyreg", nonpart: true, + selkey: undefined, + + ...transactionHeader, }) - const ajv = new Ajv() const validate = ajv.compile(keyRegSchema) expect(validate(txn)).toBe(true) }) }) + + describe("Asset Config Transactions", () => { + let assetConfigSchema: JSONSchemaType + + beforeAll(async () => { + assetConfigSchema = JSON.parse(fs.readFileSync(path.resolve(__dirname, "schemas/acfg.transaction.json"), "utf8")) + }) + it("(OK) Craft Asset Config create transaction", async () => { + // from algorand address + const from: string = algoEncoder.encodeAddress(Buffer.from(transactionHeader.snd)) + + const params = new AssetParamsBuilder() + .addTotal(1) + .addDecimals(1) + .addDefaultFrozen(false) + .addAssetName("Big Yeetus") + .addUnitName("YEET") + .addMetadataHash(randomBytes(32)) + .addClawbackAddress(from) + .addFreezeAddress(from) + .addManagerAddress(from) + .addReserveAddress(from) + .get() + + // create asset transaction + const txn: AssetConfigTransaction = withTestTransactionHeader( + algorandCrafter + .createAsset(from, params) + ).get() + + expect(txn).toBeDefined() + expect(txn).toBeInstanceOf(AssetConfigTransaction) + expect(txn).toEqual({ + type: "acfg", + apar: params, + caid: undefined, + ...transactionHeader, + }) + + const validate = ajv.compile(assetConfigSchema) + expect(validate(txn)).toBe(true) + }) + it("(OK) Craft AssetConfig destroy transaction", async () => { + // from algorand address + const from: string = algoEncoder.encodeAddress(Buffer.from(transactionHeader.snd)) + + // destroy asset config + const txn: AssetConfigTransaction = withTestTransactionHeader( + algorandCrafter + .destroyAsset(from, 1) + ).get() + + expect(txn).toBeDefined() + expect(txn).toBeInstanceOf(AssetConfigTransaction) + expect(txn).toEqual({ + type: "acfg", + apar: undefined, + caid: 1, + ...transactionHeader, + }) + + const validate = ajv.compile(assetConfigSchema) + expect(validate(txn)).toBe(true) + }) + }) + describe("Asset Freeze Transactions", () => { + let assetFreezeSchema: JSONSchemaType + + beforeAll(async () => { + assetFreezeSchema = JSON.parse(fs.readFileSync(path.resolve(__dirname, "schemas/afrz.transaction.json"), "utf8")) + }) + it("(OK) Craft Asset Freeze transaction", async () => { + // from algorand address + const from: string = algoEncoder.encodeAddress(Buffer.from(transactionHeader.snd)) + + // create freeze transaction + const txn: AssetFreezeTransaction = withTestTransactionHeader( + algorandCrafter + .freezeAsset(from, 1, true), + ).get() + + expect(txn).toBeDefined() + expect(txn).toBeInstanceOf(AssetFreezeTransaction) + expect(txn).toEqual({ + type: "afrz", + fadd: algoEncoder.decodeAddress(from), + faid: 1, + afrz: true, + ...transactionHeader, + }) + + const validate = ajv.compile(assetFreezeSchema) + expect(validate(txn)).toBe(true) + }) + }) + describe("Asset Transfer Transactions", () => { + let assetTransferSchema: JSONSchemaType + + beforeAll(async () => { + assetTransferSchema = JSON.parse(fs.readFileSync(path.resolve(__dirname, "schemas/axfer.transaction.json"), "utf8")) + }) + it("(OK) Craft Asset Transfer transaction", async () => { + // from algorand address + const from: string = algoEncoder.encodeAddress(Buffer.from(transactionHeader.snd)) + + // create transfer transaction + const txn: AssetTransferTransaction = withTestTransactionHeader( + algorandCrafter + .transferAsset(from, 1, from, 1) + .addAssetCloseTo(from) + .addAssetSender(from) + ).get() + + expect(txn).toBeDefined() + expect(txn).toBeInstanceOf(AssetTransferTransaction) + expect(txn).toEqual({ + type: "axfer", + xaid: 1, + aamt: 1, + arcv: algoEncoder.decodeAddress(from), + aclose: algoEncoder.decodeAddress(from), + asnd: algoEncoder.decodeAddress(from), + ...transactionHeader, + }) + + const validate = ajv.compile(assetTransferSchema) + expect(validate(txn)).toBe(true) + }) + }) }) diff --git a/lib/algorand.transaction.crafter.ts b/lib/algorand.transaction.crafter.ts index d46b5ab..a14cb2f 100644 --- a/lib/algorand.transaction.crafter.ts +++ b/lib/algorand.transaction.crafter.ts @@ -3,37 +3,41 @@ import { AlgorandEncoder } from "./algorand.encoder.js" import { type IPayTxBuilder, PayTxBuilder } from "./algorand.transaction.pay.js" import { type IKeyregTxBuilder, KeyregTxBuilder } from "./algorand.transaction.keyreg.js" import * as msgpack from "algo-msgpack-with-bigint" +import {AssetParams} from "./algorand.asset.params.js"; +import {AssetConfigTxBuilder, IAssetConfigTxBuilder} from "./algorand.transaction.acfg.js"; +import {AssetFreezeTxBuilder, IAssetFreezeTxBuilder} from "./algorand.transaction.afrz.js"; +import {AssetTransferTxBuilder, IAssetTransferTxBuilder} from "./algorand.transaction.axfer.js"; +/** + * @category SDK + */ export class AlgorandTransactionCrafter extends Crafter { - constructor(private readonly genesisId: string, private readonly genesisHash: string) { super() } - /** + * Payment Transaction * - * @param amount - * @param from - * @param to - * @returns + * @param amount The total amount to be sent in microAlgos. + * @param from The address of the account that pays the fee and amount. + * @param to The address of the account that receives the amount. */ pay(amount: number, from: string, to: string): IPayTxBuilder { return new PayTxBuilder(this.genesisId, this.genesisHash).addAmount(amount).addSender(from).addReceiver(to) } - /** + * Online Key Registration Transaction * - * @param from - * @param voteKey - * @param selectionKey - * @param stateProofKey - * @param voteFirst - * @param voteLast - * @param voteKeyDilution - * @returns + * @param from The address of the account that pays the fee and amount. + * @param voteKey The root participation public key. + * @param selectionKey The VRF public key. + * @param stateProofKey The 64 byte state proof public key commitment. + * @param voteFirst The first round that the participation key is valid. + * @param voteLast The last round that the participation key is valid. + * @param voteKeyDilution This is the dilution for the 2-level participation key. */ changeOnline(from: string, voteKey: string, selectionKey: string, stateProofKey: string, voteFirst: number, voteLast: number, voteKeyDilution: number): IKeyregTxBuilder { - return new KeyregTxBuilder(this.genesisHash) + return new KeyregTxBuilder(this.genesisId, this.genesisHash) .addSender(from) .addVoteKey(voteKey) .addSelectionKey(selectionKey) @@ -42,33 +46,80 @@ export class AlgorandTransactionCrafter extends Crafter { .addVoteLast(voteLast) .addVoteKeyDilution(voteKeyDilution) } - /** + * Offline Key Registration Transaction * - * @param from - * @returns + * @param from The address of the account that pays the fee and amount. */ changeOffline(from: string): IKeyregTxBuilder { - return new KeyregTxBuilder(this.genesisHash) + return new KeyregTxBuilder(this.genesisId, this.genesisHash) .addSender(from) } - /** + * Mark Non-Participation Transaction * - * @param from - * @returns + * @param from The address of the account that pays the fee and amount. */ markNonParticipation(from: string): IKeyregTxBuilder { - return new KeyregTxBuilder(this.genesisHash) + return new KeyregTxBuilder(this.genesisId, this.genesisHash) .addSender(from) .addNonParticipation(true) } - /** + * Create a new Asset + * + * @param from The address of the account that pays the fee and amount. + * @param params Asset Parameters + */ + createAsset(from: string, params: AssetParams): IAssetConfigTxBuilder { + return new AssetConfigTxBuilder(this.genesisId, this.genesisHash) + .addSender(from) + .addAssetParams(params) + } + /** + * Destroy an existing Asset + * + * @param from The address of the account that pays the fee and amount. + * @param caid Unique asset ID. + */ + destroyAsset(from: string, caid: number | bigint): IAssetConfigTxBuilder { + return new AssetConfigTxBuilder(this.genesisId, this.genesisHash) + .addSender(from) + .addAssetId(caid) + } + /** + * Freeze an Asset + * + * @param fadd The address of the account whose asset is being frozen or unfrozen. + * @param faid The asset ID being frozen or unfrozen. + * @param afrz True to freeze the asset. + */ + freezeAsset(fadd: string, faid: number, afrz: boolean): IAssetFreezeTxBuilder { + return new AssetFreezeTxBuilder(this.genesisId, this.genesisHash) + .addFreezeAccount(fadd) + .addFreezeAsset(faid) + .addAssetFrozen(afrz) + } + /** + * Transfer Asset Transaction + * + * @param from The address of the account that pays the fee and amount. + * @param xaid The unique ID of the asset to be transferred. + * @param arcv The recipient of the asset transfer. + * @param aamt The amount of the asset to be transferred. + */ + transferAsset(from: string, xaid: number, arcv: string, aamt: number | bigint): IAssetTransferTxBuilder { + return new AssetTransferTxBuilder(this.genesisId, this.genesisHash) + .addSender(from) + .addAssetId(xaid) + .addAssetAmount(aamt) + .addAssetReceiver(arcv) + } + /** + * Add Signature * - * @param encodedTransaction - * @param signature - * @returns + * @param encodedTransaction Transaction Bytes + * @param signature Signature Bytes */ addSignature(encodedTransaction: Uint8Array, signature: Uint8Array): Uint8Array { // remove TAG prefix diff --git a/lib/algorand.transaction.keyreg.ts b/lib/algorand.transaction.keyreg.ts index fc567de..bbb83e8 100644 --- a/lib/algorand.transaction.keyreg.ts +++ b/lib/algorand.transaction.keyreg.ts @@ -1,117 +1,198 @@ -import { AlgorandEncoder } from "./algorand.encoder.js" - -export class KeyregTransaction { - type: string - snd: Uint8Array - fee: number - fv: number - lv: number - note?: Uint8Array +import {AlgorandEncoder} from "./algorand.encoder.js" +import {ITransactionHeaderBuilder, TransactionHeader} from "./algorand.transaction.js"; +/** + * @category Transactions + * @see {@link AlgorandTransactionCrafter} + * @see {@link KeyregTxBuilder} + * @example // Manual + * const txn = new KeyregTransaction() + */ +export class KeyregTransaction extends TransactionHeader { + declare type: "keyreg" + /** + * Vote PublicKey + * + * The root participation public key. + */ votekey?: Uint8Array + /** + * Selection PublicKey + * + * The VRF public key. + */ selkey?: Uint8Array + /** + * State Proof PublicKey + * + * The 64 byte state proof public key commitment. + */ sprfkey?: Uint8Array + /** + * Vote First + * + * The first round that the participation key is valid. Not to be confused with the FirstValid round of the keyreg transaction. + */ votefst?: number + /** + * Vote Last + * + * The last round that the participation key is valid. + * Not to be confused with the LastValid round of the keyreg transaction. + */ votelst?: number + /** + * Vote Key Dilution + * + * This is the dilution for the 2-level participation key. + * It determines the interval (number of rounds) for generating new ephemeral keys. + */ votekd?: number + /** + * Nonparticipating + * + * All new Algorand accounts are participating by default. + * This means that they earn rewards. + * Mark an account nonparticipating by setting this value to true and this account will no longer earn rewards. + * It is unlikely that you will ever need to do this and exists mainly for economic-related functions on the network. + */ nonpart?: boolean - gen: string - gh: Uint8Array // encode the transaction // return the encoded transaction encode(): Uint8Array { - const encoded: Uint8Array = new AlgorandEncoder().encodeTransaction(this) - return encoded + return new AlgorandEncoder().encodeTransaction(this) } } - -export interface IKeyregTxBuilder { - addSender(sender: string): IKeyregTxBuilder - addFee(fee: number): IKeyregTxBuilder - addFirstValidRound(firstValid: number): IKeyregTxBuilder - addLastValidRound(lastValid: number): IKeyregTxBuilder - addNote(note: string, encoding?: BufferEncoding): IKeyregTxBuilder +/** + * @category Builders + * @internal + */ +export interface IKeyregTxBuilder extends ITransactionHeaderBuilder{ + /** + * Add Participation PublicKey + * + * @param voteKey The root participation public key. + * @param encoding Buffer encoding + */ addVoteKey(voteKey: string, encoding?: BufferEncoding): IKeyregTxBuilder + /** + * Add VRF PublicKey + * + * @param selectionKey The VRF public key. + * @param encoding Buffer encoding + */ addSelectionKey(selectionKey: string, encoding?: BufferEncoding): IKeyregTxBuilder + /** + * Add State Proof PublicKey + * + * @param stateProofKey The 64 byte state proof public key commitment. + * @param encoding Buffer encoding + */ addStateProofKey(stateProofKey: string, encoding?: BufferEncoding): IKeyregTxBuilder + /** + * Add Vote First + * + * @param voteFirst The first round that the participation key is valid. + */ addVoteFirst(voteFirst: number): IKeyregTxBuilder + /** + * Add Vote Last + * + * @param voteLast The last round that the participation key is valid. + */ addVoteLast(voteLast: number): IKeyregTxBuilder + /** + * Add Dilution + * + * @param voteKeyDilution This is the dilution for the 2-level participation key. + */ addVoteKeyDilution(voteKeyDilution: number): IKeyregTxBuilder + /** + * Add Non-Participating + * + * All new Algorand accounts are participating by default. + * + * @param nonParticipation Mark an account nonparticipating by setting this value to true and this account will no longer earn rewards. + */ addNonParticipation(nonParticipation: boolean): IKeyregTxBuilder get(): KeyregTransaction } - +/** + * @category Builders + */ export class KeyregTxBuilder implements IKeyregTxBuilder { - private tx: KeyregTransaction + private readonly tx: KeyregTransaction + private readonly encoder: AlgorandEncoder + + constructor(genesisId: string, genesisHash: string) { + this.encoder = new AlgorandEncoder() - constructor(genesisHash: string) { this.tx = new KeyregTransaction() - //this.tx.gen = genesisId + this.tx.gen = genesisId this.tx.gh = new Uint8Array(Buffer.from(genesisHash, "base64")) this.tx.type = "keyreg" this.tx.fee = 1000 } - - addSender(sender: string): IKeyregTxBuilder { - this.tx.snd = new AlgorandEncoder().decodeAddress(sender) - return this - } - - addFee(fee: number): IKeyregTxBuilder { - this.tx.fee = fee - return this - } - - addFirstValidRound(firstValid: number): IKeyregTxBuilder { - this.tx.fv = firstValid - return this - } - - addLastValidRound(lastValid: number): IKeyregTxBuilder { - this.tx.lv = lastValid - return this - } - - addNote(note: string, encoding: BufferEncoding = "base64"): IKeyregTxBuilder { - this.tx.note = new Uint8Array(Buffer.from(note, encoding)) - return this - } - addVoteKey(voteKey: string, encoding: BufferEncoding = "base64"): IKeyregTxBuilder { this.tx.votekey = new Uint8Array(Buffer.from(voteKey, encoding)) return this } - addSelectionKey(selectionKey: string, encoding: BufferEncoding = "base64"): IKeyregTxBuilder { this.tx.selkey = new Uint8Array(Buffer.from(selectionKey, encoding)) return this } - addStateProofKey(stateProofKey: string, encoding: BufferEncoding = "base64"): IKeyregTxBuilder { this.tx.sprfkey = new Uint8Array(Buffer.from(stateProofKey, encoding)) return this } - addVoteFirst(voteFirst: number): IKeyregTxBuilder { this.tx.votefst = voteFirst return this } - addVoteLast(voteLast: number): IKeyregTxBuilder { this.tx.votelst = voteLast return this } - addVoteKeyDilution(voteKeyDilution: number): IKeyregTxBuilder { this.tx.votekd = voteKeyDilution return this } - addNonParticipation(nonParticipation: boolean): IKeyregTxBuilder { this.tx.nonpart = nonParticipation return this } - + addSender(sender: string): IKeyregTxBuilder { + this.tx.snd = this.encoder.decodeAddress(sender) + return this + } + addFee(fee: number): IKeyregTxBuilder { + this.tx.fee = fee + return this + } + addFirstValidRound(fv: number): IKeyregTxBuilder { + this.tx.fv = fv + return this + } + addLastValidRound(lv: number): IKeyregTxBuilder { + this.tx.lv = lv + return this + } + addNote(note: string, encoding: BufferEncoding = "utf8"): IKeyregTxBuilder { + this.tx.note = new Uint8Array(Buffer.from(note, encoding)) + return this + } + addRekey(rekey: string): IKeyregTxBuilder { + this.tx.rekey = this.encoder.decodeAddress(rekey) + return this + } + addLease(lx: Uint8Array): IKeyregTxBuilder { + this.tx.lx = lx + return this + } + addGroup(grp: Uint8Array): IKeyregTxBuilder { + this.tx.grp = grp + return this + } get(): KeyregTransaction { return this.tx } diff --git a/lib/algorand.transaction.pay.ts b/lib/algorand.transaction.pay.ts index a0e8885..b96b682 100644 --- a/lib/algorand.transaction.pay.ts +++ b/lib/algorand.transaction.pay.ts @@ -1,83 +1,128 @@ -import { AlgorandEncoder } from "./algorand.encoder.js" +import {AlgorandEncoder} from "./algorand.encoder.js" +import {ITransactionHeaderBuilder, TransactionHeader} from "./algorand.transaction.js"; -export class PayTransaction { - type: string - snd: Uint8Array +/** + * @category Transactions + * @see {@link AlgorandTransactionCrafter} + * @see {@link PayTxBuilder} + * @example // Manual + * const txn = new PayTransaction() + */ +export class PayTransaction extends TransactionHeader { + declare type: "pay" + /** + * Receiver + * + * The address of the account that receives the amount. + */ rcv: Uint8Array + /** + * Amount + * + * The total amount to be sent in microAlgos. + */ amt: number - fee: number - fv: number - lv: number - note?: Uint8Array - gen?: string - gh: Uint8Array + + /** + * Close Remainder To + * + * When set, it indicates that the transaction is requesting that the Sender account should be closed, + * and all remaining funds, after the fee and amount are paid, be transferred to this address. + */ + close?: Uint8Array // encode the transaction // return the encoded transaction encode(): Uint8Array { - const encoded: Uint8Array = new AlgorandEncoder().encodeTransaction(this) - return encoded + return new AlgorandEncoder().encodeTransaction(this) } } -export interface IPayTxBuilder { - addSender(sender: string): IPayTxBuilder +/** + * @category Builders + * @internal + */ +export interface IPayTxBuilder extends ITransactionHeaderBuilder{ + /** + * Add Receiver + * + * @param receiver The address of the account that receives the amount. + */ addReceiver(receiver: string): IPayTxBuilder + /** + * Add Amount + * + * @param amount The total amount to be sent in microAlgos. + */ addAmount(amount: number): IPayTxBuilder - addFee(fee: number): IPayTxBuilder - addFirstValidRound(firstValid: number): IPayTxBuilder - addLastValidRound(lastValid: number): IPayTxBuilder - addNote(note: string, encoding?: BufferEncoding): IPayTxBuilder - + /** + * Add Close Remainder To + * + * @param close Indicates that the transaction is requesting that the Sender account should be closed. + */ + addCloseTo(close: string): IPayTxBuilder get(): PayTransaction } - +/** + * @category Builders + */ export class PayTxBuilder implements IPayTxBuilder { - private tx: PayTransaction + private readonly tx: PayTransaction + private readonly encoder: AlgorandEncoder constructor(genesisId: string, genesisHash: string) { + this.encoder = new AlgorandEncoder() + this.tx = new PayTransaction() this.tx.gen = genesisId this.tx.gh = new Uint8Array(Buffer.from(genesisHash, "base64")) this.tx.type = "pay" this.tx.fee = 1000 } - - addSender(sender: string): IPayTxBuilder { - this.tx.snd = new AlgorandEncoder().decodeAddress(sender) - return this - } - addReceiver(receiver: string): IPayTxBuilder { - this.tx.rcv = new AlgorandEncoder().decodeAddress(receiver) + this.tx.rcv = this.encoder.decodeAddress(receiver) return this } - addAmount(amount: number): IPayTxBuilder { this.tx.amt = amount return this } - + addCloseTo(close: string): IPayTxBuilder { + this.tx.close = this.encoder.decodeAddress(close) + return this + } + addSender(sender: string): IPayTxBuilder { + this.tx.snd = this.encoder.decodeAddress(sender) + return this + } addFee(fee: number): IPayTxBuilder { this.tx.fee = fee return this } - - addFirstValidRound(firstValid: number): IPayTxBuilder { - this.tx.fv = firstValid + addFirstValidRound(fv: number): IPayTxBuilder { + this.tx.fv = fv return this } - - addLastValidRound(lastValid: number): IPayTxBuilder { - this.tx.lv = lastValid + addLastValidRound(lv: number): IPayTxBuilder { + this.tx.lv = lv return this } - addNote(note: string, encoding: BufferEncoding = "utf8"): IPayTxBuilder { this.tx.note = new Uint8Array(Buffer.from(note, encoding)) return this } - + addRekey(rekey: string): IPayTxBuilder { + this.tx.rekey = this.encoder.decodeAddress(rekey) + return this + } + addLease(lx: Uint8Array): IPayTxBuilder { + this.tx.lx = lx + return this + } + addGroup(grp: Uint8Array): IPayTxBuilder { + this.tx.grp = grp + return this + } get(): PayTransaction { return this.tx } diff --git a/lib/algorand.transaction.ts b/lib/algorand.transaction.ts new file mode 100644 index 0000000..8c12353 --- /dev/null +++ b/lib/algorand.transaction.ts @@ -0,0 +1,170 @@ +import {PayTransaction} from "./algorand.transaction.pay.js"; +import {AssetConfigTransaction} from "./algorand.transaction.acfg.js"; +import {AssetTransferTransaction} from "./algorand.transaction.axfer.js"; +import {AssetFreezeTransaction} from "./algorand.transaction.afrz.js"; +import {KeyregTransaction} from "./algorand.transaction.keyreg.js"; + +/** + * Transaction Alias + * + * All transactions extend from + * + * @category Common + */ +export type Transaction = PayTransaction | AssetConfigTransaction | AssetTransferTransaction | AssetFreezeTransaction | KeyregTransaction +/** + * Specifies the type of transaction. This value is automatically generated using any of the developer tools. + * @category Common + */ +export type TransactionType = "pay" | "keyreg" | "acfg" | "axfer" | "afrz" | "appl" | "stpf" + +/** + * + * Transaction Header + * + * Shared keys for all transactions + * + * @category Common + */ +export abstract class TransactionHeader { + /** + * Transaction Type + * + * Specifies the type of transaction. This value is automatically generated using any of the developer tools. + */ + type: TransactionType + /** + * Sender + * + * The address of the account that pays the fee and amount. + */ + snd: Uint8Array + /** + * Fee + * + * Paid by the sender to the FeeSink to prevent denial-of-service. The minimum fee on Algorand is currently 1000 microAlgos. + */ + fee: number + /** + * First Valid + * + * The first round for when the transaction is valid. If the transaction is sent prior to this round it will be rejected by the network. + */ + fv: number + /** + * Last Valid + * + * The ending round for which the transaction is valid. After this round, the transaction will be rejected by the network. + */ + lv: number + /** + * Genesis Hash + * + * The hash of the genesis block of the network for which the transaction is valid. See the genesis hash for MainNet, TestNet, and BetaNet. + */ + gh: Uint8Array + /** + * Genesis ID + * + * The human-readable string that identifies the network for the transaction. + * The genesis ID is found in the genesis block. See the genesis ID for MainNet, TestNet, and BetaNet. + */ + gen?: string + /** + * Note + * + * Any data up to 1000 bytes. + */ + note?: Uint8Array + /** + * Rekey To + * + * Specifies the authorized address. This address will be used to authorize all future transactions. + */ + rekey?: Uint8Array + /** + * Lease + * + * A lease enforces mutual exclusion of transactions. If this field is nonzero, then once the transaction is confirmed, + * it acquires the lease identified by the (Sender, Lease) pair of the transaction until the LastValid round passes. + * While this transaction possesses the lease, no other transaction specifying this lease can be confirmed. + * A lease is often used in the context of Algorand Smart Contracts to prevent replay attacks. + * Read more about Algorand Smart Contracts. Leases can also be used to safeguard against unintended duplicate spends. + * For example, if I send a transaction to the network and later realize my fee was too low, + * I could send another transaction with a higher fee, but the same lease value. + * This would ensure that only one of those transactions ends up getting confirmed during the validity period. + */ + lx?: Uint8Array + /** + * Group + * + * The group specifies that the transaction is part of a group and, if so, specifies the hash of the transaction group. + * Assign a group ID to a transaction through the workflow described in the Atomic Transfers Guide. + */ + grp?: Uint8Array +} + +/** + * Interface for Transaction Header Builders + * @category Builders + * @internal + */ +export interface ITransactionHeaderBuilder { + /** + * Add Sender + * + * @param sender The address of the account that pays the fee and amount. + */ + addSender(sender: string): T + + /** + * Add Fee + * + * @param fee Paid by the sender to the FeeSink to prevent denial-of-service. The minimum fee on Algorand is currently 1000 microAlgos. + */ + addFee(fee: number): T + + /** + * Add First Valid Round + * + * @param fv The first round for when the transaction is valid. If the transaction is sent prior to this round it will be rejected by the network. + */ + addFirstValidRound(fv: number): T + + /** + * Add Last Valid Round + * + * @param lv The ending round for which the transaction is valid. After this round, the transaction will be rejected by the network. + */ + addLastValidRound(lv: number): T + + /** + * Add Note + * + * @param note Any data up to 1000 bytes. + * @param encoding + */ + addNote(note: string, encoding?: BufferEncoding): T + + /** + * Add Rekey Address + * + * @param rekey Specifies the authorized address. This address will be used to authorize all future transactions. + */ + addRekey(rekey: string): T + + /** + * Add Lease + * + * @param lx A lease enforces mutual exclusion of transactions. If this field is nonzero, then once the transaction + * is confirmed, it acquires the lease identified by the (Sender, Lease) pair of the transaction until the LastValid round passes. + */ + addLease(lx: Uint8Array): T + + /** + * Add Group + * + * @param grp The group specifies that the transaction is part of a group and, if so, specifies the hash of the transaction group. + */ + addGroup(grp: Uint8Array): T +} \ No newline at end of file diff --git a/lib/index.ts b/lib/index.ts index 2d2e2f6..82c48e1 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -1,4 +1,18 @@ +/** + * Algo Models + * + * Crafting Bytes for Transactions + */ export * from './algorand.encoder.js' export * from './algorand.transaction.crafter.js' -export * from './algorand.transaction.pay.js' + +// Transactions/Builders +export * from './algorand.transaction.acfg.js' +export * from './algorand.transaction.afrz.js' +export * from './algorand.transaction.axfer.js' export * from './algorand.transaction.keyreg.js' +export * from './algorand.transaction.pay.js' + +// Common +export * from './algorand.asset.params.js' +export * from './algorand.transaction.js' diff --git a/lib/schemas/acfg.transaction.json b/lib/schemas/acfg.transaction.json new file mode 100644 index 0000000..09a552e --- /dev/null +++ b/lib/schemas/acfg.transaction.json @@ -0,0 +1,24 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "http://algo-models.com/schemas/acfg.transaction.json", + "title": "Asset Configuration Transaction", + "type": "object", + "allOf": [ + { "$ref": "http://algo-models.com/schemas/transaction.header.json"}, + { + "properties": { + "type": { + "type": "string", + "const": "acfg" + }, + "caid": { + "type": "integer", + "description": "For re-configure or destroy transactions, this is the unique asset ID. On asset creation, the ID is set to zero." + }, + "apar": { + "$ref": "http://algo-models.com/schemas/asset.params.json", + "description": "Asset Parameters" + } + } + }] +} \ No newline at end of file diff --git a/lib/schemas/afrz.transaction.json b/lib/schemas/afrz.transaction.json new file mode 100644 index 0000000..3d733e4 --- /dev/null +++ b/lib/schemas/afrz.transaction.json @@ -0,0 +1,29 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "http://algo-models.com/schemas/afrz.transaction.json", + "title": "Asset Freeze Transaction", + "type": "object", + "allOf": [ + { "$ref": "http://algo-models.com/schemas/transaction.header.json"}, + { + "properties": { + "type": { + "type": "string", + "const": "afrz" + }, + "fadd": { + "$ref": "http://algo-models.com/schemas/bytes32.json", + "description": "The address of the account whose asset is being frozen or unfrozen." + }, + "faid": { + "type": "integer", + "description": "The asset ID being frozen or unfrozen." + }, + "afrz": { + "type": "boolean", + "description": "True to freeze the asset." + } + }, + "required": ["fadd", "faid", "afrz"] + }] +} \ No newline at end of file diff --git a/lib/schemas/asset.params.json b/lib/schemas/asset.params.json new file mode 100644 index 0000000..b5a3751 --- /dev/null +++ b/lib/schemas/asset.params.json @@ -0,0 +1,52 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "http://algo-models.com/schemas/asset.params.json", + "title": "Asset Parameters", + "type": "object", + "properties": { + "t": { + "type": "integer", + "description": "The total number of base units of the asset to create. This number cannot be changed." + }, + "dc": { + "type": "integer", + "description": "The number of digits to use after the decimal point when displaying the asset. If 0, the asset is not divisible. If 1, the base unit of the asset is in tenths. If 2, the base unit of the asset is in hundredths, if 3, the base unit of the asset is in thousandths, and so on up to 19 decimal places" + }, + "df": { + "type": "boolean", + "description": "True to freeze holdings for this asset by default." + }, + "un": { + "type": "string", + "description": "The name of a unit of this asset. Supplied on creation. Max size is 8 bytes. Example: USDT" + }, + "an": { + "type": "string", + "description": "The name of the asset. Supplied on creation. Max size is 32 bytes. Example: Tether" + }, + "au": { + "type": "string", + "description": "Specifies a URL where more information about the asset can be retrieved. Max size is 96 bytes." + }, + "am": { + "$ref": "http://algo-models.com/schemas/bytes32.json", + "description": "This field is intended to be a 32-byte hash of some metadata that is relevant to your asset and/or asset holders. The format of this metadata is up to the application. This field can only be specified upon creation. An example might be the hash of some certificate that acknowledges the digitized asset as the official representation of a particular real-world asset." + }, + "m": { + "$ref": "http://algo-models.com/schemas/bytes32.json", + "description": "The address of the account that can manage the configuration of the asset and destroy it." + }, + "r": { + "$ref": "http://algo-models.com/schemas/bytes32.json", + "description": "The address of the account that holds the reserve (non-minted) units of the asset. This address has no specific authority in the protocol itself. It is used in the case where you want to signal to holders of your asset that the non-minted units of the asset reside in an account that is different from the default creator account (the sender)." + }, + "f": { + "$ref": "http://algo-models.com/schemas/bytes32.json", + "description": "The address of the account used to freeze holdings of this asset. If empty, freezing is not permitted." + }, + "c": { + "$ref": "http://algo-models.com/schemas/bytes32.json", + "description": "The address of the account that can clawback holdings of this asset. If empty, clawback is not permitted." + } + } +} \ No newline at end of file diff --git a/lib/schemas/axfer.transaction.json b/lib/schemas/axfer.transaction.json new file mode 100644 index 0000000..6f98588 --- /dev/null +++ b/lib/schemas/axfer.transaction.json @@ -0,0 +1,37 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "http://algo-models.com/schemas/axfer.transaction.json", + "title": "Asset Transfer Transaction", + "type": "object", + "allOf": [ + { "$ref": "http://algo-models.com/schemas/transaction.header.json"}, + { + "properties": { + "type": { + "type": "string", + "const": "axfer" + }, + "xaid": { + "type": "integer", + "description": "The unique ID of the asset to be transferred." + }, + "aamt": { + "type": "integer", + "description": "The amount of the asset to be transferred. A zero amount transferred to self allocates that asset in the account's Asset map." + }, + "asnd": { + "$ref": "http://algo-models.com/schemas/bytes32.json", + "description": "The sender of the transfer. The regular sender field should be used and this one set to the zero value for regular transfers between accounts. If this value is nonzero, it indicates a clawback transaction where the sender is the asset's clawback address and the asset sender is the address from which the funds will be withdrawn." + }, + "arcv": { + "$ref": "http://algo-models.com/schemas/bytes32.json", + "description": "The recipient of the asset transfer." + }, + "aclose": { + "$ref": "http://algo-models.com/schemas/bytes32.json", + "description": "Specify this field to remove the asset holding from the sender account and reduce the account's minimum balance (i.e. opt-out of the asset)." + } + }, + "required": ["type", "xaid", "aamt", "arcv"] + }] +} \ No newline at end of file diff --git a/lib/schemas/bytes32.json b/lib/schemas/bytes32.json new file mode 100644 index 0000000..6a54be9 --- /dev/null +++ b/lib/schemas/bytes32.json @@ -0,0 +1,202 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "http://algo-models.com/schemas/bytes32.json", + "title": "32 Bytes", + "type": "object", + "properties": { + "0": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "1": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "2": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "3": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "4": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "5": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "6": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "7": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "8": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "9": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "10": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "11": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "12": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "13": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "14": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "15": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "16": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "17": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "18": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "19": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "20": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "21": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "22": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "23": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "24": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "25": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "26": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "27": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "28": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "29": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "30": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "31": { + "type": "integer", + "minimum": 0, + "maximum": 255 + } + }, + "required": [ + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "10", + "11", + "12", + "13", + "14", + "15", + "16", + "17", + "18", + "19", + "20", + "21", + "22", + "23", + "24", + "25", + "26", + "27", + "28", + "29", + "30", + "31" + ] +} \ No newline at end of file diff --git a/lib/schemas/bytes64.json b/lib/schemas/bytes64.json new file mode 100644 index 0000000..7b3dc57 --- /dev/null +++ b/lib/schemas/bytes64.json @@ -0,0 +1,328 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "http://algo-models.com/schemas/bytes64.json", + "title": "64 Bytes", + "type": "object", + "properties": { + "0": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "1": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "2": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "3": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "4": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "5": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "6": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "7": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "8": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "9": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "10": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "11": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "12": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "13": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "14": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "15": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "16": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "17": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "18": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "19": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "20": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "21": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "22": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "23": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "24": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "25": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "26": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "27": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "28": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "29": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "30": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "31": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "32": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "33": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "34": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "35": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "36": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "37": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "38": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "39": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "40": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "41": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "42": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "43": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "44": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "45": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "46": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "47": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "48": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "49": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "50": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "51": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "52": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "53": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "54": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "55": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "56": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "57": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "58": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "59": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "60": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "61": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "62": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "63": { + "type": "integer", + "minimum": 0, + "maximum": 255 + } + } +} \ No newline at end of file diff --git a/lib/schemas/keyreg.transaction.nonparticipation.json b/lib/schemas/keyreg.transaction.nonparticipation.json index 313a53c..ccf84d5 100644 --- a/lib/schemas/keyreg.transaction.nonparticipation.json +++ b/lib/schemas/keyreg.transaction.nonparticipation.json @@ -1,246 +1,26 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "title": "Key Reg No Participation", "$id": "http://algo-models.com/schemas/keyreg.transaction.nonparticipation.json", + "title": "Key Reg No Participation", "type": "object", - "properties": { - "gh": { - "$ref": "http://algo-models.com/schemas/bytes32.json" - }, - "type": { - "type": "string", - "const": "keyreg" - }, - "nonpart": { - "type": "boolean", - "const": true - }, - "fee": { - "type": "integer", - "minimum": 0 - }, - "snd": { - "$ref": "http://algo-models.com/schemas/bytes32.json" - }, - "fv": { - "type": "integer", - "minimum": 0 - }, - "lv": { - "type": "integer", - "minimum": 0 - } - }, - "required": [ - "gh", - "type", - "nonpart", - "fee", - "snd", - "fv", - "lv", - "note" - ], - "$defs": { - "bytes32": { - "$id": "http://algo-models.com/schemas/bytes32.json", - "type": "object", + "allOf": [ + { "$ref": "http://algo-models.com/schemas/transaction.header.json"}, + { "properties": { - "0": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "1": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "2": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "3": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "4": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "5": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "6": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "7": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "8": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "9": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "10": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "11": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "12": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "13": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "14": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "15": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "16": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "17": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "18": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "19": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "20": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "21": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "22": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "23": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "24": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "25": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "26": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "27": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "28": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "29": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "30": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "31": { - "type": "integer", - "minimum": 0, - "maximum": 255 + "type": { + "type": "string", + "const": "keyreg" + }, + "nonpart": { + "type": "boolean", + "const": true, + "description": "" } }, "required": [ - "0", - "1", - "2", - "3", - "4", - "5", - "6", - "7", - "8", - "9", - "10", - "11", - "12", - "13", - "14", - "15", - "16", - "17", - "18", - "19", - "20", - "21", - "22", - "23", - "24", - "25", - "26", - "27", - "28", - "29", - "30", - "31" + "type", + "nonpart" ] } - } + ] } \ No newline at end of file diff --git a/lib/schemas/keyreg.transaction.offline.json b/lib/schemas/keyreg.transaction.offline.json index 594ccf5..68eb697 100644 --- a/lib/schemas/keyreg.transaction.offline.json +++ b/lib/schemas/keyreg.transaction.offline.json @@ -3,579 +3,32 @@ "$id": "http://algo-models.com/schemas/keyreg.transaction.offline.json", "title": "Key Registration Offline Transaction", "type": "object", - "properties": { - "gh": { - "$ref": "http://algo-models.com/schemas/bytes32.json" - }, - "type": { - "type": "string", - "const": "keyreg" - }, - "nonpart": { - "type": "boolean", - "const": false - }, - "fee": { - "type": "integer", - "minimum": 0 - }, - "snd": { - "$ref": "http://algo-models.com/schemas/bytes32.json" - }, - "fv": { - "type": "integer", - "minimum": 0 - }, - "lv": { - "type": "integer", - "minimum": 0 - } - }, - "required": [ - "gh", - "type", - "fee", - "snd", - "fv", - "lv" - ], - "not": { - "required": [ - "votekey", - "selkey", - "sprfkey", - "votefst", - "votelst", - "votekd" - - ] - }, - "$defs": { - "bytes32": { - "$id": "http://algo-models.com/schemas/bytes32.json", - "type": "object", + "allOf": [ + { "$ref": "http://algo-models.com/schemas/transaction.header.json"}, + { "properties": { - "0": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "1": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "2": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "3": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "4": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "5": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "6": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "7": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "8": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "9": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "10": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "11": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "12": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "13": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "14": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "15": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "16": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "17": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "18": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "19": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "20": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "21": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "22": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "23": { - "type": "integer", - "minimum": 0, - "maximum": 255 + "type": { + "type": "string", + "const": "keyreg" }, - "24": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "25": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "26": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "27": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "28": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "29": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "30": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "31": { - "type": "integer", - "minimum": 0, - "maximum": 255 + "nonpart": { + "type": "boolean", + "const": false } }, "required": [ - "0", - "1", - "2", - "3", - "4", - "5", - "6", - "7", - "8", - "9", - "10", - "11", - "12", - "13", - "14", - "15", - "16", - "17", - "18", - "19", - "20", - "21", - "22", - "23", - "24", - "25", - "26", - "27", - "28", - "29", - "30", - "31" - ] - }, - "bytes64": { - "$id": "http://algo-models.com/schemas/bytes64.json", - "type": "object", - "properties": { - "0": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "1": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "2": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "3": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "4": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "5": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "6": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "7": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "8": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "9": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "10": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "11": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "12": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "13": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "14": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "15": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "16": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "17": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "18": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "19": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "20": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "21": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "22": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "23": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "24": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "25": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "26": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "27": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "28": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "29": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "30": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "31": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "32": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "33": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "34": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "35": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "36": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "37": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "38": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "39": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "40": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "41": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "42": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "43": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "44": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "45": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "46": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "47": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "48": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "49": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "50": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "51": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "52": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "53": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "54": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "55": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "56": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "57": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "58": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "59": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "60": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "61": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "62": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "63": { - "type": "integer", - "minimum": 0, - "maximum": 255 - } + "type" + ], + "not": { + "required": [ + "votekey", + "selkey", + "sprfkey", + "votefst", + "votelst", + "votekd" + ] } } - } + ] } \ No newline at end of file diff --git a/lib/schemas/keyreg.transaction.online.json b/lib/schemas/keyreg.transaction.online.json index 1acb476..4a98c46 100644 --- a/lib/schemas/keyreg.transaction.online.json +++ b/lib/schemas/keyreg.transaction.online.json @@ -3,592 +3,53 @@ "$id": "http://algo-models.com/schemas/keyreg.transaction.online.json", "title": "Key Registration Online Transaction", "type": "object", - "properties": { - "gh": { - "$ref": "http://algo-models.com/schemas/bytes32.json" - }, - "type": { - "type": "string", - "const": "keyreg" - }, - "nonpart": { - "type": "boolean", - "const": false - }, - "fee": { - "type": "integer", - "minimum": 0 - }, - "snd": { - "$ref": "http://algo-models.com/schemas/bytes32.json" - }, - "votekey": { - "$ref": "http://algo-models.com/schemas/bytes32.json" - }, - "selkey": { - "$ref": "http://algo-models.com/schemas/bytes32.json" - }, - "sprfkey": { - "$ref": "http://algo-models.com/schemas/bytes64.json" - }, - "votefst": { - "type": "integer" - }, - "votelst": { - "type": "integer" - }, - "votekd": { - "type": "integer" - }, - "fv": { - "type": "integer", - "minimum": 0 - }, - "lv": { - "type": "integer", - "minimum": 0 - } - }, - "required": [ - "gh", - "type", - "fee", - "snd", - "votekey", - "selkey", - "sprfkey", - "votefst", - "votelst", - "votekd", - "fv", - "lv" - ], - "$defs": { - "bytes32": { - "$id": "http://algo-models.com/schemas/bytes32.json", - "type": "object", + "allOf": [ + { "$ref": "http://algo-models.com/schemas/transaction.header.json"}, + { "properties": { - "0": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "1": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "2": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "3": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "4": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "5": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "6": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "7": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "8": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "9": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "10": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "11": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "12": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "13": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "14": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "15": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "16": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "17": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "18": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "19": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "20": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "21": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "22": { - "type": "integer", - "minimum": 0, - "maximum": 255 + "type": { + "type": "string", + "const": "keyreg" }, - "23": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "24": { - "type": "integer", - "minimum": 0, - "maximum": 255 + "nonpart": { + "type": "boolean", + "const": false, + "description": "All new Algorand accounts are participating by default. This means that they earn rewards. Mark an account nonparticipating by setting this value to true and this account will no longer earn rewards. It is unlikely that you will ever need to do this and exists mainly for economic-related functions on the network." }, - "25": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "26": { - "type": "integer", - "minimum": 0, - "maximum": 255 + "votekey": { + "$ref": "http://algo-models.com/schemas/bytes32.json", + "description": "The root participation public key. See Generate a Participation Key to learn more." }, - "27": { - "type": "integer", - "minimum": 0, - "maximum": 255 + "selkey": { + "$ref": "http://algo-models.com/schemas/bytes32.json", + "description": "The VRF public key." }, - "28": { - "type": "integer", - "minimum": 0, - "maximum": 255 + "sprfkey": { + "$ref": "http://algo-models.com/schemas/bytes64.json", + "description": "The 64 byte state proof public key commitment." }, - "29": { + "votefst": { "type": "integer", - "minimum": 0, - "maximum": 255 + "description": "The first round that the participation key is valid. Not to be confused with the FirstValid round of the keyreg transaction." }, - "30": { + "votelst": { "type": "integer", - "minimum": 0, - "maximum": 255 + "description": "The last round that the participation key is valid. Not to be confused with the LastValid round of the keyreg transaction." }, - "31": { + "votekd": { "type": "integer", - "minimum": 0, - "maximum": 255 + "description": "This is the dilution for the 2-level participation key. It determines the interval (number of rounds) for generating new ephemeral keys." } }, "required": [ - "0", - "1", - "2", - "3", - "4", - "5", - "6", - "7", - "8", - "9", - "10", - "11", - "12", - "13", - "14", - "15", - "16", - "17", - "18", - "19", - "20", - "21", - "22", - "23", - "24", - "25", - "26", - "27", - "28", - "29", - "30", - "31" + "type", + "votekey", + "selkey", + "sprfkey", + "votefst", + "votelst", + "votekd" ] - }, - "bytes64": { - "$id": "http://algo-models.com/schemas/bytes64.json", - "type": "object", - "properties": { - "0": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "1": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "2": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "3": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "4": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "5": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "6": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "7": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "8": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "9": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "10": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "11": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "12": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "13": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "14": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "15": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "16": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "17": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "18": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "19": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "20": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "21": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "22": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "23": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "24": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "25": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "26": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "27": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "28": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "29": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "30": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "31": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "32": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "33": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "34": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "35": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "36": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "37": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "38": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "39": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "40": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "41": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "42": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "43": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "44": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "45": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "46": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "47": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "48": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "49": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "50": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "51": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "52": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "53": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "54": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "55": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "56": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "57": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "58": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "59": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "60": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "61": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "62": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "63": { - "type": "integer", - "minimum": 0, - "maximum": 255 - } - } } - } + ] } \ No newline at end of file diff --git a/lib/schemas/pay.transaction.json b/lib/schemas/pay.transaction.json index 6a762ea..2043cd1 100644 --- a/lib/schemas/pay.transaction.json +++ b/lib/schemas/pay.transaction.json @@ -3,251 +3,31 @@ "$id": "http://algo-models.com/schemas/pay.transaction.json", "title": "Payment Transaction", "type": "object", - "properties": { - "gen": { - "type": "string" - }, - "close": { - "$ref": "http://algo-models.com/schemas/bytes32.json" - }, - "gh": { - "$ref": "http://algo-models.com/schemas/bytes32.json" - }, - "type": { - "type": "string", - "const": "pay" - }, - "fee": { - "type": "integer" - }, - "amt": { - "type": "integer" - }, - "snd": { - "$ref": "http://algo-models.com/schemas/bytes32.json" - }, - "rcv": { - "$ref": "http://algo-models.com/schemas/bytes32.json" - }, - "fv": { - "type": "integer", - "minimum": 0 - }, - "lv": { - "type": "integer", - "minimum": 0 - } - }, - "required": [ - "gh", - "type", - "fee", - "amt", - "snd", - "rcv", - "fv", - "lv" - ], - "$defs": { - "bytes32": { - "$id": "http://algo-models.com/schemas/bytes32.json", - "type": "object", + "allOf": [ + { "$ref": "http://algo-models.com/schemas/transaction.header.json"}, + { "properties": { - "0": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "1": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "2": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "3": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "4": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "5": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "6": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "7": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "8": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "9": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "10": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "11": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "12": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "13": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "14": { - "type": "integer", - "minimum": 0, - "maximum": 255 + "type": { + "type": "string", + "const": "pay" }, - "15": { + "amt": { "type": "integer", - "minimum": 0, - "maximum": 255 + "description": "The total amount to be sent in microAlgos." }, - "16": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "17": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "18": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "19": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "20": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "21": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "22": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "23": { - "type": "integer", - "minimum": 0, - "maximum": 255 + "rcv": { + "$ref": "http://algo-models.com/schemas/bytes32.json", + "description": "The address of the account that receives the amount." }, - "24": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "25": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "26": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "27": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "28": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "29": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "30": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "31": { - "type": "integer", - "minimum": 0, - "maximum": 255 + "close": { + "$ref": "http://algo-models.com/schemas/bytes32.json", + "description": "When set, it indicates that the transaction is requesting that the Sender account should be closed, and all remaining funds, after the fee and amount are paid, be transferred to this address." } }, "required": [ - "0", - "1", - "2", - "3", - "4", - "5", - "6", - "7", - "8", - "9", - "10", - "11", - "12", - "13", - "14", - "15", - "16", - "17", - "18", - "19", - "20", - "21", - "22", - "23", - "24", - "25", - "26", - "27", - "28", - "29", - "30", - "31" + "type", + "amt" ] } - } + ] } \ No newline at end of file diff --git a/lib/schemas/transaction.header.json b/lib/schemas/transaction.header.json new file mode 100644 index 0000000..19c4335 --- /dev/null +++ b/lib/schemas/transaction.header.json @@ -0,0 +1,56 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "http://algo-models.com/schemas/transaction.header.json", + "title": "Transaction Header", + "type": "object", + "properties": { + "fee": { + "type": "integer", + "description": "Paid by the sender to the FeeSink to prevent denial-of-service. The minimum fee on Algorand is currently 1000 microAlgos." + }, + "fv": { + "type": "integer", + "minimum": 0, + "description": "The first round for when the transaction is valid. If the transaction is sent prior to this round it will be rejected by the network." + }, + "gh": { + "$ref": "http://algo-models.com/schemas/bytes32.json", + "description": "The hash of the genesis block of the network for which the transaction is valid. See the genesis hash for MainNet, TestNet, and BetaNet." + }, + "lv": { + "type": "integer", + "minimum": 0, + "description": "The ending round for which the transaction is valid. After this round, the transaction will be rejected by the network." + }, + "snd": { + "$ref": "http://algo-models.com/schemas/bytes32.json", + "description": "The address of the account that pays the fee and amount." + }, + "type": { + "type": "string", + "enum": ["pay", "keyreg", "acfg", "axfer", "afrz", "appl", "stpf"], + "description": "Specifies the type of transaction. This value is automatically generated using any of the developer tools." + }, + "gen": { + "type": "string", + "description": "The human-readable string that identifies the network for the transaction. The genesis ID is found in the genesis block. See the genesis ID for MainNet, TestNet, and BetaNet." + }, + "grp": { + "$ref": "http://algo-models.com/schemas/bytes32.json", + "description": "The group specifies that the transaction is part of a group and, if so, specifies the hash of the transaction group. Assign a group ID to a transaction through the workflow described in the Atomic Transfers Guide." + }, + "lx": { + "$ref": "http://algo-models.com/schemas/bytes32.json", + "description": "A lease enforces mutual exclusion of transactions. If this field is nonzero, then once the transaction is confirmed, it acquires the lease identified by the (Sender, Lease) pair of the transaction until the LastValid round passes. While this transaction possesses the lease, no other transaction specifying this lease can be confirmed. A lease is often used in the context of Algorand Smart Contracts to prevent replay attacks. Read more about Algorand Smart Contracts. Leases can also be used to safeguard against unintended duplicate spends. For example, if I send a transaction to the network and later realize my fee was too low, I could send another transaction with a higher fee, but the same lease value. This would ensure that only one of those transactions ends up getting confirmed during the validity period." + }, + "note": { + "type": "object", + "description": "Any data up to 1000 bytes." + }, + "rekey": { + "$ref": "http://algo-models.com/schemas/bytes32.json", + "description": "Specifies the authorized address. This address will be used to authorize all future transactions." + } + }, + "required": ["fee", "fv", "gh", "lv", "snd", "type"] +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index d6c4beb..d581643 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "@types/node": "^20.7.1", "ts-jest": "^29.1.1", "tweetnacl": "^1.0.3", + "typedoc": "^0.26.7", "typescript": "^5.2.2" } }, @@ -1077,6 +1078,24 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@shikijs/core": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.16.3.tgz", + "integrity": "sha512-yETIvrETCeC39gSPIiSADmjri9FwKmxz0QvONMtTIUYlKZe90CJkvcjPksayC2VQOtzOJonEiULUa8v8crUQvA==", + "dev": true, + "dependencies": { + "@shikijs/vscode-textmate": "^9.2.0", + "@types/hast": "^3.0.4", + "oniguruma-to-js": "0.3.3", + "regex": "4.3.2" + } + }, + "node_modules/@shikijs/vscode-textmate": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-9.2.2.tgz", + "integrity": "sha512-TMp15K+GGYrWlZM8+Lnj9EaHEFmOen0WJBrfa17hF7taDOYthuPPV0GWzfd/9iMij0akS/8Yw2ikquH7uVi/fg==", + "dev": true + }, "node_modules/@sinclair/typebox": { "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", @@ -1158,6 +1177,15 @@ "@types/node": "*" } }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "dev": true, + "dependencies": { + "@types/unist": "*" + } + }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", @@ -1204,6 +1232,12 @@ "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", "dev": true }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "dev": true + }, "node_modules/@types/yargs": { "version": "17.0.25", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.25.tgz", @@ -1424,8 +1458,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "peer": true + "dev": true }, "node_modules/brace-expansion": { "version": "1.1.11", @@ -1792,6 +1825,18 @@ "dev": true, "peer": true }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -3012,6 +3057,15 @@ "dev": true, "peer": true }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "dev": true, + "dependencies": { + "uc.micro": "^2.0.0" + } + }, "node_modules/locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -3041,6 +3095,12 @@ "yallist": "^3.0.2" } }, + "node_modules/lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "dev": true + }, "node_modules/make-dir": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", @@ -3109,6 +3169,35 @@ "tmpl": "1.0.5" } }, + "node_modules/markdown-it": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, + "node_modules/markdown-it/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "dev": true + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -3229,6 +3318,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/oniguruma-to-js": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/oniguruma-to-js/-/oniguruma-to-js-0.3.3.tgz", + "integrity": "sha512-m90/WEhgs8g4BxG37+Nu3YrMfJDs2YXtYtIllhsEPR+wP3+K4EZk6dDUvy2v2K4MNFDDOYKL4/yqYPXDqyozTQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -3430,6 +3528,15 @@ "node": ">=6" } }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/pure-rand": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.4.tgz", @@ -3453,6 +3560,12 @@ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, + "node_modules/regex": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/regex/-/regex-4.3.2.tgz", + "integrity": "sha512-kK/AA3A9K6q2js89+VMymcboLOlF5lZRCYJv3gzszXFHBr6kO6qLGzbm+UIugBEV8SMMKCTR59txoY6ctRHYVw==", + "dev": true + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -3555,6 +3668,17 @@ "node": ">=8" } }, + "node_modules/shiki": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.16.3.tgz", + "integrity": "sha512-GypUE+fEd06FqDs63LSAVlmq7WsahhPQU62cgZxGF+TJT5LjD2k7HTxXj4/CKOVuMM3+wWQ1t4Y5oooeJFRRBQ==", + "dev": true, + "dependencies": { + "@shikijs/core": "1.16.3", + "@shikijs/vscode-textmate": "^9.2.0", + "@types/hast": "^3.0.4" + } + }, "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", @@ -3867,6 +3991,52 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/typedoc": { + "version": "0.26.7", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.26.7.tgz", + "integrity": "sha512-gUeI/Wk99vjXXMi8kanwzyhmeFEGv1LTdTQsiyIsmSYsBebvFxhbcyAx7Zjo4cMbpLGxM4Uz3jVIjksu/I2v6Q==", + "dev": true, + "dependencies": { + "lunr": "^2.3.9", + "markdown-it": "^14.1.0", + "minimatch": "^9.0.5", + "shiki": "^1.16.2", + "yaml": "^2.5.1" + }, + "bin": { + "typedoc": "bin/typedoc" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x" + } + }, + "node_modules/typedoc/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/typedoc/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/typescript": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", @@ -3880,6 +4050,12 @@ "node": ">=14.17" } }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "dev": true + }, "node_modules/update-browserslist-db": { "version": "1.0.13", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", @@ -4023,6 +4199,18 @@ "dev": true, "peer": true }, + "node_modules/yaml": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.1.tgz", + "integrity": "sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==", + "dev": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", diff --git a/package.json b/package.json index 9fa214a..0e16738 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,8 @@ "scripts": { "build": "tsc -p tsconfig.esm.json && tsc -p tsconfig.cjs.json && tsc -p tsconfig.json", "test": "jest lib --verbose", - "test:cov": "jest lib --coverage" + "test:cov": "jest lib --coverage", + "typedoc": "typedoc" }, "author": "", "license": "AGPL-3.0-or-later", @@ -21,6 +22,7 @@ "@types/node": "^20.7.1", "ts-jest": "^29.1.1", "tweetnacl": "^1.0.3", + "typedoc": "^0.26.7", "typescript": "^5.2.2" }, "dependencies": { @@ -47,6 +49,7 @@ }, "coverageDirectory": "./coverage", "collectCoverageFrom": [ + "lib/**", "**/!(*.module|*.interface|main|repl|exception.filter|logging.interceptor).{ts,js}" ], "coveragePathIgnorePatterns": [ diff --git a/typedoc.json b/typedoc.json new file mode 100644 index 0000000..c1ab1dd --- /dev/null +++ b/typedoc.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://typedoc.org/schema.json", + "name": "Algorand Models", + "customFooterHtml": "Copyright Algorand Foundation 2024", + "hideGenerator": true, + "excludeInternal": true, + "entryPoints": ["./lib/index.ts"] +} \ No newline at end of file