@algorandfoundation/algorand-typescript-testing 1.0.0-beta.3 → 1.0.0-beta.30

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 (104) hide show
  1. package/README.md +285 -0
  2. package/abi-metadata-Dqh8iYjB.js +117 -0
  3. package/abi-metadata-Dqh8iYjB.js.map +1 -0
  4. package/abi-metadata.d.ts +8 -8
  5. package/arc4-DMlP46RF.js +40 -0
  6. package/arc4-DMlP46RF.js.map +1 -0
  7. package/asset-params-CZmGYLQv.js +845 -0
  8. package/asset-params-CZmGYLQv.js.map +1 -0
  9. package/collections/custom-key-map.d.ts +5 -4
  10. package/context-helpers/context-manager.d.ts +7 -0
  11. package/context-helpers/context-util.d.ts +2 -2
  12. package/context-helpers/internal-context.d.ts +9 -9
  13. package/{runtime-helpers-DcRmHWMr.js → crypto-BMTigz9x.js} +968 -839
  14. package/crypto-BMTigz9x.js.map +1 -0
  15. package/decode-logs.d.ts +1 -1
  16. package/encoders.d.ts +4 -3
  17. package/errors.d.ts +27 -1
  18. package/impl/acct-params.d.ts +7 -6
  19. package/impl/app-global.d.ts +2 -2
  20. package/impl/app-local.d.ts +2 -2
  21. package/impl/app-params.d.ts +4 -3
  22. package/impl/asset-holding.d.ts +2 -2
  23. package/impl/asset-params.d.ts +4 -3
  24. package/impl/base-32.d.ts +2 -0
  25. package/impl/base-contract.d.ts +9 -0
  26. package/impl/base.d.ts +4 -3
  27. package/impl/block.d.ts +4 -4
  28. package/impl/box.d.ts +2 -2
  29. package/impl/compiled.d.ts +2 -2
  30. package/impl/contract.d.ts +14 -0
  31. package/impl/crypto.d.ts +22 -12
  32. package/impl/encoded-types.d.ts +30 -22
  33. package/impl/ensure-budget.d.ts +2 -1
  34. package/impl/global.d.ts +3 -3
  35. package/impl/gtxn.d.ts +9 -2
  36. package/impl/index.d.ts +1 -0
  37. package/impl/inner-transactions.d.ts +3 -2
  38. package/impl/itxn.d.ts +4 -4
  39. package/impl/log.d.ts +3 -0
  40. package/impl/logicSigArg.d.ts +3 -2
  41. package/impl/match.d.ts +1 -1
  42. package/impl/method-selector.d.ts +3 -0
  43. package/impl/mutable-array.d.ts +42 -0
  44. package/impl/online-stake.d.ts +2 -2
  45. package/impl/primitives.d.ts +212 -0
  46. package/impl/pure.d.ts +37 -30
  47. package/impl/reference.d.ts +96 -0
  48. package/impl/scratch.d.ts +4 -4
  49. package/impl/state.d.ts +22 -25
  50. package/impl/transactions.d.ts +41 -38
  51. package/impl/txn.d.ts +4 -3
  52. package/impl/urange.d.ts +2 -2
  53. package/impl/voter-params.d.ts +2 -2
  54. package/index.d.ts +3 -14
  55. package/index.mjs +880 -3636
  56. package/index.mjs.map +1 -1
  57. package/inner-transactions-Bz3Txrff.js +867 -0
  58. package/inner-transactions-Bz3Txrff.js.map +1 -0
  59. package/internal/arc4.d.ts +3 -0
  60. package/internal/arc4.mjs +15 -0
  61. package/internal/arc4.mjs.map +1 -0
  62. package/internal/index.d.ts +37 -0
  63. package/internal/index.mjs +250 -0
  64. package/internal/index.mjs.map +1 -0
  65. package/internal/op.d.ts +19 -0
  66. package/internal/op.mjs +16 -0
  67. package/internal/op.mjs.map +1 -0
  68. package/op-yjWBeorl.js +1812 -0
  69. package/op-yjWBeorl.js.map +1 -0
  70. package/package.json +24 -10
  71. package/{test-transformer/index.mjs → program-factory-CrdkPpT0.js} +71 -50
  72. package/program-factory-CrdkPpT0.js.map +1 -0
  73. package/runtime-helpers-DHXdMtMR.js +351 -0
  74. package/runtime-helpers-DHXdMtMR.js.map +1 -0
  75. package/runtime-helpers.d.ts +2 -7
  76. package/runtime-helpers.mjs +7 -4
  77. package/runtime-helpers.mjs.map +1 -1
  78. package/set-up.d.ts +21 -1
  79. package/subcontexts/contract-context.d.ts +17 -5
  80. package/subcontexts/ledger-context.d.ts +141 -23
  81. package/subcontexts/transaction-context.d.ts +177 -31
  82. package/test-execution-context.d.ts +110 -7
  83. package/test-transformer/jest-transformer.d.ts +37 -0
  84. package/test-transformer/jest-transformer.mjs +52 -0
  85. package/test-transformer/jest-transformer.mjs.map +1 -0
  86. package/test-transformer/node-factory.d.ts +3 -2
  87. package/test-transformer/program-factory.d.ts +7 -0
  88. package/test-transformer/visitors.d.ts +1 -1
  89. package/test-transformer/vitest-transformer.d.ts +34 -0
  90. package/test-transformer/vitest-transformer.mjs +56 -0
  91. package/test-transformer/vitest-transformer.mjs.map +1 -0
  92. package/typescript-helpers-CAukFXpp.js +18 -0
  93. package/typescript-helpers-CAukFXpp.js.map +1 -0
  94. package/typescript-helpers.d.ts +4 -0
  95. package/util.d.ts +50 -20
  96. package/value-generators/arc4.d.ts +15 -15
  97. package/value-generators/avm.d.ts +52 -13
  98. package/value-generators/txn.d.ts +37 -3
  99. package/impl/account.d.ts +0 -35
  100. package/impl/application.d.ts +0 -30
  101. package/impl/asset.d.ts +0 -24
  102. package/runtime-helpers-DcRmHWMr.js.map +0 -1
  103. package/test-transformer/index.d.ts +0 -6
  104. package/test-transformer/index.mjs.map +0 -1
package/README.md ADDED
@@ -0,0 +1,285 @@
1
+ # Algorand TypeScript Testing
2
+
3
+ [![docs-repository](https://img.shields.io/badge/url-repository-74dfdc?logo=github&style=flat.svg)](https://github.com/algorandfoundation/algorand-typescript-testing/)
4
+ [![learn-AlgoKit](https://img.shields.io/badge/learn-AlgoKit-74dfdc?logo=algorand&mac=flat.svg)](https://developer.algorand.org/algokit/)
5
+ [![github-stars](https://img.shields.io/github/stars/algorandfoundation/algorand-typescript-testing?color=74dfdc&logo=star&style=flat)](https://github.com/algorandfoundation/algorand-typescript-testing)
6
+ [![visitor-badge](https://api.visitorbadge.io/api/visitors?path=https%3A%2F%2Fgithub.com%2Falgorandfoundation%2Falgorand-typescript-testing&countColor=%2374dfdc&style=flat)](https://github.com/algorandfoundation/algorand-typescript-testing/)
7
+
8
+ `algorand-typescript-testing` is a companion package to [Algorand Typescript](https://github.com/algorandfoundation/puya-ts/tree/main/packages/algo-ts) that enables efficient unit testing of Algorand TypeScript smart contracts in an offline environment. This package emulates key AVM behaviors without requiring a network connection, offering fast and reliable testing capabilities with a familiar TypeScript interface.
9
+
10
+ The `algorand-typescript-testing` package provides:
11
+
12
+ - A simple interface for fast and reliable unit testing
13
+ - An offline testing environment that simulates core AVM functionality
14
+ - A familiar TypeScript experience, compatible with testing frameworks like [vitest](https://vitest.dev/), and [jest](https://jestjs.io/)
15
+
16
+ ## Quick Start
17
+
18
+ `algorand-typescript` is a prerequisite for `algorand-typescript-testing`, providing stubs and type annotations for Algorand TypeScript syntax. It enhances code completion and type checking when writing smart contracts. Note that this code isn't directly executable in standard Node.js environment; it's compiled by `puya-ts` into TEAL for Algorand Network deployment.
19
+
20
+ Traditionally, testing Algorand smart contracts involved deployment on sandboxed networks and interacting with live instances. While robust, this approach can be inefficient and lacks versatility for testing Algorand TypeScript code.
21
+
22
+ Enter `algorand-typescript-testing`: it leverages TypeScript's rich testing ecosystem for unit testing without network deployment. This enables rapid iteration and granular logic testing.
23
+
24
+ > **NOTE**: While `algorand-typescript-testing` offers valuable unit testing capabilities, it's not a replacement for comprehensive testing. Use it alongside other test types, particularly those running against the actual Algorand Network, for thorough contract validation.
25
+
26
+ ### Prerequisites
27
+
28
+ - Python 3.12 or later
29
+ - [Algorand Python](https://github.com/algorandfoundation/puya)
30
+ - Node.js 20.x or later
31
+ - [Algorand TypeScript](https://github.com/algorandfoundation/puya-ts)
32
+
33
+ ### Installation
34
+
35
+ `algorand-typescript-testing` is distributed via [npm](https://www.npmjs.com/package/@algorandfoundation/algorand-typescript-testing/). Install the package using `npm`:
36
+
37
+ ```bash
38
+ npm i @algorandfoundation/algorand-typescript-testing
39
+ ```
40
+
41
+ ### Testing your first contract
42
+
43
+ Let's write a simple contract and test it using the `algorand-typescript-testing` framework.
44
+
45
+ #### Configuring vitest
46
+
47
+ If you are using [vitest](https://vitest.dev/) with [@rollup/plugin-typescript](https://www.npmjs.com/package/@rollup/plugin-typescript) plugin, configure `puyaTsTransformer` as a `before` stage transformer of the `typescript` plugin in `vitest.config.mts` file.
48
+
49
+ ```typescript
50
+ import typescript from '@rollup/plugin-typescript'
51
+ import { defineConfig } from 'vitest/config'
52
+ import { puyaTsTransformer } from '@algorandfoundation/algorand-typescript-testing/vitest-transformer'
53
+
54
+ export default defineConfig({
55
+ esbuild: {},
56
+ test: {
57
+ setupFiles: 'vitest.setup.ts',
58
+ },
59
+ plugins: [
60
+ typescript({
61
+ transformers: {
62
+ before: [puyaTsTransformer],
63
+ },
64
+ }),
65
+ ],
66
+ })
67
+ ```
68
+
69
+ `algorand-typescript-testing` package also exposes additional equality testers which enables the smart contract developers to write terser test by avoiding type casting in assertions. It can setup in `beforeAll` hook point in the setup file, `vitest.setup.ts`.
70
+
71
+ ```typescript
72
+ import { beforeAll, expect } from 'vitest'
73
+ import { addEqualityTesters } from '@algorandfoundation/algorand-typescript-testing'
74
+
75
+ beforeAll(() => {
76
+ addEqualityTesters({ expect })
77
+ })
78
+ ```
79
+
80
+ #### Configuring jest
81
+
82
+ If you are using [jest](https://jestjs.io/) with [ts-jest](https://www.npmjs.com/package/ts-jest), [@jest/globals](https://www.npmjs.com/package/@jest/globals) and [ts-node](https://www.npmjs.com/package/ts-node) plugins, configure `puyaTsTransformer` as a `before` stage transformer of the `typescript` plugin in `jest.config.ts` file.
83
+
84
+ ```typescript
85
+ import { createDefaultEsmPreset, type JestConfigWithTsJest } from 'ts-jest'
86
+
87
+ const presetConfig = createDefaultEsmPreset({})
88
+ const jestConfig: JestConfigWithTsJest = {
89
+ ...presetConfig,
90
+ testMatch: ['**/*.test.ts'],
91
+ setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
92
+ transform: {
93
+ '^.+\\.tsx?$': [
94
+ 'ts-jest',
95
+ {
96
+ useESM: true,
97
+ astTransformers: {
98
+ before: ['node_modules/@algorandfoundation/algorand-typescript-testing/test-transformer/jest-transformer.mjs'],
99
+ },
100
+ },
101
+ ],
102
+ },
103
+ extensionsToTreatAsEsm: ['.ts'],
104
+ }
105
+ export default jestConfig
106
+ ```
107
+
108
+ `algorand-typescript-testing` package also exposes additional equality testers which enables the smart contract developers to write terser test by avoiding type casting in assertions. It can setup in `beforeAll` hook point in the setup file, `jest.setup.ts`.
109
+
110
+ ```typescript
111
+ import { beforeAll, expect } from '@jest/globals'
112
+ import { addEqualityTesters } from '@algorandfoundation/algorand-typescript-testing'
113
+
114
+ beforeAll(() => {
115
+ addEqualityTesters({ expect })
116
+ })
117
+ ```
118
+
119
+ You'll also need to run `jest` with the `--experimental-vm-modules` and `--experimental-require-module` flags in the `package.json`. This requires node 20.17 or greater.
120
+
121
+ ```json
122
+ {
123
+ "name": "puya-ts-demo",
124
+ "scripts": {
125
+ "test:jest": "tsc && node --experimental-vm-modules --experimental-require-module node_modules/jest/bin/jest"
126
+ },
127
+ "engines": {
128
+ "node": ">=20.17"
129
+ }
130
+ }
131
+ ```
132
+
133
+ There is also a patch file `ts-jest+29.2.5.patch` that needs to be applied to `ts-jest` package to for the `puyaTsTransformer` to work with the test files.
134
+
135
+ 1. Place the file in `<rootDir>\patches` folder.
136
+ 1. Install [patch-package](https://www.npmjs.com/package/patch-package) package as a dev dependency.
137
+ 1. Add `"postinstall": "patch-package",` script in `package.json` file.
138
+ The patch will then be applied with every `npm install` call.
139
+
140
+ ```patch
141
+ diff --git a/node_modules/ts-jest/dist/legacy/compiler/ts-compiler.js b/node_modules/ts-jest/dist/legacy/compiler/ts-compiler.js
142
+ index 5198f8f..addb47c 100644
143
+ --- a/node_modules/ts-jest/dist/legacy/compiler/ts-compiler.js
144
+ +++ b/node_modules/ts-jest/dist/legacy/compiler/ts-compiler.js
145
+ @@ -234,7 +234,7 @@ var TsCompiler = /** @class */ (function () {
146
+ var _a;
147
+ // Initialize memory cache for typescript compiler
148
+ this._parsedTsConfig.fileNames
149
+ - .filter(function (fileName) { return constants_1.TS_TSX_REGEX.test(fileName) && !_this.configSet.isTestFile(fileName); })
150
+ + .filter(function (fileName) { return constants_1.TS_TSX_REGEX.test(fileName); })
151
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
152
+ .forEach(function (fileName) { return _this._fileVersionCache.set(fileName, 0); });
153
+ /* istanbul ignore next */
154
+
155
+ ```
156
+
157
+ After the setup, the examples provided using `vitest` can be converted to work with `jest` by simply swapping the `import {...} from 'vitest'` with `import {...} from '@jest/globals'`.
158
+
159
+ #### Contract Definition
160
+
161
+ ```typescript
162
+ import { arc4, assert, Bytes, GlobalState, gtxn, LocalState, op, Txn, uint64, Uint64 } from '@algorandfoundation/algorand-typescript'
163
+
164
+ export default class VotingContract extends arc4.Contract {
165
+ topic = GlobalState({ initialValue: 'default_topic', key: Bytes('topic') })
166
+ votes = GlobalState({ initialValue: Uint64(0), key: Bytes('votes') })
167
+ voted = LocalState<uint64>({ key: Bytes('voted') })
168
+
169
+ @arc4.abimethod()
170
+ public setTopic(topic: string): void {
171
+ this.topic.value = topic
172
+ }
173
+ @arc4.abimethod()
174
+ public vote(pay: gtxn.PaymentTxn): boolean {
175
+ assert(op.Global.groupSize === 2, 'Expected 2 transactions')
176
+ assert(pay.amount === 10_000, 'Incorrect payment amount')
177
+ assert(pay.sender === Txn.sender, 'Payment sender must match transaction sender')
178
+
179
+ if (this.voted(Txn.sender).hasValue) {
180
+ return false // Already voted
181
+ }
182
+
183
+ this.votes.value = this.votes.value + 1
184
+ this.voted(Txn.sender).value = 1
185
+ return true
186
+ }
187
+
188
+ @arc4.abimethod({ readonly: true })
189
+ public getVotes(): uint64 {
190
+ return this.votes.value
191
+ }
192
+
193
+ public clearStateProgram(): boolean {
194
+ return true
195
+ }
196
+ }
197
+ ```
198
+
199
+ #### Test Definition
200
+
201
+ ```typescript
202
+ import { Uint64 } from '@algorandfoundation/algorand-typescript'
203
+ import { TestExecutionContext } from '@algorandfoundation/algorand-typescript-testing'
204
+ import { afterEach, describe, expect, test } from 'vitest'
205
+ import VotingContract from './contract.algo'
206
+
207
+ describe('Voting contract', () => {
208
+ const ctx = new TestExecutionContext()
209
+ afterEach(() => {
210
+ ctx.reset()
211
+ })
212
+
213
+ test('vote function', () => {
214
+ // Initialize the contract within the testing context
215
+ const contract = ctx.contract.create(VotingContract)
216
+
217
+ const voter = ctx.defaultSender
218
+ const payment = ctx.any.txn.payment({
219
+ sender: voter,
220
+ amount: 10_000,
221
+ })
222
+
223
+ const result = contract.vote(payment)
224
+ expect(result).toEqual(true)
225
+ expect(contract.votes.value).toEqual(1)
226
+ expect(contract.voted(voter).value).toEqual(1)
227
+ })
228
+
229
+ test('setTopic function', () => {
230
+ // Initialize the contract within the testing context
231
+ const contract = ctx.contract.create(VotingContract)
232
+
233
+ const newTopic = ctx.any.string(10)
234
+ contract.setTopic(newTopic)
235
+ expect(contract.topic.value).toEqual(newTopic)
236
+ })
237
+
238
+ test('getVotes function', () => {
239
+ // Initialize the contract within the testing context
240
+ const contract = ctx.contract.create(VotingContract)
241
+
242
+ contract.votes.value = 5
243
+ const votes = contract.getVotes()
244
+ expect(votes).toEqual(5)
245
+ })
246
+ })
247
+ ```
248
+
249
+ This example demonstrates key aspects of testing with `algorand-typescript-testing` for ARC4-based contracts:
250
+
251
+ 1. ARC4 Contract Features:
252
+
253
+ - Use of `arc4.Contract` as the base class for the contract.
254
+ - ABI methods defined using the `@arc4.abimethod` decorator.
255
+ - Readonly method annotation with `@arc4.abimethod({readonly: true})`.
256
+
257
+ 2. Testing ARC4 Contracts:
258
+
259
+ - Creation of an `arc4.Contract` instance within the test context.
260
+ - Use of `ctx.any` for generating random test data.
261
+ - Direct invocation of ABI methods on the contract instance.
262
+
263
+ 3. Transaction Handling:
264
+
265
+ - Use of `ctx.any.txn` to create test transactions.
266
+ - Passing transaction objects as parameters to contract methods.
267
+
268
+ 4. State Verification:
269
+ - Checking global and local state changes after method execution.
270
+ - Verifying return values from ABI methods.
271
+
272
+ > **NOTE**: Thorough testing is crucial in smart contract development due to their immutable nature post-deployment. Comprehensive unit and integration tests ensure contract validity and reliability. Optimizing for efficiency can significantly improve user experience by reducing transaction fees and simplifying interactions. Investing in robust testing and optimization practices is crucial and offers many benefits in the long run.
273
+
274
+ ### Next steps
275
+
276
+ To dig deeper into the capabilities of `algorand-typescript-testing`, continue with the following sections.
277
+
278
+ #### Contents
279
+
280
+ - [Testing Guide](./docs/testing-guide/index.md)
281
+ - [Examples](./docs/examples.md)
282
+ - [Coverage](./docs/coverage.md)
283
+ - [FQA](./docs/faq.md)
284
+ - [API Reference](./docs/api.md)
285
+ - [Algorand TypeScript](./docs/algots.md)
@@ -0,0 +1,117 @@
1
+ import js_sha512 from 'js-sha512';
2
+ import { d as BaseContract, al as getArc4TypeName$1 } from './crypto-BMTigz9x.js';
3
+
4
+ class Contract extends BaseContract {
5
+ static isArc4 = true;
6
+ approvalProgram() {
7
+ return true;
8
+ }
9
+ }
10
+ const Arc4MethodConfigSymbol = Symbol('Arc4MethodConfig');
11
+ function abimethod(config) {
12
+ return function (target) {
13
+ target[Arc4MethodConfigSymbol] = {
14
+ ...config,
15
+ onCreate: config?.onCreate ?? 'disallow',
16
+ allowActions: [].concat(config?.allowActions ?? 'NoOp'),
17
+ };
18
+ return target;
19
+ };
20
+ }
21
+ function baremethod(config) {
22
+ return function (target) {
23
+ target[Arc4MethodConfigSymbol] = {
24
+ ...config,
25
+ onCreate: config?.onCreate ?? 'disallow',
26
+ allowActions: [].concat(config?.allowActions ?? 'NoOp'),
27
+ };
28
+ return target;
29
+ };
30
+ }
31
+
32
+ const metadataStore = new WeakMap();
33
+ const attachAbiMetadata = (contract, methodName, metadata) => {
34
+ if (!metadataStore.has(contract)) {
35
+ metadataStore.set(contract, {});
36
+ }
37
+ const metadatas = metadataStore.get(contract);
38
+ metadatas[methodName] = metadata;
39
+ };
40
+ const getContractAbiMetadata = (contract) => {
41
+ // Initialize result object to store merged metadata
42
+ const result = {};
43
+ // Get the contract's class
44
+ let currentClass = contract instanceof Contract ? contract.constructor : contract;
45
+ // Walk up the prototype chain
46
+ while (currentClass && currentClass.prototype) {
47
+ // Find metadata for current class
48
+ const currentMetadata = metadataStore.get(currentClass);
49
+ if (currentMetadata) {
50
+ // Merge metadata with existing result (don't override existing entries)
51
+ const classMetadata = currentMetadata;
52
+ for (const [methodName, metadata] of Object.entries(classMetadata)) {
53
+ if (!(methodName in result)) {
54
+ result[methodName] = {
55
+ ...metadata,
56
+ ...currentClass.prototype?.[methodName]?.[Arc4MethodConfigSymbol],
57
+ };
58
+ }
59
+ }
60
+ }
61
+ // Move up the prototype chain
62
+ currentClass = Object.getPrototypeOf(currentClass);
63
+ }
64
+ return result;
65
+ };
66
+ const getContractMethodAbiMetadata = (contract, methodName) => {
67
+ const metadatas = getContractAbiMetadata(contract);
68
+ return metadatas[methodName];
69
+ };
70
+ const getArc4Signature = (metadata) => {
71
+ if (metadata.methodSignature === undefined) {
72
+ const argTypes = metadata.argTypes.map((t) => JSON.parse(t)).map(getArc4TypeName);
73
+ const returnType = getArc4TypeName(JSON.parse(metadata.returnType));
74
+ metadata.methodSignature = `${metadata.name ?? metadata.methodName}(${argTypes.join(',')})${returnType}`;
75
+ }
76
+ return metadata.methodSignature;
77
+ };
78
+ const getArc4Selector = (metadata) => {
79
+ const hash = js_sha512.sha512_256.array(getArc4Signature(metadata));
80
+ return new Uint8Array(hash.slice(0, 4));
81
+ };
82
+ const getArc4TypeName = (t) => {
83
+ const map = {
84
+ void: 'void',
85
+ account: 'account',
86
+ application: 'application',
87
+ asset: 'asset',
88
+ boolean: 'bool',
89
+ biguint: 'uint512',
90
+ bytes: 'byte[]',
91
+ string: 'string',
92
+ uint64: 'uint64',
93
+ OnCompleteAction: 'uint64',
94
+ TransactionType: 'uint64',
95
+ Transaction: 'txn',
96
+ PaymentTxn: 'pay',
97
+ KeyRegistrationTxn: 'keyreg',
98
+ AssetConfigTxn: 'acfg',
99
+ AssetTransferTxn: 'axfer',
100
+ AssetFreezeTxn: 'afrz',
101
+ ApplicationTxn: 'appl',
102
+ 'Tuple(<.*>)?': (t) => `(${Object.values(t.genericArgs)
103
+ .map(getArc4TypeName)
104
+ .join(',')})`,
105
+ };
106
+ const entry = Object.entries(map).find(([k, _]) => new RegExp(`^${k}$`, 'i').test(t.name))?.[1];
107
+ if (entry === undefined) {
108
+ return getArc4TypeName$1(t) ?? t.name;
109
+ }
110
+ if (entry instanceof Function) {
111
+ return entry(t);
112
+ }
113
+ return entry;
114
+ };
115
+
116
+ export { Contract as C, getContractMethodAbiMetadata as a, getContractAbiMetadata as b, abimethod as c, baremethod as d, attachAbiMetadata as e, getArc4Selector as g };
117
+ //# sourceMappingURL=abi-metadata-Dqh8iYjB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"abi-metadata-Dqh8iYjB.js","sources":["../src/impl/contract.ts","../src/abi-metadata.ts"],"sourcesContent":["import type { arc4, OnCompleteActionStr } from '@algorandfoundation/algorand-typescript'\nimport type { DeliberateAny } from '../typescript-helpers'\nimport { BaseContract } from './base-contract'\n\nexport class Contract extends BaseContract {\n static isArc4 = true\n\n override approvalProgram(): boolean {\n return true\n }\n}\n\nexport const Arc4MethodConfigSymbol = Symbol('Arc4MethodConfig')\nexport function abimethod<TContract extends Contract>(config?: arc4.AbiMethodConfig<TContract>) {\n return function <TArgs extends DeliberateAny[], TReturn>(\n target: { [Arc4MethodConfigSymbol]: arc4.AbiMethodConfig<TContract> } & ((this: TContract, ...args: TArgs) => TReturn),\n ): (this: TContract, ...args: TArgs) => TReturn {\n target[Arc4MethodConfigSymbol] = {\n ...config,\n onCreate: config?.onCreate ?? 'disallow',\n allowActions: ([] as OnCompleteActionStr[]).concat(config?.allowActions ?? 'NoOp'),\n }\n return target\n }\n}\n\nexport function baremethod<TContract extends Contract>(config?: arc4.BareMethodConfig) {\n return function <TArgs extends DeliberateAny[], TReturn>(\n target: { [Arc4MethodConfigSymbol]: arc4.AbiMethodConfig<TContract> } & ((this: TContract, ...args: TArgs) => TReturn),\n ): (this: TContract, ...args: TArgs) => TReturn {\n target[Arc4MethodConfigSymbol] = {\n ...config,\n onCreate: config?.onCreate ?? 'disallow',\n allowActions: ([] as OnCompleteActionStr[]).concat(config?.allowActions ?? 'NoOp'),\n }\n return target\n }\n}\n","import type { OnCompleteActionStr } from '@algorandfoundation/algorand-typescript'\nimport type { CreateOptions } from '@algorandfoundation/algorand-typescript/arc4'\nimport js_sha512 from 'js-sha512'\nimport type { TypeInfo } from './encoders'\nimport { Arc4MethodConfigSymbol, Contract } from './impl/contract'\nimport { getArc4TypeName as getArc4TypeNameForARC4Encoded } from './impl/encoded-types'\nimport type { DeliberateAny } from './typescript-helpers'\n\nexport interface AbiMetadata {\n methodName: string\n name?: string\n methodSignature: string | undefined\n argTypes: string[]\n returnType: string\n onCreate?: CreateOptions\n allowActions?: OnCompleteActionStr[]\n}\n\nconst metadataStore: WeakMap<{ new (): Contract }, Record<string, AbiMetadata>> = new WeakMap()\nexport const attachAbiMetadata = (contract: { new (): Contract }, methodName: string, metadata: AbiMetadata): void => {\n if (!metadataStore.has(contract)) {\n metadataStore.set(contract, {})\n }\n const metadatas: Record<string, AbiMetadata> = metadataStore.get(contract) as Record<string, AbiMetadata>\n metadatas[methodName] = metadata\n}\n\nexport const getContractAbiMetadata = <T extends Contract>(contract: T | { new (): T }): Record<string, AbiMetadata> => {\n // Initialize result object to store merged metadata\n const result: Record<string, AbiMetadata> = {}\n\n // Get the contract's class\n let currentClass = contract instanceof Contract ? (contract.constructor as { new (): T }) : contract\n\n // Walk up the prototype chain\n while (currentClass && currentClass.prototype) {\n // Find metadata for current class\n const currentMetadata = metadataStore.get(currentClass)\n\n if (currentMetadata) {\n // Merge metadata with existing result (don't override existing entries)\n const classMetadata = currentMetadata\n for (const [methodName, metadata] of Object.entries(classMetadata)) {\n if (!(methodName in result)) {\n result[methodName] = {\n ...metadata,\n ...(currentClass.prototype as DeliberateAny)?.[methodName]?.[Arc4MethodConfigSymbol],\n }\n }\n }\n }\n\n // Move up the prototype chain\n currentClass = Object.getPrototypeOf(currentClass)\n }\n\n return result\n}\n\nexport const getContractMethodAbiMetadata = <T extends Contract>(contract: T, methodName: string): AbiMetadata => {\n const metadatas = getContractAbiMetadata(contract)\n return metadatas[methodName]\n}\n\nexport const getArc4Signature = (metadata: AbiMetadata): string => {\n if (metadata.methodSignature === undefined) {\n const argTypes = metadata.argTypes.map((t) => JSON.parse(t) as TypeInfo).map(getArc4TypeName)\n const returnType = getArc4TypeName(JSON.parse(metadata.returnType) as TypeInfo)\n metadata.methodSignature = `${metadata.name ?? metadata.methodName}(${argTypes.join(',')})${returnType}`\n }\n return metadata.methodSignature\n}\n\nexport const getArc4Selector = (metadata: AbiMetadata): Uint8Array => {\n const hash = js_sha512.sha512_256.array(getArc4Signature(metadata))\n return new Uint8Array(hash.slice(0, 4))\n}\n\nconst getArc4TypeName = (t: TypeInfo): string => {\n const map: Record<string, string | ((t: TypeInfo) => string)> = {\n void: 'void',\n account: 'account',\n application: 'application',\n asset: 'asset',\n boolean: 'bool',\n biguint: 'uint512',\n bytes: 'byte[]',\n string: 'string',\n uint64: 'uint64',\n OnCompleteAction: 'uint64',\n TransactionType: 'uint64',\n Transaction: 'txn',\n PaymentTxn: 'pay',\n KeyRegistrationTxn: 'keyreg',\n AssetConfigTxn: 'acfg',\n AssetTransferTxn: 'axfer',\n AssetFreezeTxn: 'afrz',\n ApplicationTxn: 'appl',\n 'Tuple(<.*>)?': (t) =>\n `(${Object.values(t.genericArgs as Record<string, TypeInfo>)\n .map(getArc4TypeName)\n .join(',')})`,\n }\n const entry = Object.entries(map).find(([k, _]) => new RegExp(`^${k}$`, 'i').test(t.name))?.[1]\n if (entry === undefined) {\n return getArc4TypeNameForARC4Encoded(t) ?? t.name\n }\n if (entry instanceof Function) {\n return entry(t)\n }\n return entry\n}\n"],"names":["getArc4TypeNameForARC4Encoded"],"mappings":"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"}
package/abi-metadata.d.ts CHANGED
@@ -1,21 +1,21 @@
1
- import { BaseContract, Contract } from '@algorandfoundation/algorand-typescript';
2
- import { AbiMethodConfig, BareMethodConfig, CreateOptions, OnCompleteActionStr } from '@algorandfoundation/algorand-typescript/arc4';
1
+ import type { OnCompleteActionStr } from '@algorandfoundation/algorand-typescript';
2
+ import type { CreateOptions } from '@algorandfoundation/algorand-typescript/arc4';
3
+ import { Contract } from './impl/contract';
3
4
  export interface AbiMetadata {
4
5
  methodName: string;
6
+ name?: string;
5
7
  methodSignature: string | undefined;
6
8
  argTypes: string[];
7
9
  returnType: string;
8
10
  onCreate?: CreateOptions;
9
11
  allowActions?: OnCompleteActionStr[];
10
12
  }
11
- export declare const isContractProxy: unique symbol;
12
13
  export declare const attachAbiMetadata: (contract: {
13
14
  new (): Contract;
14
15
  }, methodName: string, metadata: AbiMetadata) => void;
15
- export declare const copyAbiMetadatas: <T extends BaseContract>(sourceContract: T, targetContract: T) => void;
16
- export declare const captureMethodConfig: <T extends Contract>(contract: T, methodName: string, config?: AbiMethodConfig<T> | BareMethodConfig) => void;
17
- export declare const hasAbiMetadata: <T extends Contract>(contract: T) => boolean;
18
- export declare const getContractAbiMetadata: <T extends BaseContract>(contract: T) => Record<string, AbiMetadata>;
19
- export declare const getContractMethodAbiMetadata: <T extends BaseContract>(contract: T, methodName: string) => AbiMetadata;
16
+ export declare const getContractAbiMetadata: <T extends Contract>(contract: T | {
17
+ new (): T;
18
+ }) => Record<string, AbiMetadata>;
19
+ export declare const getContractMethodAbiMetadata: <T extends Contract>(contract: T, methodName: string) => AbiMetadata;
20
20
  export declare const getArc4Signature: (metadata: AbiMetadata) => string;
21
21
  export declare const getArc4Selector: (metadata: AbiMetadata) => Uint8Array;
@@ -0,0 +1,40 @@
1
+ import * as arc4$1 from '@algorandfoundation/algorand-typescript/arc4';
2
+ import { a as getContractMethodAbiMetadata, g as getArc4Selector, C as Contract, c as abimethod, d as baremethod } from './abi-metadata-Dqh8iYjB.js';
3
+ import { encodingUtil } from '@algorandfoundation/puya-ts';
4
+ import { am as sha512_256, i as Bytes } from './crypto-BMTigz9x.js';
5
+
6
+ function _mergeNamespaces(n, m) {
7
+ m.forEach(function (e) {
8
+ e && typeof e !== 'string' && !Array.isArray(e) && Object.keys(e).forEach(function (k) {
9
+ if (k !== 'default' && !(k in n)) {
10
+ var d = Object.getOwnPropertyDescriptor(e, k);
11
+ Object.defineProperty(n, k, d.get ? d : {
12
+ enumerable: true,
13
+ get: function () { return e[k]; }
14
+ });
15
+ }
16
+ });
17
+ });
18
+ return Object.freeze(n);
19
+ }
20
+
21
+ const methodSelector = (methodSignature, contract) => {
22
+ if (typeof methodSignature === 'string') {
23
+ return sha512_256(Bytes(encodingUtil.utf8ToUint8Array(methodSignature))).slice(0, 4);
24
+ }
25
+ else {
26
+ const abiMetadata = getContractMethodAbiMetadata(contract, methodSignature.name);
27
+ return Bytes(getArc4Selector(abiMetadata));
28
+ }
29
+ };
30
+
31
+ var arc4 = /*#__PURE__*/_mergeNamespaces({
32
+ __proto__: null,
33
+ Contract: Contract,
34
+ abimethod: abimethod,
35
+ baremethod: baremethod,
36
+ methodSelector: methodSelector
37
+ }, [arc4$1]);
38
+
39
+ export { arc4 as a, methodSelector as m };
40
+ //# sourceMappingURL=arc4-DMlP46RF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"arc4-DMlP46RF.js","sources":["../src/impl/method-selector.ts"],"sourcesContent":["import type { arc4, bytes } from '@algorandfoundation/algorand-typescript'\nimport { encodingUtil } from '@algorandfoundation/puya-ts'\nimport { getArc4Selector, getContractMethodAbiMetadata } from '../abi-metadata'\nimport type { Contract } from './contract'\nimport { sha512_256 } from './crypto'\nimport { Bytes } from './primitives'\n\nexport const methodSelector = <TContract extends Contract>(\n methodSignature: Parameters<typeof arc4.methodSelector>[0],\n contract?: TContract,\n): bytes => {\n if (typeof methodSignature === 'string') {\n return sha512_256(Bytes(encodingUtil.utf8ToUint8Array(methodSignature))).slice(0, 4)\n } else {\n const abiMetadata = getContractMethodAbiMetadata(contract!, methodSignature.name)\n return Bytes(getArc4Selector(abiMetadata))\n }\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;MAOa,cAAc,GAAG,CAC5B,eAA0D,EAC1D,QAAoB,KACX;AACT,IAAA,IAAI,OAAO,eAAe,KAAK,QAAQ,EAAE;AACvC,QAAA,OAAO,UAAU,CAAC,KAAK,CAAC,YAAY,CAAC,gBAAgB,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;;SAC/E;QACL,MAAM,WAAW,GAAG,4BAA4B,CAAC,QAAS,EAAE,eAAe,CAAC,IAAI,CAAC;AACjF,QAAA,OAAO,KAAK,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC;;AAE9C;;;;;;;;;;;;"}