@goplausible/openclaw-algorand-plugin 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +112 -0
  3. package/index.ts +361 -0
  4. package/lib/mcp-servers.ts +14 -0
  5. package/lib/x402-fetch.ts +213 -0
  6. package/memory/algorand-plugin.md +82 -0
  7. package/openclaw.plugin.json +30 -0
  8. package/package.json +41 -0
  9. package/setup.ts +80 -0
  10. package/skills/algorand-development/SKILL.md +90 -0
  11. package/skills/algorand-development/references/build-smart-contracts-reference.md +79 -0
  12. package/skills/algorand-development/references/build-smart-contracts.md +52 -0
  13. package/skills/algorand-development/references/create-project-reference.md +86 -0
  14. package/skills/algorand-development/references/create-project.md +89 -0
  15. package/skills/algorand-development/references/implement-arc-standards-arc32-arc56.md +396 -0
  16. package/skills/algorand-development/references/implement-arc-standards-arc4.md +265 -0
  17. package/skills/algorand-development/references/implement-arc-standards.md +92 -0
  18. package/skills/algorand-development/references/search-algorand-examples-reference.md +119 -0
  19. package/skills/algorand-development/references/search-algorand-examples.md +89 -0
  20. package/skills/algorand-development/references/troubleshoot-errors-contract.md +373 -0
  21. package/skills/algorand-development/references/troubleshoot-errors-transaction.md +599 -0
  22. package/skills/algorand-development/references/troubleshoot-errors.md +105 -0
  23. package/skills/algorand-development/references/use-algokit-cli-reference.md +228 -0
  24. package/skills/algorand-development/references/use-algokit-cli.md +64 -0
  25. package/skills/algorand-interaction/SKILL.md +223 -0
  26. package/skills/algorand-interaction/references/algorand-mcp.md +743 -0
  27. package/skills/algorand-interaction/references/examples-algorand-mcp.md +647 -0
  28. package/skills/algorand-python/SKILL.md +95 -0
  29. package/skills/algorand-python/references/build-smart-contracts-decorators.md +413 -0
  30. package/skills/algorand-python/references/build-smart-contracts-reference.md +55 -0
  31. package/skills/algorand-python/references/build-smart-contracts-storage.md +452 -0
  32. package/skills/algorand-python/references/build-smart-contracts-transactions.md +445 -0
  33. package/skills/algorand-python/references/build-smart-contracts-types.md +438 -0
  34. package/skills/algorand-python/references/build-smart-contracts.md +82 -0
  35. package/skills/algorand-python/references/create-project-reference.md +55 -0
  36. package/skills/algorand-python/references/create-project.md +75 -0
  37. package/skills/algorand-python/references/implement-arc-standards-arc32-arc56.md +101 -0
  38. package/skills/algorand-python/references/implement-arc-standards-arc4.md +154 -0
  39. package/skills/algorand-python/references/implement-arc-standards.md +39 -0
  40. package/skills/algorand-python/references/troubleshoot-errors-contract.md +355 -0
  41. package/skills/algorand-python/references/troubleshoot-errors-transaction.md +430 -0
  42. package/skills/algorand-python/references/troubleshoot-errors.md +46 -0
  43. package/skills/algorand-python/references/use-algokit-utils-reference.md +350 -0
  44. package/skills/algorand-python/references/use-algokit-utils.md +76 -0
  45. package/skills/algorand-typescript/SKILL.md +131 -0
  46. package/skills/algorand-typescript/references/algorand-ts-migration-from-beta.md +448 -0
  47. package/skills/algorand-typescript/references/algorand-ts-migration-from-tealscript.md +487 -0
  48. package/skills/algorand-typescript/references/algorand-ts-migration.md +102 -0
  49. package/skills/algorand-typescript/references/algorand-typescript-syntax-methods-and-abi.md +134 -0
  50. package/skills/algorand-typescript/references/algorand-typescript-syntax-reference.md +58 -0
  51. package/skills/algorand-typescript/references/algorand-typescript-syntax-storage.md +154 -0
  52. package/skills/algorand-typescript/references/algorand-typescript-syntax-transactions.md +187 -0
  53. package/skills/algorand-typescript/references/algorand-typescript-syntax-types-and-values.md +150 -0
  54. package/skills/algorand-typescript/references/algorand-typescript-syntax.md +84 -0
  55. package/skills/algorand-typescript/references/build-smart-contracts-reference.md +52 -0
  56. package/skills/algorand-typescript/references/build-smart-contracts.md +74 -0
  57. package/skills/algorand-typescript/references/call-smart-contracts-reference.md +237 -0
  58. package/skills/algorand-typescript/references/call-smart-contracts.md +183 -0
  59. package/skills/algorand-typescript/references/create-project-reference.md +53 -0
  60. package/skills/algorand-typescript/references/create-project.md +86 -0
  61. package/skills/algorand-typescript/references/deploy-react-frontend-examples.md +527 -0
  62. package/skills/algorand-typescript/references/deploy-react-frontend-reference.md +412 -0
  63. package/skills/algorand-typescript/references/deploy-react-frontend.md +239 -0
  64. package/skills/algorand-typescript/references/implement-arc-standards-arc32-arc56.md +73 -0
  65. package/skills/algorand-typescript/references/implement-arc-standards-arc4.md +126 -0
  66. package/skills/algorand-typescript/references/implement-arc-standards.md +44 -0
  67. package/skills/algorand-typescript/references/test-smart-contracts-examples.md +245 -0
  68. package/skills/algorand-typescript/references/test-smart-contracts-unit-tests.md +147 -0
  69. package/skills/algorand-typescript/references/test-smart-contracts.md +127 -0
  70. package/skills/algorand-typescript/references/troubleshoot-errors-contract.md +296 -0
  71. package/skills/algorand-typescript/references/troubleshoot-errors-transaction.md +438 -0
  72. package/skills/algorand-typescript/references/troubleshoot-errors.md +56 -0
  73. package/skills/algorand-typescript/references/use-algokit-utils-reference.md +342 -0
  74. package/skills/algorand-typescript/references/use-algokit-utils.md +74 -0
  75. package/skills/algorand-x402-python/SKILL.md +113 -0
  76. package/skills/algorand-x402-python/references/create-python-x402-client-examples.md +469 -0
  77. package/skills/algorand-x402-python/references/create-python-x402-client-reference.md +313 -0
  78. package/skills/algorand-x402-python/references/create-python-x402-client.md +207 -0
  79. package/skills/algorand-x402-python/references/create-python-x402-facilitator-examples.md +924 -0
  80. package/skills/algorand-x402-python/references/create-python-x402-facilitator-reference.md +629 -0
  81. package/skills/algorand-x402-python/references/create-python-x402-facilitator.md +408 -0
  82. package/skills/algorand-x402-python/references/create-python-x402-server-examples.md +703 -0
  83. package/skills/algorand-x402-python/references/create-python-x402-server-reference.md +303 -0
  84. package/skills/algorand-x402-python/references/create-python-x402-server.md +221 -0
  85. package/skills/algorand-x402-python/references/explain-algorand-x402-python-examples.md +605 -0
  86. package/skills/algorand-x402-python/references/explain-algorand-x402-python-reference.md +315 -0
  87. package/skills/algorand-x402-python/references/explain-algorand-x402-python.md +167 -0
  88. package/skills/algorand-x402-python/references/use-python-x402-core-avm-examples.md +554 -0
  89. package/skills/algorand-x402-python/references/use-python-x402-core-avm-reference.md +278 -0
  90. package/skills/algorand-x402-python/references/use-python-x402-core-avm.md +166 -0
  91. package/skills/algorand-x402-typescript/SKILL.md +129 -0
  92. package/skills/algorand-x402-typescript/references/create-typescript-x402-client-examples.md +879 -0
  93. package/skills/algorand-x402-typescript/references/create-typescript-x402-client-reference.md +371 -0
  94. package/skills/algorand-x402-typescript/references/create-typescript-x402-client.md +236 -0
  95. package/skills/algorand-x402-typescript/references/create-typescript-x402-facilitator-examples.md +875 -0
  96. package/skills/algorand-x402-typescript/references/create-typescript-x402-facilitator-reference.md +461 -0
  97. package/skills/algorand-x402-typescript/references/create-typescript-x402-facilitator.md +270 -0
  98. package/skills/algorand-x402-typescript/references/create-typescript-x402-nextjs-examples.md +1181 -0
  99. package/skills/algorand-x402-typescript/references/create-typescript-x402-nextjs-reference.md +360 -0
  100. package/skills/algorand-x402-typescript/references/create-typescript-x402-nextjs.md +251 -0
  101. package/skills/algorand-x402-typescript/references/create-typescript-x402-paywall-examples.md +870 -0
  102. package/skills/algorand-x402-typescript/references/create-typescript-x402-paywall-reference.md +323 -0
  103. package/skills/algorand-x402-typescript/references/create-typescript-x402-paywall.md +281 -0
  104. package/skills/algorand-x402-typescript/references/create-typescript-x402-server-examples.md +1135 -0
  105. package/skills/algorand-x402-typescript/references/create-typescript-x402-server-reference.md +382 -0
  106. package/skills/algorand-x402-typescript/references/create-typescript-x402-server.md +216 -0
  107. package/skills/algorand-x402-typescript/references/explain-algorand-x402-typescript-examples.md +616 -0
  108. package/skills/algorand-x402-typescript/references/explain-algorand-x402-typescript-reference.md +323 -0
  109. package/skills/algorand-x402-typescript/references/explain-algorand-x402-typescript.md +232 -0
  110. package/skills/algorand-x402-typescript/references/use-typescript-x402-core-avm-examples.md +1417 -0
  111. package/skills/algorand-x402-typescript/references/use-typescript-x402-core-avm-reference.md +504 -0
  112. package/skills/algorand-x402-typescript/references/use-typescript-x402-core-avm.md +158 -0
@@ -0,0 +1,126 @@
1
+ # ARC-4 Implementation (TypeScript)
2
+
3
+ This reference covers implementing and calling ARC-4 methods in Algorand TypeScript.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Using ARC-4 Types in Contracts](#using-arc-4-types-in-contracts)
8
+ - [Calling ARC-4 Methods from Clients](#calling-arc-4-methods-from-clients)
9
+ - [Common ARC-4 Patterns](#common-arc-4-patterns)
10
+ - [Structs](#structs)
11
+ - [Arrays](#arrays)
12
+ - [Bare Methods](#bare-methods)
13
+
14
+ ## Using ARC-4 Types in Contracts
15
+
16
+ ```typescript
17
+ import { Contract, Account, Asset, Application, Global } from '@algorandfoundation/algorand-typescript'
18
+ import { abimethod, UInt64, Bool, Str, DynamicBytes, Address } from '@algorandfoundation/algorand-typescript/arc4'
19
+ import { PaymentTxn } from '@algorandfoundation/algorand-typescript/gtxn'
20
+
21
+ class MyContract extends Contract {
22
+ @abimethod()
23
+ demoTypes(
24
+ // Primitive types
25
+ amount: UInt64,
26
+ flag: Bool,
27
+ name: Str,
28
+
29
+ // Reference types
30
+ user: Account,
31
+ token: Asset,
32
+ app: Application,
33
+
34
+ // Complex types
35
+ data: DynamicBytes,
36
+ addr: Address,
37
+ ): Str {
38
+ return new Str('Success')
39
+ }
40
+
41
+ @abimethod()
42
+ withTransaction(
43
+ payment: PaymentTxn, // Preceding payment in group
44
+ amount: UInt64,
45
+ ): void {
46
+ assert(payment.receiver === Global.currentApplicationAddress)
47
+ }
48
+ }
49
+ ```
50
+
51
+ ## Calling ARC-4 Methods from Clients
52
+
53
+ ```typescript
54
+ // Using AlgoKit Utils typed client
55
+ const result = await client.send.add({
56
+ args: { a: 10n, b: 20n }
57
+ })
58
+
59
+ // Access return value
60
+ const sum = result.return // BigInt
61
+ ```
62
+
63
+ ## Common ARC-4 Patterns
64
+
65
+ ### Structs
66
+
67
+ ```typescript
68
+ import { Contract } from '@algorandfoundation/algorand-typescript'
69
+ import { abimethod, Struct, UInt64, Bool, Str, Address } from '@algorandfoundation/algorand-typescript/arc4'
70
+
71
+ class UserInfo extends Struct<{
72
+ name: Str
73
+ balance: UInt64
74
+ active: Bool
75
+ }> {}
76
+
77
+ class MyContract extends Contract {
78
+ @abimethod()
79
+ getUser(addr: Address): UserInfo {
80
+ return new UserInfo({
81
+ name: new Str('Alice'),
82
+ balance: new UInt64(1000),
83
+ active: new Bool(true),
84
+ })
85
+ }
86
+ }
87
+ ```
88
+
89
+ ### Arrays
90
+
91
+ ```typescript
92
+ import { Contract } from '@algorandfoundation/algorand-typescript'
93
+ import { abimethod, UInt64, DynamicArray, StaticArray } from '@algorandfoundation/algorand-typescript/arc4'
94
+
95
+ class MyContract extends Contract {
96
+ @abimethod()
97
+ processList(items: DynamicArray<UInt64>): UInt64 {
98
+ let total = 0n
99
+ for (const item of items) {
100
+ total += item.native
101
+ }
102
+ return new UInt64(total)
103
+ }
104
+ }
105
+ ```
106
+
107
+ ### Bare Methods
108
+
109
+ ```typescript
110
+ import { Contract } from '@algorandfoundation/algorand-typescript'
111
+ import { baremethod } from '@algorandfoundation/algorand-typescript/arc4'
112
+
113
+ class MyContract extends Contract {
114
+ @baremethod({ create: 'require' })
115
+ create(): void {
116
+ // Called on app creation with no args
117
+ }
118
+
119
+ @baremethod({ allowActions: ['OptIn'] })
120
+ optIn(): void {
121
+ // Called on OptIn with no args
122
+ }
123
+ }
124
+ ```
125
+
126
+ Bare calls are identified by `NumAppArgs == 0`.
@@ -0,0 +1,44 @@
1
+ # Implement ARC Standards (TypeScript)
2
+
3
+ This reference covers implementing ARC standards in Algorand TypeScript smart contracts and clients. ARC-4 defines the ABI for method calls and type encoding, while ARC-56 provides the modern application specification format for typed client generation.
4
+
5
+ ## ARC-4 Contract Method Example
6
+
7
+ ```typescript
8
+ import { Contract } from '@algorandfoundation/algorand-typescript'
9
+ import { abimethod, UInt64, UInt128 } from '@algorandfoundation/algorand-typescript/arc4'
10
+
11
+ class Calculator extends Contract {
12
+ @abimethod()
13
+ add(a: UInt64, b: UInt64): UInt128 {
14
+ return new UInt128(a.native + b.native)
15
+ }
16
+ }
17
+ ```
18
+
19
+ ## Using Typed Clients with ARC-56
20
+
21
+ ```typescript
22
+ import { AlgorandClient } from '@algorandfoundation/algokit-utils'
23
+ import { CalculatorFactory } from './clients/Calculator'
24
+
25
+ const algorand = AlgorandClient.defaultLocalNet()
26
+
27
+ // Deploy new contract
28
+ const factory = algorand.client.getTypedAppFactory(CalculatorFactory)
29
+ const { appClient } = await factory.deploy({
30
+ onSchemaBreak: 'replace',
31
+ onUpdate: 'update',
32
+ })
33
+
34
+ // Call methods with full type safety
35
+ const result = await appClient.send.add({
36
+ args: { a: 10n, b: 20n }
37
+ })
38
+ console.log(result.return) // BigInt: 30n
39
+ ```
40
+
41
+ ## References
42
+
43
+ - [TypeScript ARC-4 Implementation](./implement-arc-standards-arc4.md) - ARC-4 types, contracts, and client calls
44
+ - [TypeScript ARC-32/56 Client Usage](./implement-arc-standards-arc32-arc56.md) - App specs, typed clients, and state access
@@ -0,0 +1,245 @@
1
+ # Canonical Test Examples
2
+
3
+ Real-world examples from [algorandfoundation/devportal-code-examples](https://github.com/algorandfoundation/devportal-code-examples/tree/main/projects/typescript-examples/contracts).
4
+
5
+ ## HelloWorld - Basic Contract
6
+
7
+ **Source:** [HelloWorld/contract.algo.e2e.spec.ts](https://github.com/algorandfoundation/devportal-code-examples/blob/main/projects/typescript-examples/contracts/HelloWorld/contract.algo.e2e.spec.ts)
8
+
9
+ ```typescript
10
+ import { Config } from '@algorandfoundation/algokit-utils'
11
+ import { algorandFixture } from '@algorandfoundation/algokit-utils/testing'
12
+ import { Address } from 'algosdk'
13
+ import { beforeAll, beforeEach, describe, expect, test } from 'vitest'
14
+ import { HelloWorldFactory } from '../artifacts/clients/HelloWorld/HelloWorldClient'
15
+
16
+ describe('HelloWorld contract', () => {
17
+ const localnet = algorandFixture()
18
+
19
+ beforeAll(() => {
20
+ Config.configure({ debug: true })
21
+ })
22
+ beforeEach(localnet.newScope)
23
+
24
+ const deploy = async (account: Address) => {
25
+ const factory = localnet.algorand.client.getTypedAppFactory(HelloWorldFactory, {
26
+ defaultSender: account,
27
+ })
28
+ const { appClient } = await factory.deploy({
29
+ onUpdate: 'append',
30
+ onSchemaBreak: 'append',
31
+ suppressLog: true,
32
+ })
33
+ return { client: appClient }
34
+ }
35
+
36
+ test('say hello', async () => {
37
+ const { testAccount } = localnet.context
38
+ const { client } = await deploy(testAccount)
39
+
40
+ const result = await client
41
+ .newGroup()
42
+ .sayHello({ args: { firstName: 'Silvio', lastName: 'Micali' } })
43
+ .simulate()
44
+
45
+ expect(result.returns[0]).toBe('Hello Silvio Micali')
46
+ })
47
+ })
48
+ ```
49
+
50
+ ## BoxStorage - Boxes and BoxMaps
51
+
52
+ **Source:** [BoxStorage/contract.algo.e2e.test.ts](https://github.com/algorandfoundation/devportal-code-examples/blob/main/projects/typescript-examples/contracts/BoxStorage/contract.algo.e2e.test.ts)
53
+
54
+ ```typescript
55
+ import { Config } from '@algorandfoundation/algokit-utils'
56
+ import { algorandFixture } from '@algorandfoundation/algokit-utils/testing'
57
+ import { Address, ABIUintType } from 'algosdk'
58
+ import { beforeAll, beforeEach, describe, expect, test } from 'vitest'
59
+ import { BoxStorageFactory } from '../artifacts/clients/BoxStorage/BoxStorageClient'
60
+
61
+ describe('BoxStorage contract', () => {
62
+ const localnet = algorandFixture()
63
+
64
+ beforeAll(() => {
65
+ Config.configure({ debug: true })
66
+ })
67
+ beforeEach(localnet.newScope)
68
+
69
+ const deploy = async (account: Address) => {
70
+ const factory = localnet.algorand.client.getTypedAppFactory(BoxStorageFactory, {
71
+ defaultSender: account,
72
+ })
73
+ const { appClient } = await factory.deploy({
74
+ onUpdate: 'append',
75
+ onSchemaBreak: 'append',
76
+ suppressLog: true,
77
+ })
78
+ return { client: appClient }
79
+ }
80
+
81
+ // CRITICAL: Fund app account before any box operations
82
+ const fundContract = async (sender: Address, receiver: Address) => {
83
+ await localnet.algorand.send.payment({
84
+ amount: (1).algo(),
85
+ sender,
86
+ receiver,
87
+ })
88
+ }
89
+
90
+ // Helper for BoxMap references with uint64 keys
91
+ function createBoxReference(appId: bigint, prefix: string, key: bigint) {
92
+ const uint64Type = new ABIUintType(64)
93
+ const encodedKey = uint64Type.encode(key)
94
+ const boxName = new Uint8Array([...new TextEncoder().encode(prefix), ...encodedKey])
95
+ return { appId, name: boxName }
96
+ }
97
+
98
+ test('set and read box value', async () => {
99
+ const { testAccount } = localnet.context
100
+ const { client } = await deploy(testAccount)
101
+
102
+ // Fund BEFORE box operations
103
+ await fundContract(testAccount, client.appAddress)
104
+
105
+ await client
106
+ .newGroup()
107
+ .setBox({ args: { valueInt: 42n }, boxReferences: ['boxInt'] })
108
+ .send()
109
+
110
+ const boxValue = await client.state.box.boxInt()
111
+ expect(boxValue).toBe(42n)
112
+ })
113
+
114
+ test('set and read BoxMap', async () => {
115
+ const { testAccount } = localnet.context
116
+ const { client } = await deploy(testAccount)
117
+
118
+ await fundContract(testAccount, client.appAddress)
119
+
120
+ await client
121
+ .newGroup()
122
+ .setBoxMap({
123
+ args: { key: 1n, value: 'Hello' },
124
+ boxReferences: [createBoxReference(client.appId, 'boxMap', 1n)],
125
+ })
126
+ .send()
127
+
128
+ const value = await client.getBoxMap({ args: { key: 1n } })
129
+ expect(value).toBe('Hello')
130
+ })
131
+ })
132
+ ```
133
+
134
+ ## LocalStorage - Opt-in and Local State
135
+
136
+ **Source:** [LocalStorage/contract.algo.e2e.spec.ts](https://github.com/algorandfoundation/devportal-code-examples/blob/main/projects/typescript-examples/contracts/LocalStorage/contract.algo.e2e.spec.ts)
137
+
138
+ ```typescript
139
+ import { Config } from '@algorandfoundation/algokit-utils'
140
+ import { algorandFixture } from '@algorandfoundation/algokit-utils/testing'
141
+ import { Address } from 'algosdk'
142
+ import { beforeAll, beforeEach, describe, expect, test } from 'vitest'
143
+ import { LocalStorageFactory } from '../artifacts/clients/LocalStorage/LocalStorageClient'
144
+
145
+ describe('LocalStorage contract', () => {
146
+ const localnet = algorandFixture()
147
+
148
+ beforeAll(() => {
149
+ Config.configure({ debug: true })
150
+ })
151
+ beforeEach(localnet.newScope)
152
+
153
+ const deploy = async (account: Address) => {
154
+ const factory = localnet.algorand.client.getTypedAppFactory(LocalStorageFactory, {
155
+ defaultSender: account,
156
+ })
157
+ const { appClient } = await factory.deploy({
158
+ onUpdate: 'append',
159
+ onSchemaBreak: 'append',
160
+ suppressLog: true,
161
+ })
162
+ return { client: appClient }
163
+ }
164
+
165
+ test('opt in and read local state', async () => {
166
+ const { testAccount } = localnet.context
167
+ const { client } = await deploy(testAccount)
168
+
169
+ // MUST opt in before accessing local state
170
+ await client.newGroup().optIn.optInToApplication().send()
171
+
172
+ const result = await client.newGroup().readLocalState().simulate()
173
+ expect(result.returns![0]).toBeDefined()
174
+ })
175
+
176
+ test('write and read local state', async () => {
177
+ const { testAccount } = localnet.context
178
+ const { client } = await deploy(testAccount)
179
+
180
+ await client.newGroup().optIn.optInToApplication().send()
181
+
182
+ await client
183
+ .newGroup()
184
+ .writeLocalState({
185
+ args: {
186
+ valueString: 'Hello',
187
+ valueBool: true,
188
+ valueAccount: testAccount.addr.toString(),
189
+ },
190
+ })
191
+ .send()
192
+
193
+ const result = await client.newGroup().readLocalState().simulate()
194
+ expect(result.returns![0]![3]).toBe('Hello')
195
+ })
196
+ })
197
+ ```
198
+
199
+ ## StructInBox - Struct Returns as Tuples
200
+
201
+ **Source:** [StructInBox/contract.algo.e2e.spec.ts](https://github.com/algorandfoundation/devportal-code-examples/blob/main/projects/typescript-examples/contracts/StructInBox/contract.algo.e2e.spec.ts)
202
+
203
+ ```typescript
204
+ test('create and get user struct', async () => {
205
+ const { testAccount } = localnet.context
206
+ const { client } = await deploy(testAccount)
207
+
208
+ await fundContract(testAccount, client.appAddress)
209
+
210
+ const testUser = {
211
+ id: 1n,
212
+ name: 'TestUser',
213
+ age: 25n,
214
+ }
215
+
216
+ await client.send.createNewUser({
217
+ args: { id: 1n, user: testUser },
218
+ boxReferences: [createBoxReference(client.appId, 'users', 1n)],
219
+ })
220
+
221
+ const { returns } = await client.send.getUser({
222
+ args: { id: 1n },
223
+ boxReferences: [createBoxReference(client.appId, 'users', 1n)],
224
+ })
225
+
226
+ // CRITICAL: Struct returns are tuples, access by index
227
+ const [id, name, age] = returns?.[0]?.returnValue as [bigint, string, bigint]
228
+ expect(id).toBe(testUser.id)
229
+ expect(name).toBe(testUser.name)
230
+ expect(age).toBe(testUser.age)
231
+ })
232
+ ```
233
+
234
+ ## Key Patterns Summary
235
+
236
+ | Pattern | Code |
237
+ |---------|------|
238
+ | Deploy | `const { appClient } = await factory.deploy({ onUpdate: 'append', onSchemaBreak: 'append' })` |
239
+ | Send method | `await client.send.methodName({ args: { ... } })` |
240
+ | Chain methods | `await client.newGroup().method1().method2().send()` |
241
+ | Simulate | `await client.newGroup().method().simulate()` |
242
+ | Fund app | `await localnet.algorand.send.payment({ amount: (1).algo(), sender, receiver: client.appAddress })` |
243
+ | Opt-in | `await client.newGroup().optIn.optInToApplication().send()` |
244
+ | Box reference | `boxReferences: ['boxName']` or `boxReferences: [createBoxReference(...)]` |
245
+ | Struct return | `const [field1, field2] = result.return as [Type1, Type2]` |
@@ -0,0 +1,147 @@
1
+ # Unit Testing Guide
2
+
3
+ **Only use unit tests if the user explicitly requests them.** Integration tests (E2E) are the default and recommended approach.
4
+
5
+ ## When to use unit tests
6
+
7
+ - User explicitly says "unit test" or "offline test"
8
+ - Testing pure contract logic without network interaction
9
+ - Fast iteration during contract development
10
+
11
+ ## File naming
12
+
13
+ - Unit tests: `contract.algo.spec.ts` (no `.e2e.` in the name)
14
+
15
+ ## Basic Setup
16
+
17
+ ```typescript
18
+ import { TestExecutionContext } from '@algorandfoundation/algorand-typescript-testing'
19
+ import { describe, expect, it, afterEach } from 'vitest'
20
+ import MyContract from './contract.algo'
21
+
22
+ describe('MyContract unit tests', () => {
23
+ const ctx = new TestExecutionContext()
24
+
25
+ afterEach(() => {
26
+ ctx.reset()
27
+ })
28
+
29
+ it('should call method directly', () => {
30
+ const contract = ctx.contract.create(MyContract)
31
+
32
+ // Call methods directly - no ABI encoding
33
+ const result = contract.myMethod('arg1', 42n)
34
+
35
+ expect(result).toBe('expected value')
36
+ })
37
+ })
38
+ ```
39
+
40
+ ## Key Differences from E2E Tests
41
+
42
+ | Aspect | E2E Tests | Unit Tests |
43
+ |--------|-----------|------------|
44
+ | **Framework** | `algorandFixture` | `TestExecutionContext` |
45
+ | **Network** | LocalNet | Emulated AVM |
46
+ | **Contract access** | Via typed client | Direct instance |
47
+ | **Method calls** | `client.send.method({ args: {...} })` | `contract.method(arg1, arg2)` |
48
+ | **Struct returns** | Tuples `[field1, field2]` | Object properties `result.field1` |
49
+ | **File naming** | `*.e2e.spec.ts` | `*.spec.ts` |
50
+
51
+ ## Canonical Example
52
+
53
+ **Source:** [HelloWorld/contract.algo.spec.ts](https://github.com/algorandfoundation/devportal-code-examples/blob/main/projects/typescript-examples/contracts/HelloWorld/contract.algo.spec.ts)
54
+
55
+ ```typescript
56
+ import { TestExecutionContext } from '@algorandfoundation/algorand-typescript-testing'
57
+ import { describe, expect, it } from 'vitest'
58
+ import HelloWorld from './contract.algo'
59
+
60
+ describe('HelloWorld unit tests', () => {
61
+ const ctx = new TestExecutionContext()
62
+
63
+ it('returns greeting', () => {
64
+ const contract = ctx.contract.create(HelloWorld)
65
+
66
+ const result = contract.sayHello('Sally', 'Jones')
67
+
68
+ expect(result).toBe('Hello Sally Jones')
69
+ })
70
+
71
+ it('returns bananas', () => {
72
+ const contract = ctx.contract.create(HelloWorld)
73
+
74
+ const result = contract.sayBananas()
75
+
76
+ expect(result).toBe('Bananas')
77
+ })
78
+ })
79
+ ```
80
+
81
+ ## Testing with State
82
+
83
+ ```typescript
84
+ import { TestExecutionContext } from '@algorandfoundation/algorand-typescript-testing'
85
+ import { Uint64 } from '@algorandfoundation/algorand-typescript'
86
+ import { describe, expect, it, afterEach } from 'vitest'
87
+ import CounterContract from './contract.algo'
88
+
89
+ describe('Counter unit tests', () => {
90
+ const ctx = new TestExecutionContext()
91
+
92
+ afterEach(() => {
93
+ ctx.reset()
94
+ })
95
+
96
+ it('increments counter', () => {
97
+ const contract = ctx.contract.create(CounterContract)
98
+
99
+ contract.increment()
100
+ contract.increment()
101
+
102
+ // Access state directly on contract instance
103
+ expect(contract.counter.value).toBe(Uint64(2))
104
+ })
105
+ })
106
+ ```
107
+
108
+ ## Testing with Multiple Accounts
109
+
110
+ ```typescript
111
+ it('supports multiple accounts', () => {
112
+ const contract = ctx.contract.create(MyContract)
113
+
114
+ // Create test accounts
115
+ const account1 = ctx.any.account()
116
+ const account2 = ctx.any.account()
117
+
118
+ // Change sender for subsequent calls
119
+ ctx.txn.sender = account1
120
+ contract.doSomething()
121
+
122
+ ctx.txn.sender = account2
123
+ contract.doSomethingElse()
124
+ })
125
+ ```
126
+
127
+ ## Testing Boxes
128
+
129
+ ```typescript
130
+ it('sets box value', () => {
131
+ const contract = ctx.contract.create(BoxContract)
132
+ const key = Bytes('myKey')
133
+ const value = Bytes('myValue')
134
+
135
+ contract.setBox(key, value)
136
+
137
+ // Access box via ledger context
138
+ const storedValue = ctx.ledger.getBox(contract, key)
139
+ expect(storedValue).toEqual(value)
140
+ })
141
+ ```
142
+
143
+ ## Documentation
144
+
145
+ - [TypeScript Unit Testing Guide](https://dev.algorand.co/algokit/unit-testing/typescript/overview)
146
+ - [TestExecutionContext API](https://dev.algorand.co/algokit/unit-testing/typescript/concepts)
147
+ - [State Management in Tests](https://dev.algorand.co/algokit/unit-testing/typescript/state-management)
@@ -0,0 +1,127 @@
1
+
2
+ # Testing Smart Contracts
3
+
4
+ Write integration tests for Algorand smart contracts using the `algorandFixture` and generated typed clients.
5
+
6
+ ## Default: Integration Tests (E2E)
7
+
8
+ **Always write integration tests unless the user explicitly requests unit tests.** Integration tests run against LocalNet and test real contract behavior.
9
+
10
+ **Test Framework**: Both Vitest (default) and Jest are supported. The examples below use Vitest syntax, but Jest equivalents work identically.
11
+
12
+ ### File naming
13
+
14
+ - Integration tests: `contract.algo.e2e.spec.ts`
15
+ - Unit tests (only if requested): `contract.algo.spec.ts`
16
+
17
+ ### Canonical Example
18
+
19
+ Study and adapt from: [devportal-code-examples/contracts/HelloWorld](https://github.com/algorandfoundation/devportal-code-examples/tree/main/projects/typescript-examples/contracts/HelloWorld)
20
+
21
+ ```typescript
22
+ import { Config } from '@algorandfoundation/algokit-utils'
23
+ import { algorandFixture } from '@algorandfoundation/algokit-utils/testing'
24
+ import { Address } from 'algosdk'
25
+ import { beforeAll, beforeEach, describe, expect, test } from 'vitest'
26
+ import { MyContractFactory } from '../artifacts/clients/MyContract/MyContractClient'
27
+
28
+ describe('MyContract', () => {
29
+ const localnet = algorandFixture()
30
+
31
+ beforeAll(() => {
32
+ Config.configure({ debug: true })
33
+ })
34
+ // 10-second timeout: LocalNet needs time to process transactions and confirm blocks
35
+ beforeEach(localnet.newScope, 10_000)
36
+
37
+ const deploy = async (account: Address) => {
38
+ const factory = localnet.algorand.client.getTypedAppFactory(MyContractFactory, {
39
+ defaultSender: account,
40
+ })
41
+ const { appClient } = await factory.deploy({
42
+ onUpdate: 'append',
43
+ onSchemaBreak: 'append',
44
+ suppressLog: true,
45
+ })
46
+ return { client: appClient }
47
+ }
48
+
49
+ test('should call method and verify result', async () => {
50
+ const { testAccount } = localnet.context
51
+ const { client } = await deploy(testAccount)
52
+
53
+ const result = await client.send.myMethod({ args: { value: 42n } })
54
+ expect(result.return).toBe(42n)
55
+ })
56
+ })
57
+ ```
58
+
59
+ ## How to proceed
60
+
61
+ 1. **Locate the generated client** in `artifacts/clients/<ContractName>/<ContractName>Client.ts`
62
+ 2. **Import the Factory** (e.g., `MyContractFactory`) - NOT the Client directly
63
+ 3. **Use the deploy helper pattern** shown above
64
+ 4. **Call methods via `client.send.methodName()`** or `client.newGroup().methodName().send()`
65
+
66
+ ## Critical Rules
67
+
68
+ | Rule | Details |
69
+ |------|---------|
70
+ | **Use newGroup() for chaining** | `client.newGroup().method1().method2().send()` |
71
+ | **Struct returns are tuples** | `const [id, name] = result.return as [bigint, string]` |
72
+ | **Fund app for BoxMap** | Send payment to `client.appAddress` before box operations |
73
+ | **Opt-in before local state** | `await client.newGroup().optIn.optInToApplication().send()` |
74
+
75
+ ## Common Patterns
76
+
77
+ ### Fund contract for box storage
78
+
79
+ ```typescript
80
+ await localnet.algorand.send.payment({
81
+ amount: (1).algo(),
82
+ sender: testAccount,
83
+ receiver: client.appAddress,
84
+ })
85
+ ```
86
+
87
+ ### Multiple users on same contract
88
+
89
+ ```typescript
90
+ // Create and fund second user
91
+ const user2 = localnet.algorand.account.random()
92
+ await localnet.algorand.send.payment({
93
+ amount: (5).algo(),
94
+ sender: testAccount,
95
+ receiver: user2.addr,
96
+ })
97
+
98
+ // Get client for same app with different sender
99
+ const client2 = factory.getAppClientById({
100
+ appId: client.appId,
101
+ defaultSender: user2.addr,
102
+ })
103
+ ```
104
+
105
+ ### Box references
106
+
107
+ ```typescript
108
+ import { ABIUintType } from 'algosdk'
109
+
110
+ function createBoxReference(appId: bigint, prefix: string, key: bigint) {
111
+ const uint64Type = new ABIUintType(64)
112
+ const encodedKey = uint64Type.encode(key)
113
+ const boxName = new Uint8Array([...new TextEncoder().encode(prefix), ...encodedKey])
114
+ return { appId, name: boxName }
115
+ }
116
+
117
+ await client.send.setBoxMap({
118
+ args: { key: 1n, value: 'hello' },
119
+ boxReferences: [createBoxReference(client.appId, 'boxMap', 1n)],
120
+ })
121
+ ```
122
+
123
+ ## References
124
+
125
+ - [Canonical Examples](./test-smart-contracts-examples.md) - Complete patterns from algorandfoundation repos
126
+ - [Unit Testing Guide](./test-smart-contracts-unit-tests.md) - Only use if user requests unit tests
127
+ - [devportal-code-examples](https://github.com/algorandfoundation/devportal-code-examples/tree/main/projects/typescript-examples/contracts)