diff --git a/lib/algorand.transaction.appl.ts b/lib/algorand.transaction.appl.ts new file mode 100644 index 0000000..844062a --- /dev/null +++ b/lib/algorand.transaction.appl.ts @@ -0,0 +1,330 @@ +import {AlgorandEncoder} from "./algorand.encoder.js" +import {ITransactionHeaderBuilder, TransactionHeader} from "./algorand.transaction.header"; + +/** + * Represents the schema of the state used within an application. + * + * @category Common + * @since v1.0.0 + */ +export type StateSchema = { + /** + * Maximum number of integer values that may be stored in + * the [global || local] application key/value store. + * + * Immutable. + */ + nui: number + /** + * Maximum number of byte slices values that may be stored in + * the [global || local] application key/value store. + * + * Immutable. + */ + nbs: number +} + +/** + * Includes all fields in {@link TransactionHeader} and "type" is "appl". + * + * @category Transactions + * @see {@link AlgorandTransactionCrafter} + * @see {@link ApplicationCallTxBuilder} + * @since v1.0.0 + */ +export class ApplicationCallTransaction extends TransactionHeader { + declare type: "appl" + /** + * Application ID + * + * ID of the application being configured or empty if creating. + */ + apid: bigint // Application id (required) + /** + * OnComplete + * + * Defines what additional actions occur with the transaction. + * + * An application transaction must indicate the action to be taken following the execution of its approvalProgram or clearStateProgram. + * The constants below describe the available actions. + * + * | Value | Name | Description | + * |-------|------|-------------| + * | 0 | NoOp | Only execute the ApprovalProgram associated with this application ID, with no additional effects. | + * | 1 | OptIn | Before executing the ApprovalProgram, allocate the local state for this application into the sender's account data. | + * | 2 | CloseOut | After executing the ApprovalProgram, clear any local state for this application out of the sender's account data. | + * | 3 | ClearState | Don't execute the ApprovalProgram, and instead execute the ClearStateProgram (which may not reject this transaction). Additionally, clear any local state for this application out of the sender's account data as in CloseOutOC. | + * | 4 | UpdateApplication | After executing the ApprovalProgram, replace the ApprovalProgram and ClearStateProgram associated with this application ID with the programs specified in this transaction. | + * | 5 | DeleteApplication | After executing the ApprovalProgram, delete the application parameters from the account data of the application's creator. | + */ + apan: number // #onComplete (required) + /** + * Accounts + * + * List of accounts in addition to the sender that may be accessed from the + * application's approval-program and clear-state-program. + */ + apat?: Uint8Array[] // Accounts + /** + * Approval Program + * + * Logic executed for every application transaction, except when on-completion is set to "clear". + * It can read and write global state for the application, as well as account-specific local state. + * Approval programs may reject the transaction. + */ + apap?: Uint8Array // Approval program + /** + * App Arguments + * + * Transaction-specific arguments accessed from the application's approval-program and clear-state-program. + */ + apaa?: Uint8Array[] // Application arguments + /** + * Clear State Program + * + * Logic executed for application transactions with on-completion set to "clear". + * It can read and write global state for the application, as well as account-specific local state. + * Clear state programs cannot reject the transaction. + */ + apsu?: Uint8Array // Clear state program + /** + * Foreign Apps + * + * Lists the applications in addition to the application-id whose global states may + * be accessed by this application's approval-program and clear-state-program. + * The access is read-only. + */ + apfa?: bigint[] // Foreign apps (check) + /** + * Foreign Assets + * + * Lists the assets whose AssetParams may be accessed by this application's approval-program and clear-state-program. The access is read-only. + */ + apas?: bigint[] // Foreign assets (check) + /** + * Global {@link StateSchema} + * + * Holds the maximum number of global state values defined within a {@link StateSchema} object. + */ + apgs?: StateSchema; // Global schema + /** + * Local {@link StateSchema} + * + * Holds the maximum number of local state values defined within a {@link StateSchema} object. + */ + apls?: StateSchema; // Local schema + /** + * Extra Program Pages + * + * Number of additional pages allocated to the application's approval and clear state programs. + * Each ExtraProgramPages is 2048 bytes. + * The sum of ApprovalProgram and ClearStateProgram may not exceed 2048*(1+ExtraProgramPages) bytes. + */ + apep?: number // Extra program + /** + * Boxes + * + * The boxes that should be made available for the runtime of the program. + */ + apbx?: { + i: number + n: string + }[] // Boxes + /** + * Encodes the current transaction object into a Uint8Array using the Algorand transaction encoding format. + * + * @return {Uint8Array} The encoded transaction as a Uint8Array. + */ + encode(): Uint8Array { + return new AlgorandEncoder().encodeTransaction(this) + } +} +/** + * Interface representing a builder for creating Application Call transactions. + * This builder provides methods to configure various attributes of an Application Call transaction. + * + * @category Builders + * @protected + * @since v1.0.0 + */ +export interface IApplicationCallTxBuilder extends ITransactionHeaderBuilder { + /** + * {@inheritDoc ApplicationCallTransaction#apid} + * @param {bigint} apid - The unique identifier of the application to be called. + */ + addApplicationId(apid: bigint): IApplicationCallTxBuilder; + /** + * {@inheritDoc ApplicationCallTransaction#apan} + * @param {number} apan - which action to take + */ + addOnComplete(apan: number): IApplicationCallTxBuilder; + /** + * {@inheritDoc ApplicationCallTransaction#apat} + * @param {string[]} apat - An array of account addresses to be added. + */ + addAccounts(apat: string[]): IApplicationCallTxBuilder; + /** + * {@inheritDoc ApplicationCallTransaction#apap} + * @param {Uint8Array} apap - The approval program bytes to be added to the transaction. + */ + addApprovalProgram(apap: Uint8Array): IApplicationCallTxBuilder; + /** + * {@inheritDoc ApplicationCallTransaction#apaa} + * @param {Uint8Array[]} apaa - Application arguments in bytes + */ + addApplicationArgs(apaa: Uint8Array[]): IApplicationCallTxBuilder; + /** + * {@inheritDoc ApplicationCallTransaction#apsu} + * @param {Uint8Array} apsu - The clear state program bytes to be added + */ + addClearStateProgram(apsu: Uint8Array): IApplicationCallTxBuilder; + /** + * {@inheritDoc ApplicationCallTransaction#apfa} + * @param {bigint[]} apfa - List of foreign application ids + */ + addForeignApps(apfa: bigint[]): IApplicationCallTxBuilder; + /** + * {@inheritDoc ApplicationCallTransaction#apas} + * @param {bigint[]} apas - List of foreign assets ids + */ + addForeignAssets(apas: bigint[]): IApplicationCallTxBuilder; + /** + * {@inheritDoc ApplicationCallTransaction#apgs} + * @param {StateSchema} apgs - Global state schema + */ + addGlobalSchema(apgs: StateSchema): IApplicationCallTxBuilder; + /** + * {@inheritDoc ApplicationCallTransaction#apls} + * @param {StateSchema} apls - Global state schema + */ + addLocalSchema(apls: StateSchema): IApplicationCallTxBuilder; + /** + * {@inheritDoc ApplicationCallTransaction#apep} + * @param {StateSchema} apep - Number of pages to add + */ + addExtraProgramPages(apep: number): IApplicationCallTxBuilder; + /** + * {@inheritDoc ApplicationCallTransaction#apbx} + * @param apbx - List of boxes + */ + addBoxes(apbx: { i: number; n: string }[]): IApplicationCallTxBuilder; + + /** + * Validate the model and return the instance + */ + get(): ApplicationCallTransaction; +} + +/** + * Class to build an Algorand Application Call Transaction with a fluent interface. + * This class provides methods to configure various properties of the transaction. + * + * This builder can be used to interact with a {@link ApplicationCallTransaction} + * + * + * @category Builders + * @see {@link AlgorandTransactionCrafter} + * @since v1.0.0 + */ +export class ApplicationCallTxBuilder implements IApplicationCallTxBuilder { + private readonly tx: ApplicationCallTransaction + private readonly encoder: AlgorandEncoder + + constructor(genesisId: string, genesisHash: string) { + this.encoder = new AlgorandEncoder() + + this.tx = new ApplicationCallTransaction(); + this.tx.gen = genesisId; + this.tx.gh = new Uint8Array(Buffer.from(genesisHash, "base64")); + this.tx.type = "appl"; + this.tx.fee = 1000n; + } + + addApplicationId(appId: bigint): IApplicationCallTxBuilder { + this.tx.apid = appId; + return this; + } + + addOnComplete(apan: number): IApplicationCallTxBuilder { + this.tx.apan = apan; + return this; + } + + addAccounts(apat: string[]): IApplicationCallTxBuilder { + this.tx.apat = apat.map(account => new AlgorandEncoder().decodeAddress(account)); + return this; + } + addApprovalProgram(apap: Uint8Array): IApplicationCallTxBuilder { + this.tx.apap = apap; + return this; + } + addApplicationArgs(apaa: Uint8Array[]): IApplicationCallTxBuilder { + this.tx.apaa = apaa; + return this; + } + addClearStateProgram(apsu: Uint8Array): IApplicationCallTxBuilder { + this.tx.apsu = apsu; + return this; + } + + addForeignApps(apps: bigint[]): IApplicationCallTxBuilder { + this.tx.apas = apps; + return this; + } + addForeignAssets(apfa: bigint[]): IApplicationCallTxBuilder { + this.tx.apfa = apfa; + return this; + } + addGlobalSchema(apgs: StateSchema): IApplicationCallTxBuilder { + this.tx.apgs = apgs; + return this; + } + addLocalSchema(apls: StateSchema): IApplicationCallTxBuilder { + this.tx.apls = apls; + return this; + } + + addExtraProgramPages(apep: number): IApplicationCallTxBuilder { + this.tx.apep = apep; + return this; + } + addBoxes(apbx: { i: number; n: string }[]): IApplicationCallTxBuilder { + this.tx.apbx = apbx; + return this; + } + addSender(sender: string): IApplicationCallTxBuilder { + this.tx.snd = this.encoder.decodeAddress(sender) + return this + } + addFee(fee: number | bigint): IApplicationCallTxBuilder { + this.tx.fee = AlgorandEncoder.safeCastBigInt(fee) + return this + } + addFirstValidRound(firstValid: number | bigint): IApplicationCallTxBuilder { + this.tx.fv = AlgorandEncoder.safeCastBigInt(firstValid) + return this + } + addLastValidRound(lastValid: number | bigint): IApplicationCallTxBuilder { + this.tx.lv = AlgorandEncoder.safeCastBigInt(lastValid) + return this + } + addNote(note: string, encoding: BufferEncoding = "utf8"): IApplicationCallTxBuilder { + this.tx.note = new Uint8Array(Buffer.from(note, encoding)) + return this + } + addRekey(address: string): IApplicationCallTxBuilder { + this.tx.rekey = this.encoder.decodeAddress(address) + return this + } + addLease(lease: Uint8Array): IApplicationCallTxBuilder { + this.tx.lx = lease + return this + } + addGroup(group: Uint8Array): IApplicationCallTxBuilder { + this.tx.grp = group + return this + } + get(): ApplicationCallTransaction { + return this.tx; + } +} diff --git a/lib/algorand.transaction.ts b/lib/algorand.transaction.ts index 4e851ca..7c0777a 100644 --- a/lib/algorand.transaction.ts +++ b/lib/algorand.transaction.ts @@ -3,6 +3,7 @@ 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"; +import {ApplicationCallTransaction} from "./algorand.transaction.appl"; /** * Transaction Alias @@ -11,7 +12,7 @@ import {KeyregTransaction} from "./algorand.transaction.keyreg.js"; * * @category Common */ -export type Transaction = PayTransaction | AssetConfigTransaction | AssetTransferTransaction | AssetFreezeTransaction | KeyregTransaction +export type Transaction = PayTransaction | AssetConfigTransaction | AssetTransferTransaction | AssetFreezeTransaction | KeyregTransaction | ApplicationCallTransaction // SignedTransaction export interface SignedTransaction { diff --git a/lib/e2e.spec.ts b/lib/e2e.spec.ts index 5dd59a4..74ad9f6 100644 --- a/lib/e2e.spec.ts +++ b/lib/e2e.spec.ts @@ -1,10 +1,18 @@ -import {algo, AlgorandClient, waitForConfirmation} from '@algorandfoundation/algokit-utils' -import {AlgorandTransactionCrafter, AssetConfigTransaction, AssetParamsBuilder} from "./index"; -import {Address, SuggestedParams} from "algosdk"; +import {AlgorandClient, waitForConfirmation} from '@algorandfoundation/algokit-utils' +import { + AlgorandTransactionCrafter, ApplicationCallTransaction, + ApplicationCallTxBuilder, + AssetConfigTransaction, + AssetParamsBuilder, Transaction +} from "./index"; +import algosdk, {ABIStringType, Address, SuggestedParams} from "algosdk"; import {SigningAccount, TransactionSignerAccount} from "@algorandfoundation/algokit-utils/types/account"; import {AlgoAmount} from "@algorandfoundation/algokit-utils/types/amount"; import {encode} from "hi-base32"; import {sha512_256} from "js-sha512"; +import {Arc56Contract} from "@algorandfoundation/algokit-utils/types/app-arc56"; +import {decode} from "algorand-msgpack"; +import * as msgpack from "algo-msgpack-with-bigint"; export type KeyPairRecord = { id: string @@ -61,9 +69,10 @@ export function generateChecksum(publicKey: Uint8Array){ ); } - - describe('Algorand Transaction Crafter', () => { + let genesisId: string + let genesisHash: string + let algorand: AlgorandClient let deployer: Address & TransactionSignerAccount & { account: SigningAccount; @@ -76,7 +85,7 @@ describe('Algorand Transaction Crafter', () => { beforeAll(async () => { algorand = AlgorandClient.fromEnvironment() - deployer = await algorand.account.fromEnvironment('DEPLOYER') + deployer = await algorand.account.fromEnvironment('DEPLOYER', new AlgoAmount({algos: 10000})) masterKeyPair = await generateKey() secondaryKeyPair = await generateKey() @@ -85,7 +94,9 @@ describe('Algorand Transaction Crafter', () => { await algorand.account.ensureFunded(secondaryKeyPair.id, deployer, new AlgoAmount({algos: 10})) params = await algorand.getSuggestedParams() - algorandCrafter = new AlgorandTransactionCrafter(params.genesisID as string, Buffer.from(params.genesisHash as Uint8Array).toString('base64')) + genesisId = params.genesisID as string + genesisHash = Buffer.from(params.genesisHash as Uint8Array).toString('base64') + algorandCrafter = new AlgorandTransactionCrafter(genesisId, genesisHash) }, 10000) it("(OK) Pay Transaction", async () => { @@ -107,7 +118,7 @@ describe('Algorand Transaction Crafter', () => { expect(account.status).toEqual("Offline") const onlineTxn = algorandCrafter .changeOnline( - masterKeyPair.id, + masterKeyPair.id, // Vote Key "CR3Bf/IJqzHC1TORQe83QnAkcB+JLyb+opP8f8q3ke0=", // Selection Key @@ -239,4 +250,153 @@ describe('Algorand Transaction Crafter', () => { const destroyResult = await algorand.client.algod.sendRawTransaction(destroySigned).do() await waitForConfirmation(destroyResult.txid, 20, algorand.client.algod) }) + it("(OK Application Create/Delete)", async ()=>{ + const appSpec = { + "name": "HelloWorld", + "structs": {}, + "methods": [ + { + "name": "hello", + "args": [ + { + "type": "string", + "name": "name" + } + ], + "returns": { + "type": "string" + }, + "actions": { + "create": [], + "call": [ + "NoOp" + ] + }, + "readonly": false, + "events": [], + "recommendations": {} + } + ], + "arcs": [ + 22, + 28 + ], + "networks": {}, + "state": { + "schema": { + "global": { + "ints": 0, + "bytes": 0 + }, + "local": { + "ints": 0, + "bytes": 0 + } + }, + "keys": { + "global": {}, + "local": {}, + "box": {} + }, + "maps": { + "global": {}, + "local": {}, + "box": {} + } + }, + "bareActions": { + "create": [ + "NoOp" + ], + "call": [] + }, + "sourceInfo": { + "approval": { + "sourceInfo": [ + { + "pc": [ + 25 + ], + "errorMessage": "OnCompletion is not NoOp" + }, + { + "pc": [ + 66 + ], + "errorMessage": "can only call when creating" + }, + { + "pc": [ + 28 + ], + "errorMessage": "can only call when not creating" + } + ], + "pcOffsetMethod": "none" + }, + "clear": { + "sourceInfo": [], + "pcOffsetMethod": "none" + } + }, + "source": { + "approval": "I3ByYWdtYSB2ZXJzaW9uIDEwCiNwcmFnbWEgdHlwZXRyYWNrIGZhbHNlCgovLyBhbGdvcHkuYXJjNC5BUkM0Q29udHJhY3QuYXBwcm92YWxfcHJvZ3JhbSgpIC0+IHVpbnQ2NDoKbWFpbjoKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9oZWxsb193b3JsZC9jb250cmFjdC5weTo1CiAgICAvLyBjbGFzcyBIZWxsb1dvcmxkKEFSQzRDb250cmFjdCk6CiAgICB0eG4gTnVtQXBwQXJncwogICAgYnogbWFpbl9iYXJlX3JvdXRpbmdANgogICAgcHVzaGJ5dGVzIDB4MDJiZWNlMTEgLy8gbWV0aG9kICJoZWxsbyhzdHJpbmcpc3RyaW5nIgogICAgdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMAogICAgbWF0Y2ggbWFpbl9oZWxsb19yb3V0ZUAzCgptYWluX2FmdGVyX2lmX2Vsc2VAMTA6CiAgICAvLyBzbWFydF9jb250cmFjdHMvaGVsbG9fd29ybGQvY29udHJhY3QucHk6NQogICAgLy8gY2xhc3MgSGVsbG9Xb3JsZChBUkM0Q29udHJhY3QpOgogICAgcHVzaGludCAwIC8vIDAKICAgIHJldHVybgoKbWFpbl9oZWxsb19yb3V0ZUAzOgogICAgLy8gc21hcnRfY29udHJhY3RzL2hlbGxvX3dvcmxkL2NvbnRyYWN0LnB5OjYKICAgIC8vIEBhYmltZXRob2QoKQogICAgdHhuIE9uQ29tcGxldGlvbgogICAgIQogICAgYXNzZXJ0IC8vIE9uQ29tcGxldGlvbiBpcyBub3QgTm9PcAogICAgdHhuIEFwcGxpY2F0aW9uSUQKICAgIGFzc2VydCAvLyBjYW4gb25seSBjYWxsIHdoZW4gbm90IGNyZWF0aW5nCiAgICAvLyBzbWFydF9jb250cmFjdHMvaGVsbG9fd29ybGQvY29udHJhY3QucHk6NQogICAgLy8gY2xhc3MgSGVsbG9Xb3JsZChBUkM0Q29udHJhY3QpOgogICAgdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQogICAgZXh0cmFjdCAyIDAKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9oZWxsb193b3JsZC9jb250cmFjdC5weTo2CiAgICAvLyBAYWJpbWV0aG9kKCkKICAgIGNhbGxzdWIgaGVsbG8KICAgIGR1cAogICAgbGVuCiAgICBpdG9iCiAgICBleHRyYWN0IDYgMgogICAgc3dhcAogICAgY29uY2F0CiAgICBwdXNoYnl0ZXMgMHgxNTFmN2M3NQogICAgc3dhcAogICAgY29uY2F0CiAgICBsb2cKICAgIHB1c2hpbnQgMSAvLyAxCiAgICByZXR1cm4KCm1haW5fYmFyZV9yb3V0aW5nQDY6CiAgICAvLyBzbWFydF9jb250cmFjdHMvaGVsbG9fd29ybGQvY29udHJhY3QucHk6NQogICAgLy8gY2xhc3MgSGVsbG9Xb3JsZChBUkM0Q29udHJhY3QpOgogICAgdHhuIE9uQ29tcGxldGlvbgogICAgYm56IG1haW5fYWZ0ZXJfaWZfZWxzZUAxMAogICAgdHhuIEFwcGxpY2F0aW9uSUQKICAgICEKICAgIGFzc2VydCAvLyBjYW4gb25seSBjYWxsIHdoZW4gY3JlYXRpbmcKICAgIHB1c2hpbnQgMSAvLyAxCiAgICByZXR1cm4KCgovLyBzbWFydF9jb250cmFjdHMuaGVsbG9fd29ybGQuY29udHJhY3QuSGVsbG9Xb3JsZC5oZWxsbyhuYW1lOiBieXRlcykgLT4gYnl0ZXM6CmhlbGxvOgogICAgLy8gc21hcnRfY29udHJhY3RzL2hlbGxvX3dvcmxkL2NvbnRyYWN0LnB5OjYtNwogICAgLy8gQGFiaW1ldGhvZCgpCiAgICAvLyBkZWYgaGVsbG8oc2VsZiwgbmFtZTogU3RyaW5nKSAtPiBTdHJpbmc6CiAgICBwcm90byAxIDEKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9oZWxsb193b3JsZC9jb250cmFjdC5weTo4CiAgICAvLyByZXR1cm4gIkhlbGxvLCAiICsgbmFtZQogICAgcHVzaGJ5dGVzICJIZWxsbywgIgogICAgZnJhbWVfZGlnIC0xCiAgICBjb25jYXQKICAgIHJldHN1Ygo=", + "clear": "I3ByYWdtYSB2ZXJzaW9uIDEwCiNwcmFnbWEgdHlwZXRyYWNrIGZhbHNlCgovLyBhbGdvcHkuYXJjNC5BUkM0Q29udHJhY3QuY2xlYXJfc3RhdGVfcHJvZ3JhbSgpIC0+IHVpbnQ2NDoKbWFpbjoKICAgIHB1c2hpbnQgMSAvLyAxCiAgICByZXR1cm4K" + }, + "byteCode": { + "approval": "CjEbQQA0gAQCvs4RNhoAjgEAA4EAQzEZFEQxGEQ2GgFXAgCIACBJFRZXBgJMUIAEFR98dUxQsIEBQzEZQP/UMRgURIEBQ4oBAYAHSGVsbG8sIIv/UIk=", + "clear": "CoEBQw==" + }, + "compilerInfo": { + "compiler": "puya", + "compilerVersion": { + "major": 4, + "minor": 5, + "patch": 3 + } + }, + "events": [], + "templateVariables": {} + } as Arc56Contract + + // Create Transaction Factory using Master KeyPair + const client = algorand.client.getAppFactory({ + appSpec, + defaultSender: deployer.addr, + defaultSigner: deployer.signer + }) + + const compilationResult = await client.compile() + + const applicationCallTransaction = new ApplicationCallTxBuilder(genesisId, genesisHash) + .addSender(masterKeyPair.id) + .addApprovalProgram(compilationResult.approvalProgram) + .addClearStateProgram(compilationResult.clearStateProgram) + .addFirstValidRound(params.firstValid) + .addLastValidRound(params.lastValid) + .addFee(Number(params.fee) < 1000 ? 1000 : params.fee) + .get() + + + const encodedTxn = applicationCallTransaction.encode() + const signature = await sign(encodedTxn, masterKeyPair) + const signed = algorandCrafter.addSignature(encodedTxn, signature) + const {txid} = await algorand.client.algod.sendRawTransaction(signed).do() + const {applicationIndex} = await waitForConfirmation(txid, 20, algorand.client.algod) + + const callMethodTransaction = new ApplicationCallTxBuilder(genesisId, genesisHash) + .addApplicationId(applicationIndex as bigint) + .addApplicationArgs([new Uint8Array(sha512_256.array(Buffer.from("hello(string)string")).slice(0, 4)), Buffer.from("world")]) + .addSender(masterKeyPair.id) + .addFirstValidRound(params.firstValid) + .addLastValidRound(params.lastValid) + .addFee(Number(params.fee) < 1000 ? 1000 : params.fee) + .get() + + const callMethodEncodedTxn = callMethodTransaction.encode() + const callMethodSignature = await sign(callMethodEncodedTxn, masterKeyPair) + const callMethodSigned = algorandCrafter.addSignature(callMethodEncodedTxn, callMethodSignature) + const callMethodResult = await algorand.client.algod.sendRawTransaction(callMethodSigned).do() + await waitForConfirmation(callMethodResult.txid, 20, algorand.client.algod) + }) }) diff --git a/lib/index.ts b/lib/index.ts index f93fde7..e82befd 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -9,6 +9,7 @@ export * from './algorand.transaction.crafter.js' // Transactions/Builders export * from './algorand.transaction.acfg.js' export * from './algorand.transaction.afrz.js' +export * from './algorand.transaction.appl.js' export * from './algorand.transaction.axfer.js' export * from './algorand.transaction.keyreg.js' export * from './algorand.transaction.pay.js' diff --git a/lib/schemas/appl.transaction.json b/lib/schemas/appl.transaction.json new file mode 100644 index 0000000..a3923fb --- /dev/null +++ b/lib/schemas/appl.transaction.json @@ -0,0 +1,103 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "http://algo-models.com/schemas/appl.transaction.json", + "title": "Application Call Transaction", + "type": "object", + "allOf": [ + { "$ref": "http://algo-models.com/schemas/transaction.header.json"}, + { + "properties": { + "type": { + "type": "string", + "const": "appl" + }, + "apid": { + "title": "Application ID", + "typeof": "bigint", + "description": "ID of the application being configured or empty if creating." + }, + "apan": { + "title": "OnComplete", + "type": "number", + "description": "Defines what additional actions occur with the transaction." + }, + "apat": { + "title": "Accounts", + "type": "array", + "description": "List of accounts in addition to the sender that may be accessed from the application's approval-program and clear-state-program.", + "items": { + "typeof" : "Uint8Array", + "description": "Account address in bytes" + } + }, + "apap": { + "title": "Approval Program", + "typeof" : "Uint8Array", + "description": "Logic executed for every application transaction, except when on-completion is set to \"clear\".\nIt can read and write global state for the application, as well as account-specific local state.\nApproval programs may reject the transaction." + }, + "apaa": { + "title": "App Arguments", + "type": "array", + "description": "Transaction-specific arguments accessed from the application's approval-program and clear-state-program.", + "items": { + "typeof" : "Uint8Array", + "description": "Argument in bytes" + } + }, + "apsu": { + "title": "Clear State Program", + "typeof" : "Uint8Array", + "description": "Logic executed for application transactions with on-completion set to \"clear\".\nIt can read and write global state for the application, as well as account-specific local state.\nClear state programs cannot reject the transaction." + }, + "apfa": { + "title": "Foreign Apps", + "type": "array", + "description": "Lists the applications in addition to the application-id whose global states may\nbe accessed by this application's approval-program and clear-state-program.\nThe access is read-only.", + "items": { + "typeof": "bigint", + "description": "Application id" + } + }, + "apas": { + "title": "Foreign Assets", + "type": "array", + "description": "Lists the assets whose AssetParams may be accessed by this application's approval-program and clear-state-program. The access is read-only.", + "items": { + "typeof": "bigint", + "description": "Assset id" + } + }, + "apgs": { + "title": "Global StateSchema", + "description": "Holds the maximum number of global state values defined within a StateSchema object.", + "$ref": "http://algo-models.com/schemas/state.schema.json" + }, + "apls": { + "title": "Local StateSchema", + "description": "Holds the maximum number of local state values defined within a StateSchema object." + }, + "apep": { + "title": "Extra Program Pages", + "type": "number", + "description": "Number of additional pages allocated to the application's approval and clear state programs.\nEach ExtraProgramPages is 2048 bytes.\nThe sum of ApprovalProgram and ClearStateProgram may not exceed 2048*(1+ExtraProgramPages) bytes." + }, + "apbx": { + "title": "Boxes", + "type": "array", + "description": "The boxes that should be made available for the runtime of the program.", + "items": { + "type": "object", + "properties": { + "i": { + "type": "number" + }, + "n": { + "type": "string" + } + } + } + } + }, + "required": ["type", "apid", "apan"] + }] +} \ No newline at end of file diff --git a/lib/schemas/state.schema.json b/lib/schemas/state.schema.json new file mode 100644 index 0000000..cb2d625 --- /dev/null +++ b/lib/schemas/state.schema.json @@ -0,0 +1,16 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "http://algo-models.com/schemas/state.schema.json", + "title": "State Schema", + "type": "object", + "properties": { + "nui": { + "typeof": "bigint", + "description": "Maximum number of integer values that may be stored in the [global || local] application key/value store." + }, + "nbs": { + "typeof": "bigint", + "description": "Maximum number of byte slices values that may be stored in the [global || local] application key/value store." + } + } +} \ No newline at end of file