diff --git a/CHANGELOG.md b/CHANGELOG.md
index 968d890cc..e6713e493 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,25 @@
+# v1.24.0
+
+## What's Changed
+
+### Bugfixes
+
+- Bug-Fix: encode ABI string with non-ASCII characters by @ahangsu in https://github.com/algorand/js-algorand-sdk/pull/700
+
+### Enhancements
+
+- Tests: Migrate v1 algod dependencies to v2 in cucumber tests by @algochoi in https://github.com/algorand/js-algorand-sdk/pull/693
+- REST API: Add KV counts to NodeStatusResponse by @michaeldiamant in https://github.com/algorand/js-algorand-sdk/pull/696
+- Fix: createMultisigTransaction name in comments by @nullun in https://github.com/algorand/js-algorand-sdk/pull/694
+- Enhancement: allowing zero-length static array by @ahangsu in https://github.com/algorand/js-algorand-sdk/pull/698
+- ABI: Refactor ABI encoding test to round-trip by @michaeldiamant in https://github.com/algorand/js-algorand-sdk/pull/701
+
+## New Contributors
+
+- @nullun made their first contribution in https://github.com/algorand/js-algorand-sdk/pull/694
+
+**Full Changelog**: https://github.com/algorand/js-algorand-sdk/compare/v1.23.2...v1.24.0
+
# v1.23.2
## What's Changed
diff --git a/README.md b/README.md
index 9dbf8996c..2571126a0 100644
--- a/README.md
+++ b/README.md
@@ -22,8 +22,8 @@ Include a minified browser bundle directly in your HTML like so:
```html
```
@@ -32,8 +32,8 @@ or
```html
```
diff --git a/package-lock.json b/package-lock.json
index fcca6b315..72870c902 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "algosdk",
- "version": "1.23.2",
+ "version": "1.24.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "algosdk",
- "version": "1.23.2",
+ "version": "1.24.0",
"license": "MIT",
"dependencies": {
"algo-msgpack-with-bigint": "^2.1.1",
diff --git a/package.json b/package.json
index 7795dbf80..22b5815c9 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "algosdk",
- "version": "1.23.2",
+ "version": "1.24.0",
"description": "The official JavaScript SDK for Algorand",
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
diff --git a/src/abi/abi_type.ts b/src/abi/abi_type.ts
index 4c0d632ac..3ea89e67c 100644
--- a/src/abi/abi_type.ts
+++ b/src/abi/abi_type.ts
@@ -28,7 +28,7 @@ interface Segment {
right: number;
}
-const staticArrayRegexp = /^([a-z\d[\](),]+)\[([1-9][\d]*)]$/;
+const staticArrayRegexp = /^([a-z\d[\](),]+)\[(0|[1-9][\d]*)]$/;
const ufixedRegexp = /^ufixed([1-9][\d]*)x([1-9][\d]*)$/;
export type ABIValue =
@@ -380,8 +380,13 @@ export class ABIStringType extends ABIType {
throw new Error(`Cannot encode value as string: ${value}`);
}
const encodedBytes = Buffer.from(value);
- const encodedLength = bigIntToBytes(value.length, LENGTH_ENCODE_BYTE_SIZE);
- const mergedBytes = new Uint8Array(value.length + LENGTH_ENCODE_BYTE_SIZE);
+ const encodedLength = bigIntToBytes(
+ encodedBytes.length,
+ LENGTH_ENCODE_BYTE_SIZE
+ );
+ const mergedBytes = new Uint8Array(
+ encodedBytes.length + LENGTH_ENCODE_BYTE_SIZE
+ );
mergedBytes.set(encodedLength);
mergedBytes.set(encodedBytes, LENGTH_ENCODE_BYTE_SIZE);
return mergedBytes;
@@ -414,9 +419,9 @@ export class ABIArrayStaticType extends ABIType {
constructor(argType: ABIType, arrayLength: number) {
super();
- if (arrayLength < 1) {
+ if (arrayLength < 0) {
throw new Error(
- `static array must have a length greater than 0: ${arrayLength}`
+ `static array must have a non negative length: ${arrayLength}`
);
}
this.childType = argType;
diff --git a/src/client/v2/algod/models/types.ts b/src/client/v2/algod/models/types.ts
index 5e538012a..98fbe1540 100644
--- a/src/client/v2/algod/models/types.ts
+++ b/src/client/v2/algod/models/types.ts
@@ -2530,6 +2530,12 @@ export class NodeStatusResponse extends BaseModel {
*/
public catchpointProcessedAccounts?: number | bigint;
+ /**
+ * The number of key-values (KVs) from the current catchpoint that have been
+ * processed so far as part of the catchup
+ */
+ public catchpointProcessedKvs?: number | bigint;
+
/**
* The total number of accounts included in the current catchpoint
*/
@@ -2541,12 +2547,23 @@ export class NodeStatusResponse extends BaseModel {
*/
public catchpointTotalBlocks?: number | bigint;
+ /**
+ * The total number of key-values (KVs) included in the current catchpoint
+ */
+ public catchpointTotalKvs?: number | bigint;
+
/**
* The number of accounts from the current catchpoint that have been verified so
* far as part of the catchup
*/
public catchpointVerifiedAccounts?: number | bigint;
+ /**
+ * The number of key-values (KVs) from the current catchpoint that have been
+ * verified so far as part of the catchup
+ */
+ public catchpointVerifiedKvs?: number | bigint;
+
/**
* The last catchpoint seen by the node
*/
@@ -2569,11 +2586,16 @@ export class NodeStatusResponse extends BaseModel {
* catchup
* @param catchpointProcessedAccounts - The number of accounts from the current catchpoint that have been processed so
* far as part of the catchup
+ * @param catchpointProcessedKvs - The number of key-values (KVs) from the current catchpoint that have been
+ * processed so far as part of the catchup
* @param catchpointTotalAccounts - The total number of accounts included in the current catchpoint
* @param catchpointTotalBlocks - The total number of blocks that are required to complete the current catchpoint
* catchup
+ * @param catchpointTotalKvs - The total number of key-values (KVs) included in the current catchpoint
* @param catchpointVerifiedAccounts - The number of accounts from the current catchpoint that have been verified so
* far as part of the catchup
+ * @param catchpointVerifiedKvs - The number of key-values (KVs) from the current catchpoint that have been
+ * verified so far as part of the catchup
* @param lastCatchpoint - The last catchpoint seen by the node
*/
constructor({
@@ -2588,9 +2610,12 @@ export class NodeStatusResponse extends BaseModel {
catchpoint,
catchpointAcquiredBlocks,
catchpointProcessedAccounts,
+ catchpointProcessedKvs,
catchpointTotalAccounts,
catchpointTotalBlocks,
+ catchpointTotalKvs,
catchpointVerifiedAccounts,
+ catchpointVerifiedKvs,
lastCatchpoint,
}: {
catchupTime: number | bigint;
@@ -2604,9 +2629,12 @@ export class NodeStatusResponse extends BaseModel {
catchpoint?: string;
catchpointAcquiredBlocks?: number | bigint;
catchpointProcessedAccounts?: number | bigint;
+ catchpointProcessedKvs?: number | bigint;
catchpointTotalAccounts?: number | bigint;
catchpointTotalBlocks?: number | bigint;
+ catchpointTotalKvs?: number | bigint;
catchpointVerifiedAccounts?: number | bigint;
+ catchpointVerifiedKvs?: number | bigint;
lastCatchpoint?: string;
}) {
super();
@@ -2621,9 +2649,12 @@ export class NodeStatusResponse extends BaseModel {
this.catchpoint = catchpoint;
this.catchpointAcquiredBlocks = catchpointAcquiredBlocks;
this.catchpointProcessedAccounts = catchpointProcessedAccounts;
+ this.catchpointProcessedKvs = catchpointProcessedKvs;
this.catchpointTotalAccounts = catchpointTotalAccounts;
this.catchpointTotalBlocks = catchpointTotalBlocks;
+ this.catchpointTotalKvs = catchpointTotalKvs;
this.catchpointVerifiedAccounts = catchpointVerifiedAccounts;
+ this.catchpointVerifiedKvs = catchpointVerifiedKvs;
this.lastCatchpoint = lastCatchpoint;
this.attribute_map = {
@@ -2638,9 +2669,12 @@ export class NodeStatusResponse extends BaseModel {
catchpoint: 'catchpoint',
catchpointAcquiredBlocks: 'catchpoint-acquired-blocks',
catchpointProcessedAccounts: 'catchpoint-processed-accounts',
+ catchpointProcessedKvs: 'catchpoint-processed-kvs',
catchpointTotalAccounts: 'catchpoint-total-accounts',
catchpointTotalBlocks: 'catchpoint-total-blocks',
+ catchpointTotalKvs: 'catchpoint-total-kvs',
catchpointVerifiedAccounts: 'catchpoint-verified-accounts',
+ catchpointVerifiedKvs: 'catchpoint-verified-kvs',
lastCatchpoint: 'last-catchpoint',
};
}
@@ -2692,9 +2726,12 @@ export class NodeStatusResponse extends BaseModel {
catchpoint: data['catchpoint'],
catchpointAcquiredBlocks: data['catchpoint-acquired-blocks'],
catchpointProcessedAccounts: data['catchpoint-processed-accounts'],
+ catchpointProcessedKvs: data['catchpoint-processed-kvs'],
catchpointTotalAccounts: data['catchpoint-total-accounts'],
catchpointTotalBlocks: data['catchpoint-total-blocks'],
+ catchpointTotalKvs: data['catchpoint-total-kvs'],
catchpointVerifiedAccounts: data['catchpoint-verified-accounts'],
+ catchpointVerifiedKvs: data['catchpoint-verified-kvs'],
lastCatchpoint: data['last-catchpoint'],
});
/* eslint-enable dot-notation */
diff --git a/src/multisig.ts b/src/multisig.ts
index 297c9a7e8..8efd5797a 100644
--- a/src/multisig.ts
+++ b/src/multisig.ts
@@ -42,7 +42,7 @@ interface MultisigMetadataWithPks extends Omit {
}
/**
- * createRawMultisigTransaction creates a raw, unsigned multisig transaction blob.
+ * createMultisigTransaction creates a raw, unsigned multisig transaction blob.
* @param txn - the actual transaction.
* @param version - multisig version
* @param threshold - multisig threshold
diff --git a/tests/10.ABI.ts b/tests/10.ABI.ts
index ca90f6f3b..68447aa4b 100644
--- a/tests/10.ABI.ts
+++ b/tests/10.ABI.ts
@@ -10,6 +10,7 @@ import {
ABIUfixedType,
ABIUintType,
ABIType,
+ ABIValue,
} from '../src/abi/abi_type';
import { decodeAddress } from '../src/encoding/address';
@@ -125,7 +126,7 @@ describe('ABI type checking', () => {
'[][][]',
'stuff[]',
// static array
- 'ufixed32x10[0]',
+ 'bool[01]',
'byte[10 ]',
'uint64[0x21]',
// tuple
@@ -218,191 +219,233 @@ describe('ABI type checking', () => {
});
describe('ABI encoding', () => {
- it('should encode the value correctly into bytes', () => {
- const testCases = [
- [new ABIUintType(8).encode(BigInt(0)), new Uint8Array([0])],
- [new ABIUintType(16).encode(BigInt(3)), new Uint8Array([0, 3])],
- [
- new ABIUintType(64).encode(256),
- new Uint8Array([0, 0, 0, 0, 0, 0, 1, 0]),
- ],
- [new ABIUfixedType(8, 30).encode(BigInt(255)), new Uint8Array([255])],
- [new ABIUfixedType(32, 10).encode(33), new Uint8Array([0, 0, 0, 33])],
- [
- new ABIAddressType().encode(
- 'MO2H6ZU47Q36GJ6GVHUKGEBEQINN7ZWVACMWZQGIYUOE3RBSRVYHV4ACJI'
- ),
- decodeAddress(
- 'MO2H6ZU47Q36GJ6GVHUKGEBEQINN7ZWVACMWZQGIYUOE3RBSRVYHV4ACJI'
- ).publicKey,
- ],
- [new ABIByteType().encode(10), new Uint8Array([10])],
- [new ABIByteType().encode(255), new Uint8Array([255])],
- [new ABIBoolType().encode(true), new Uint8Array([128])],
- [new ABIBoolType().encode(false), new Uint8Array([0])],
- [
- new ABIStringType().encode('asdf'),
- new Uint8Array([0, 4, 97, 115, 100, 102]),
- ],
- [
- new ABIArrayStaticType(new ABIBoolType(), 3).encode([
- true,
- true,
- false,
- ]),
- new Uint8Array([192]),
- ],
- [
- new ABIArrayStaticType(new ABIBoolType(), 8).encode([
- false,
- true,
- false,
- false,
- false,
- false,
- false,
- false,
- ]),
- new Uint8Array([64]),
- ],
- [
- new ABIArrayStaticType(new ABIBoolType(), 8).encode([
- true,
- true,
- true,
- true,
- true,
- true,
- true,
- true,
- ]),
- new Uint8Array([255]),
- ],
- [
- new ABIArrayStaticType(new ABIBoolType(), 9).encode([
- true,
- false,
- false,
- true,
- false,
- false,
- true,
- false,
- true,
- ]),
- new Uint8Array([146, 128]),
- ],
- [
- new ABIArrayStaticType(new ABIUintType(64), 3).encode([
- BigInt(1),
- BigInt(2),
- BigInt(3),
- ]),
- new Uint8Array([
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 1,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 2,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 3,
- ]),
- ],
- [
- new ABIArrayDynamicType(new ABIBoolType()).encode([]),
- new Uint8Array([0, 0]),
- ],
- [
- new ABIArrayDynamicType(new ABIBoolType()).encode([true, true, false]),
- new Uint8Array([0, 3, 192]),
- ],
- [
- new ABIArrayDynamicType(new ABIBoolType()).encode([
- false,
- true,
- false,
- false,
- false,
- false,
- false,
- false,
- ]),
- new Uint8Array([0, 8, 64]),
- ],
- [
- new ABIArrayDynamicType(new ABIBoolType()).encode([
- true,
- false,
- false,
- true,
- false,
- false,
- true,
- false,
- true,
- ]),
- new Uint8Array([0, 9, 146, 128]),
- ],
- [ABIType.from('()').encode([]), new Uint8Array([])],
- // 2^6 + 2^5 = 64 + 32 = 96
- [
- ABIType.from('(bool,bool,bool)').encode([false, true, true]),
- new Uint8Array([96]),
- ],
- [
- ABIType.from('(bool[3])').encode([[false, true, true]]),
- new Uint8Array([96]),
- ],
- [
- ABIType.from('(bool[])').encode([[false, true, true]]),
- new Uint8Array([0, 2, 0, 3, 96]),
- ],
- [
- ABIType.from('(bool[2],bool[])').encode([
- [true, true],
- [true, true],
- ]),
- new Uint8Array([192, 0, 3, 0, 2, 192]),
- ],
- [
- ABIType.from('(bool[],bool[])').encode([[], []]),
- new Uint8Array([0, 4, 0, 6, 0, 0, 0, 0]),
- ],
- [
- ABIType.from('(string,bool,bool,bool,bool,string)').encode([
- 'AB',
- true,
- false,
- true,
- false,
- 'DE',
- ]),
- new Uint8Array([0, 5, 160, 0, 9, 0, 2, 65, 66, 0, 2, 68, 69]),
- ],
- ];
+ type TestCase = {
+ abiType: ABIType;
+ input: T;
+ expectedEncoding: Uint8Array;
+ };
- for (const testCase of testCases) {
- const actual = testCase[0];
- const expected = testCase[1];
- assert.deepStrictEqual(actual, expected);
- }
+ function newTestCase(a: ABIType, b: T, c: Uint8Array): TestCase {
+ return {
+ abiType: a,
+ input: b,
+ expectedEncoding: c,
+ };
+ }
+
+ [
+ newTestCase(new ABIUintType(8), BigInt(0), new Uint8Array([0])),
+ newTestCase(new ABIUintType(16), BigInt(3), new Uint8Array([0, 3])),
+ newTestCase(
+ new ABIUintType(64),
+ 256,
+ new Uint8Array([0, 0, 0, 0, 0, 0, 1, 0])
+ ),
+ newTestCase(new ABIUfixedType(8, 30), BigInt(255), new Uint8Array([255])),
+ newTestCase(new ABIUfixedType(32, 10), 33, new Uint8Array([0, 0, 0, 33])),
+ newTestCase(
+ new ABIAddressType(),
+ 'MO2H6ZU47Q36GJ6GVHUKGEBEQINN7ZWVACMWZQGIYUOE3RBSRVYHV4ACJI',
+ decodeAddress(
+ 'MO2H6ZU47Q36GJ6GVHUKGEBEQINN7ZWVACMWZQGIYUOE3RBSRVYHV4ACJI'
+ ).publicKey
+ ),
+ newTestCase(
+ new ABIStringType(),
+ 'What’s new',
+ new Uint8Array([
+ 0,
+ 12,
+ 87,
+ 104,
+ 97,
+ 116,
+ 226,
+ 128,
+ 153,
+ 115,
+ 32,
+ 110,
+ 101,
+ 119,
+ ])
+ ),
+ newTestCase(
+ new ABIStringType(),
+ '😅🔨',
+ new Uint8Array([0, 8, 240, 159, 152, 133, 240, 159, 148, 168])
+ ),
+ newTestCase(new ABIByteType(), 10, new Uint8Array([10])),
+ newTestCase(new ABIByteType(), 255, new Uint8Array([255])),
+ newTestCase(new ABIBoolType(), true, new Uint8Array([128])),
+ newTestCase(new ABIBoolType(), false, new Uint8Array([0])),
+ newTestCase(
+ new ABIStringType(),
+ 'asdf',
+ new Uint8Array([0, 4, 97, 115, 100, 102])
+ ),
+ newTestCase(
+ new ABIArrayStaticType(new ABIBoolType(), 3),
+ [true, true, false],
+ new Uint8Array([192])
+ ),
+ newTestCase(
+ new ABIArrayStaticType(new ABIBoolType(), 8),
+ [false, true, false, false, false, false, false, false],
+ new Uint8Array([64])
+ ),
+ newTestCase(
+ new ABIArrayStaticType(new ABIBoolType(), 8),
+ [true, true, true, true, true, true, true, true],
+ new Uint8Array([255])
+ ),
+ newTestCase(
+ new ABIArrayStaticType(new ABIBoolType(), 9),
+ [true, false, false, true, false, false, true, false, true],
+ new Uint8Array([146, 128])
+ ),
+ newTestCase(
+ new ABIArrayStaticType(new ABIUintType(64), 3),
+ [BigInt(1), BigInt(2), 3], // Deliberately mix BigInt and int
+ new Uint8Array([
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3,
+ ])
+ ),
+ newTestCase(
+ new ABIArrayDynamicType(new ABIBoolType()),
+ [],
+ new Uint8Array([0, 0])
+ ),
+ newTestCase(
+ new ABIArrayDynamicType(new ABIBoolType()),
+ [true, true, false],
+ new Uint8Array([0, 3, 192])
+ ),
+ newTestCase(
+ new ABIArrayDynamicType(new ABIBoolType()),
+ [false, true, false, false, false, false, false, false],
+ new Uint8Array([0, 8, 64])
+ ),
+ newTestCase(
+ new ABIArrayDynamicType(new ABIBoolType()),
+ [true, false, false, true, false, false, true, false, true],
+ new Uint8Array([0, 9, 146, 128])
+ ),
+ newTestCase(ABIType.from('()'), [], new Uint8Array([])),
+ // 2^6 + 2^5 = 64 + 32 = 96
+ newTestCase(
+ ABIType.from('(bool,bool,bool)'),
+ [false, true, true],
+ new Uint8Array([96])
+ ),
+ newTestCase(
+ ABIType.from('(bool[3])'),
+ [[false, true, true]],
+ new Uint8Array([96])
+ ),
+ newTestCase(
+ ABIType.from('(bool[])'),
+ [[false, true, true]],
+ new Uint8Array([0, 2, 0, 3, 96])
+ ),
+ newTestCase(
+ ABIType.from('(bool[2],bool[])'),
+ [
+ [true, true],
+ [true, true],
+ ],
+ new Uint8Array([192, 0, 3, 0, 2, 192])
+ ),
+ newTestCase(
+ ABIType.from('(bool[],bool[])'),
+ [[], []],
+ new Uint8Array([0, 4, 0, 6, 0, 0, 0, 0])
+ ),
+ newTestCase(
+ ABIType.from('(string,bool,bool,bool,bool,string)'),
+ ['AB', true, false, true, false, 'DE'],
+ new Uint8Array([0, 5, 160, 0, 9, 0, 2, 65, 66, 0, 2, 68, 69])
+ ),
+ newTestCase(
+ new ABITupleType([new ABIUintType(8), new ABIUintType(16)]),
+ [1, 2],
+ new Uint8Array([1, 0, 2])
+ ),
+ ].forEach((testCase) => {
+ it(`should round-trip ${testCase.abiType}, ${testCase.input}`, () => {
+ const encoded = testCase.abiType.encode(testCase.input);
+ assert.deepStrictEqual(encoded, testCase.expectedEncoding);
+ const decoded = testCase.abiType.decode(encoded);
+
+ // Converts any numeric type to BigInt for strict equality comparisons.
+ // The conversion is required because there's no type information
+ // available to convert a decoded BigInt back to its original number
+ // form. Converting from number to BigInt is always _safe_.
+ function numericAsBigInt(d: ABIValue): ABIValue {
+ if (typeof d === 'number') {
+ return BigInt(d);
+ }
+ if (d instanceof Array) {
+ return (d as ABIValue[]).map(numericAsBigInt);
+ }
+ return d;
+ }
+
+ // Returns true when the provided ABIType decodes to BigInt.
+ function decodeReturnsBigInt(t: ABIType): boolean {
+ if (t instanceof ABIUintType || t instanceof ABIUfixedType) {
+ return true;
+ }
+ if (t instanceof ABITupleType) {
+ return t.childTypes.map(decodeReturnsBigInt).includes(true);
+ }
+ if (t instanceof ABIArrayStaticType) {
+ return decodeReturnsBigInt(t.childType);
+ }
+ if (t instanceof ABIArrayDynamicType) {
+ return decodeReturnsBigInt(t.childType);
+ }
+ return false;
+ }
+
+ if (decodeReturnsBigInt(testCase.abiType)) {
+ // If casting to BigInt changes the test case input, then it implies
+ // the _unchanged_ test case input != `decoded`.
+ //
+ // The sanity check confirms that transforming the expected value is
+ // necessary.
+ if (testCase.input !== numericAsBigInt(testCase.input)) {
+ assert.notDeepStrictEqual(decoded, testCase.input);
+ }
+
+ assert.deepStrictEqual(decoded, numericAsBigInt(testCase.input));
+ } else {
+ assert.deepStrictEqual(decoded, testCase.input);
+ }
+ });
});
it('should fail for bad values during encoding', () => {
@@ -431,156 +474,4 @@ describe('ABI encoding', () => {
])
);
});
-
- it('should decode the value correctly into bytes', () => {
- const testCases = [
- [new ABIUintType(8).decode(new Uint8Array([0])), BigInt(0)],
- [new ABIUintType(16).decode(new Uint8Array([0, 3])), BigInt(3)],
- [
- new ABIUintType(64).decode(new Uint8Array([1, 0, 0, 0, 0, 0, 0, 0])),
- BigInt(2 ** 56),
- ],
- [new ABIUfixedType(8, 30).decode(new Uint8Array([255])), BigInt(255)],
- [
- new ABIUfixedType(32, 10).decode(new Uint8Array([0, 0, 0, 33])),
- BigInt(33),
- ],
- [
- new ABIAddressType().decode(
- decodeAddress(
- 'MO2H6ZU47Q36GJ6GVHUKGEBEQINN7ZWVACMWZQGIYUOE3RBSRVYHV4ACJI'
- ).publicKey
- ),
- 'MO2H6ZU47Q36GJ6GVHUKGEBEQINN7ZWVACMWZQGIYUOE3RBSRVYHV4ACJI',
- ],
- [new ABIByteType().decode(new Uint8Array([10])), 10],
- [new ABIByteType().decode(new Uint8Array([255])), 255],
- [new ABIBoolType().decode(new Uint8Array([128])), true],
- [new ABIBoolType().decode(new Uint8Array([0])), false],
- [
- new ABIStringType().decode(new Uint8Array([0, 4, 97, 115, 100, 102])),
- 'asdf',
- ],
- [
- new ABIArrayStaticType(new ABIBoolType(), 3).decode(
- new Uint8Array([192])
- ),
- [true, true, false],
- ],
- [
- new ABIArrayStaticType(new ABIBoolType(), 8).decode(
- new Uint8Array([64])
- ),
- [false, true, false, false, false, false, false, false],
- ],
- [
- new ABIArrayStaticType(new ABIBoolType(), 8).decode(
- new Uint8Array([255])
- ),
- [true, true, true, true, true, true, true, true],
- ],
- [
- new ABIArrayStaticType(new ABIBoolType(), 9).decode(
- new Uint8Array([146, 128])
- ),
- [true, false, false, true, false, false, true, false, true],
- ],
- [
- new ABIArrayStaticType(new ABIUintType(64), 3).decode(
- new Uint8Array([
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 1,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 2,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 3,
- ])
- ),
- [BigInt(1), BigInt(2), BigInt(3)],
- ],
- [
- new ABIArrayDynamicType(new ABIBoolType()).decode(
- new Uint8Array([0, 0])
- ),
- [],
- ],
- [
- new ABIArrayDynamicType(new ABIBoolType()).decode(
- new Uint8Array([0, 3, 192])
- ),
- [true, true, false],
- ],
- [
- new ABIArrayDynamicType(new ABIBoolType()).decode(
- new Uint8Array([0, 8, 64])
- ),
- [false, true, false, false, false, false, false, false],
- ],
- [
- new ABIArrayDynamicType(new ABIBoolType()).decode(
- new Uint8Array([0, 9, 146, 128])
- ),
- [true, false, false, true, false, false, true, false, true],
- ],
- [ABIType.from('()').decode(new Uint8Array([])), []],
- // // 2^6 + 2^5 = 64 + 32 = 96
- [
- ABIType.from('(bool,bool,bool)').decode(new Uint8Array([96])),
- [false, true, true],
- ],
- [
- ABIType.from('(bool[3])').decode(new Uint8Array([96])),
- [[false, true, true]],
- ],
- [
- ABIType.from('(bool[])').decode(new Uint8Array([0, 2, 0, 3, 96])),
- [[false, true, true]],
- ],
- [
- ABIType.from('(bool[2],bool[])').decode(
- new Uint8Array([192, 0, 3, 0, 2, 192])
- ),
- [
- [true, true],
- [true, true],
- ],
- ],
- [
- ABIType.from('(bool[],bool[])').decode(
- new Uint8Array([0, 4, 0, 6, 0, 0, 0, 0])
- ),
- [[], []],
- ],
- [
- ABIType.from('(string,bool,bool,bool,bool,string)').decode(
- new Uint8Array([0, 5, 160, 0, 9, 0, 2, 65, 66, 0, 2, 68, 69])
- ),
- ['AB', true, false, true, false, 'DE'],
- ],
- ];
-
- for (const testCase of testCases) {
- const actual = testCase[0];
- const expected = testCase[1];
- assert.deepStrictEqual(actual, expected);
- }
- });
});
diff --git a/tests/cucumber/steps/steps.js b/tests/cucumber/steps/steps.js
index 8a4b14dcd..53d9613e7 100644
--- a/tests/cucumber/steps/steps.js
+++ b/tests/cucumber/steps/steps.js
@@ -120,17 +120,6 @@ module.exports = function getSteps(options) {
// Dev Mode State
const DEV_MODE_INITIAL_MICROALGOS = 10_000_000;
- /*
- * waitForAlgodInDevMode is a Dev mode helper method that waits for a transaction to resolve.
- * Since Dev mode produces blocks on a per transaction basis, it's possible
- * algod generates a block _before_ the corresponding SDK call to wait for a block.
- * Without _any_ wait, it's possible the SDK looks for the transaction before algod completes processing.
- * So, the method performs a local sleep to simulate waiting for a block.
- */
- function waitForAlgodInDevMode() {
- return new Promise((resolve) => setTimeout(resolve, 500));
- }
-
const { algod_token: algodToken, kmd_token: kmdToken } = options;
// String parsing helper methods
@@ -187,11 +176,6 @@ module.exports = function getSteps(options) {
return boxRefArray;
}
- Given('an algod client', async function () {
- this.acl = new algosdk.Algod(algodToken, 'http://localhost', 60000);
- return this.acl;
- });
-
Given('a kmd client', function () {
this.kcl = new algosdk.Kmd(kmdToken, 'http://localhost', 60001);
return this.kcl;
@@ -228,7 +212,7 @@ module.exports = function getSteps(options) {
});
When('I get versions with algod', async function () {
- this.versions = await this.acl.versions();
+ this.versions = await this.v2Client.versionsCheck().do();
this.versions = this.versions.versions;
return this.versions;
});
@@ -237,47 +221,16 @@ module.exports = function getSteps(options) {
assert.deepStrictEqual(true, this.versions.indexOf('v1') >= 0);
});
+ Then('v2 should be in the versions', function () {
+ assert.deepStrictEqual(true, this.versions.indexOf('v2') >= 0);
+ });
+
When('I get versions with kmd', async function () {
this.versions = await this.kcl.versions();
this.versions = this.versions.versions;
return this.versions;
});
- When('I get the status', async function () {
- this.status = await this.acl.status();
- return this.status;
- });
-
- When('I get status after this block', async function () {
- // Send a transaction to advance blocks in dev mode.
- const sp = await this.acl.getTransactionParams();
- if (sp.firstRound === 0) sp.firstRound = 1;
- const fundingTxnArgs = {
- from: this.accounts[0],
- to: this.accounts[0],
- amount: 0,
- fee: sp.fee,
- firstRound: sp.lastRound + 1,
- lastRound: sp.lastRound + 1000,
- genesisHash: sp.genesishashb64,
- genesisID: sp.genesisID,
- };
- const stxKmd = await this.kcl.signTransaction(
- this.handle,
- this.wallet_pswd,
- fundingTxnArgs
- );
- await this.acl.sendRawTransaction(stxKmd);
-
- this.statusAfter = await this.acl.statusAfterBlock(this.status.lastRound);
- return this.statusAfter;
- });
-
- Then('I can get the block info', async function () {
- this.block = await this.acl.block(this.statusAfter.lastRound);
- assert.deepStrictEqual(true, Number.isInteger(this.block.round));
- });
-
Given(
'payment transaction parameters {int} {int} {int} {string} {string} {string} {int} {string} {string}',
function (fee, fv, lv, gh, to, close, amt, gen, note) {
@@ -426,16 +379,16 @@ module.exports = function getSteps(options) {
this.rekey = await this.kcl.generateKey(this.handle);
this.rekey = this.rekey.address;
// Fund the rekey address with some Algos
- const sp = await this.acl.getTransactionParams();
+ const sp = await this.v2Client.getTransactionParams().do();
if (sp.firstRound === 0) sp.firstRound = 1;
const fundingTxnArgs = {
from: this.accounts[0],
to: this.rekey,
amount: DEV_MODE_INITIAL_MICROALGOS,
fee: sp.fee,
- firstRound: sp.lastRound + 1,
- lastRound: sp.lastRound + 1000,
- genesisHash: sp.genesishashb64,
+ firstRound: sp.firstRound,
+ lastRound: sp.lastRound,
+ genesisHash: sp.genesisHash,
genesisID: sp.genesisID,
};
@@ -444,7 +397,7 @@ module.exports = function getSteps(options) {
this.wallet_pswd,
fundingTxnArgs
);
- await this.acl.sendRawTransaction(stxKmd);
+ await this.v2Client.sendRawTransaction(stxKmd).do();
return this.rekey;
}
);
@@ -504,15 +457,15 @@ module.exports = function getSteps(options) {
'default transaction with parameters {int} {string}',
async function (amt, note) {
[this.pk] = this.accounts;
- const result = await this.acl.getTransactionParams();
+ const result = await this.v2Client.getTransactionParams().do();
this.lastRound = result.lastRound;
this.txn = {
from: this.accounts[0],
to: this.accounts[1],
fee: result.fee,
- firstRound: result.lastRound + 1,
- lastRound: result.lastRound + 1000,
- genesisHash: result.genesishashb64,
+ firstRound: result.firstRound,
+ lastRound: result.lastRound,
+ genesisHash: result.genesisHash,
genesisID: result.genesisID,
note: makeUint8Array(Buffer.from(note, 'base64')),
amount: parseInt(amt),
@@ -525,15 +478,15 @@ module.exports = function getSteps(options) {
'default transaction with parameters {int} {string} and rekeying key',
async function (amt, note) {
this.pk = this.rekey;
- const result = await this.acl.getTransactionParams();
+ const result = await this.v2Client.getTransactionParams().do();
this.lastRound = result.lastRound;
this.txn = {
from: this.rekey,
to: this.accounts[1],
fee: result.fee,
- firstRound: result.lastRound + 1,
- lastRound: result.lastRound + 1000,
- genesisHash: result.genesishashb64,
+ firstRound: result.firstRound,
+ lastRound: result.lastRound,
+ genesisHash: result.genesisHash,
genesisID: result.genesisID,
note: makeUint8Array(Buffer.from(note, 'base64')),
amount: parseInt(amt),
@@ -546,7 +499,7 @@ module.exports = function getSteps(options) {
'default multisig transaction with parameters {int} {string}',
async function (amt, note) {
[this.pk] = this.accounts;
- const result = await this.acl.getTransactionParams();
+ const result = await this.v2Client.getTransactionParams().do();
this.msig = {
version: 1,
threshold: 1,
@@ -557,9 +510,9 @@ module.exports = function getSteps(options) {
from: algosdk.multisigAddress(this.msig),
to: this.accounts[1],
fee: result.fee,
- firstRound: result.lastRound + 1,
- lastRound: result.lastRound + 1000,
- genesisHash: result.genesishashb64,
+ firstRound: result.firstRound,
+ lastRound: result.lastRound,
+ genesisHash: result.genesisHash,
genesisID: result.genesisID,
note: makeUint8Array(Buffer.from(note, 'base64')),
amount: parseInt(amt),
@@ -635,55 +588,14 @@ module.exports = function getSteps(options) {
});
Then('the node should be healthy', async function () {
- const health = await this.acl.healthCheck();
+ const health = await this.v2Client.healthCheck().do();
assert.deepStrictEqual(health, makeObject({}));
});
Then('I get the ledger supply', async function () {
- return this.acl.ledgerSupply();
- });
-
- Then('I get transactions by address and round', async function () {
- const lastRound = await this.acl.status();
- const transactions = await this.acl.transactionByAddress(
- this.accounts[0],
- 1,
- lastRound.lastRound
- );
- assert.deepStrictEqual(
- true,
- Object.entries(transactions).length === 0 ||
- 'transactions' in transactions
- );
+ return this.v2Client.supply().do();
});
- Then('I get pending transactions', async function () {
- const transactions = await this.acl.pendingTransactions(10);
- assert.deepStrictEqual(
- true,
- Object.entries(transactions).length === 0 ||
- 'truncatedTxns' in transactions
- );
- });
-
- When('I get the suggested params', async function () {
- this.params = await this.acl.getTransactionParams();
- return this.params;
- });
-
- When('I get the suggested fee', async function () {
- this.fee = await this.acl.suggestedFee();
- this.fee = this.fee.fee;
- return this.fee;
- });
-
- Then(
- 'the fee in the suggested params should equal the suggested fee',
- function () {
- assert.deepStrictEqual(this.params.fee, this.fee);
- }
- );
-
When('I create a bid', function () {
let addr = algosdk.generateAccount();
this.sk = addr.sk;
@@ -865,21 +777,23 @@ module.exports = function getSteps(options) {
});
When('I send the transaction', async function () {
- this.txid = await this.acl.sendRawTransaction(this.stx);
- this.txid = this.txid.txId;
+ const txid = await this.v2Client.sendRawTransaction(this.stx).do();
+ this.txid = txid.txId;
+ this.appTxid = txid; // Alias to use in waitForTransaction.
return this.txid;
});
When('I send the kmd-signed transaction', async function () {
- this.txid = await this.acl.sendRawTransaction(this.stxKmd);
- this.txid = this.txid.txId;
+ const txid = await this.v2Client.sendRawTransaction(this.stxKmd).do();
+ this.txid = txid.txId;
+ this.appTxid = txid; // Alias to use in waitForTransaction.
return this.txid;
});
// eslint-disable-next-line consistent-return
When('I send the multisig transaction', async function () {
try {
- this.txid = await this.acl.sendRawTransaction(this.stx);
+ this.txid = await this.v2Client.sendRawTransaction(this.stx).do();
this.err = false;
return this.txid;
} catch (e) {
@@ -887,19 +801,6 @@ module.exports = function getSteps(options) {
}
});
- Then('the transaction should go through', async function () {
- await waitForAlgodInDevMode();
- const info = await this.acl.pendingTransactionInformation(this.txid);
- assert.deepStrictEqual(true, 'type' in info);
-
- // TODO: this needs to be modified/removed when v1 is no longer supported
- // let localParams = await this.acl.getTransactionParams();
- // this.lastRound = localParams.lastRound;
- // await waitForAlgodInDevMode();
- // info = await this.acl.transactionById(this.txid);
- // assert.deepStrictEqual(true, 'type' in info);
- });
-
Then('the transaction should not go through', function () {
assert.deepStrictEqual(true, this.err);
});
@@ -1006,12 +907,8 @@ module.exports = function getSteps(options) {
// return this.txid
// })
- Then('I get account information', async function () {
- return this.acl.accountInformation(this.accounts[0]);
- });
-
Then('I can get account information', async function () {
- await this.acl.accountInformation(this.pk);
+ await this.v2Client.accountInformation(this.pk).do();
return this.kcl.deleteKey(this.handle, this.wallet_pswd, this.pk);
});
@@ -1034,12 +931,12 @@ module.exports = function getSteps(options) {
const from = this.accounts[0];
this.pk = from;
- const result = await this.acl.getTransactionParams();
+ const result = await this.v2Client.getTransactionParams().do();
const suggestedParams = {
fee: result.fee,
- firstRound: result.lastRound + 1,
- lastRound: result.lastRound + 1000,
- genesisHash: result.genesishashb64,
+ firstRound: result.firstRound,
+ lastRound: result.lastRound,
+ genesisHash: result.genesisHash,
genesisID: result.genesisID,
};
this.lastRound = result.lastRound;
@@ -1094,12 +991,12 @@ module.exports = function getSteps(options) {
'default asset creation transaction with total issuance {int}',
async function (issuance) {
[this.assetTestFixture.creator] = this.accounts;
- this.params = await this.acl.getTransactionParams();
+ this.params = await this.v2Client.getTransactionParams().do();
this.fee = this.params.fee;
- this.fv = this.params.lastRound;
- this.lv = this.fv + 1000;
+ this.fv = this.params.firstRound;
+ this.lv = this.params.lastRound;
this.note = undefined;
- this.gh = this.params.genesishashb64;
+ this.gh = this.params.genesisHash;
const parsedIssuance = parseInt(issuance);
const decimals = 0;
const defaultFrozen = false;
@@ -1160,12 +1057,12 @@ module.exports = function getSteps(options) {
'default-frozen asset creation transaction with total issuance {int}',
async function (issuance) {
[this.assetTestFixture.creator] = this.accounts;
- this.params = await this.acl.getTransactionParams();
+ this.params = await this.v2Client.getTransactionParams().do();
this.fee = this.params.fee;
- this.fv = this.params.lastRound;
- this.lv = this.fv + 1000;
+ this.fv = this.params.firstRound;
+ this.lv = this.params.lastRound;
this.note = undefined;
- this.gh = this.params.genesishashb64;
+ this.gh = this.params.genesisHash;
const parsedIssuance = parseInt(issuance);
const decimals = 0;
const defaultFrozen = true;
@@ -1235,22 +1132,22 @@ module.exports = function getSteps(options) {
}
When('I update the asset index', async function () {
- const accountResponse = await this.acl.accountInformation(
- this.assetTestFixture.creator
- );
- const heldAssets = accountResponse.thisassettotal;
- let keys = Object.keys(heldAssets).map((key) => parseInt(key));
- keys = keys.sort(sortKeysAscending);
- const assetIndex = keys[keys.length - 1];
+ const accountResponse = await this.v2Client
+ .accountInformation(this.assetTestFixture.creator)
+ .do();
+ const heldAssets = accountResponse['created-assets'];
+ let assetIds = heldAssets.map((asset) => asset.index);
+ assetIds = assetIds.sort(sortKeysAscending);
+ const assetIndex = assetIds[assetIds.length - 1];
// this is stored as a string so it can be used as a key later.
this.assetTestFixture.index = assetIndex.toString();
});
When('I get the asset info', async function () {
- this.assetTestFixture.queriedParams = await this.acl.assetInformation(
- this.assetTestFixture.index
- );
+ this.assetTestFixture.queriedParams = await this.v2Client
+ .getAssetByID(this.assetTestFixture.index)
+ .do();
});
Then('the asset info should match the expected asset info', function () {
@@ -1258,9 +1155,9 @@ module.exports = function getSteps(options) {
assert.strictEqual(
true,
this.assetTestFixture.expectedParams[key] ===
- this.assetTestFixture.queriedParams[key] ||
+ this.assetTestFixture.queriedParams.params[key] ||
typeof this.assetTestFixture.expectedParams[key] === 'undefined' ||
- typeof this.assetTestFixture.queriedParams[key] === 'undefined'
+ typeof this.assetTestFixture.queriedParams.params[key] === 'undefined'
);
});
});
@@ -1269,12 +1166,12 @@ module.exports = function getSteps(options) {
'I create a no-managers asset reconfigure transaction',
async function () {
[this.assetTestFixture.creator] = this.accounts;
- this.params = await this.acl.getTransactionParams();
+ this.params = await this.v2Client.getTransactionParams().do();
this.fee = this.params.fee;
- this.fv = this.params.lastRound;
- this.lv = this.fv + 1000;
+ this.fv = this.params.firstRound;
+ this.lv = this.params.lastRound;
this.note = undefined;
- this.gh = this.params.genesishashb64;
+ this.gh = this.params.genesisHash;
// if we truly supplied no managers at all, it would be an asset destroy txn
// so leave one key written
const manager = this.assetTestFixture.creator;
@@ -1311,12 +1208,12 @@ module.exports = function getSteps(options) {
When('I create an asset destroy transaction', async function () {
[this.assetTestFixture.creator] = this.accounts;
- this.params = await this.acl.getTransactionParams();
+ this.params = await this.v2Client.getTransactionParams().do();
this.fee = this.params.fee;
- this.fv = this.params.lastRound;
- this.lv = this.fv + 1000;
+ this.fv = this.params.firstRound;
+ this.lv = this.params.lastRound;
this.note = undefined;
- this.gh = this.params.genesishashb64;
+ this.gh = this.params.genesisHash;
const genesisID = '';
const type = 'acfg';
@@ -1340,7 +1237,7 @@ module.exports = function getSteps(options) {
Then('I should be unable to get the asset info', async function () {
let failed = false;
try {
- await this.acl.assetInformation(this.assetTestFixture.index);
+ await this.v2Client.getAssetByID(this.assetTestFixture.index).do();
} catch (e) {
failed = true;
}
@@ -1351,12 +1248,12 @@ module.exports = function getSteps(options) {
'I create a transaction for a second account, signalling asset acceptance',
async function () {
const accountToUse = this.accounts[1];
- this.params = await this.acl.getTransactionParams();
+ this.params = await this.v2Client.getTransactionParams().do();
this.fee = this.params.fee;
- this.fv = this.params.lastRound;
- this.lv = this.fv + 1000;
+ this.fv = this.params.firstRound;
+ this.lv = this.params.lastRound;
this.note = undefined;
- this.gh = this.params.genesishashb64;
+ this.gh = this.params.genesisHash;
const genesisID = '';
const type = 'axfer';
@@ -1383,12 +1280,12 @@ module.exports = function getSteps(options) {
When(
'I create a transaction transferring {int} assets from creator to a second account',
async function (amount) {
- this.params = await this.acl.getTransactionParams();
+ this.params = await this.v2Client.getTransactionParams().do();
this.fee = this.params.fee;
- this.fv = this.params.lastRound;
- this.lv = this.fv + 1000;
+ this.fv = this.params.firstRound;
+ this.lv = this.params.lastRound;
this.note = undefined;
- this.gh = this.params.genesishashb64;
+ this.gh = this.params.genesisHash;
const genesisID = '';
const type = 'axfer';
@@ -1415,12 +1312,12 @@ module.exports = function getSteps(options) {
When(
'I create a transaction transferring {int} assets from a second account to creator',
async function (amount) {
- this.params = await this.acl.getTransactionParams();
+ this.params = await this.v2Client.getTransactionParams().do();
this.fee = this.params.fee;
- this.fv = this.params.lastRound;
- this.lv = this.fv + 1000;
+ this.fv = this.params.firstRound;
+ this.lv = this.params.lastRound;
this.note = undefined;
- this.gh = this.params.genesishashb64;
+ this.gh = this.params.genesisHash;
const genesisID = '';
const type = 'axfer';
@@ -1447,18 +1344,21 @@ module.exports = function getSteps(options) {
Then(
'the creator should have {int} assets remaining',
async function (expectedTotal) {
- const accountInformation = await this.acl.accountInformation(
- this.assetTestFixture.creator
- );
- const assetsHeld = accountInformation.assets[this.assetTestFixture.index];
- assert.deepStrictEqual(assetsHeld.amount, parseInt(expectedTotal));
+ const accountInformation = await this.v2Client
+ .accountInformation(this.assetTestFixture.creator)
+ .do();
+ for (const asset of accountInformation.assets) {
+ if (asset['asset-id'] === this.assetTestFixture.index) {
+ assert.deepStrictEqual(asset.amount, parseInt(expectedTotal));
+ }
+ }
}
);
When('I send the bogus kmd-signed transaction', async function () {
this.err = false;
try {
- await this.acl.sendRawTransaction(this.stxKmd);
+ await this.v2Client.sendRawTransaction(this.stxKmd).do();
} catch (e) {
this.err = true;
}
@@ -1467,12 +1367,12 @@ module.exports = function getSteps(options) {
When(
'I create an un-freeze transaction targeting the second account',
async function () {
- this.params = await this.acl.getTransactionParams();
+ this.params = await this.v2Client.getTransactionParams().do();
this.fee = this.params.fee;
- this.fv = this.params.lastRound;
- this.lv = this.fv + 1000;
+ this.fv = this.params.firstRound;
+ this.lv = this.params.lastRound;
this.note = undefined;
- this.gh = this.params.genesishashb64;
+ this.gh = this.params.genesisHash;
const freezer = this.assetTestFixture.creator;
this.assetTestFixture.lastTxn = {
@@ -1497,12 +1397,12 @@ module.exports = function getSteps(options) {
When(
'I create a freeze transaction targeting the second account',
async function () {
- this.params = await this.acl.getTransactionParams();
+ this.params = await this.v2Client.getTransactionParams().do();
this.fee = this.params.fee;
- this.fv = this.params.lastRound;
- this.lv = this.fv + 1000;
+ this.fv = this.params.firstRound;
+ this.lv = this.params.lastRound;
this.note = undefined;
- this.gh = this.params.genesishashb64;
+ this.gh = this.params.genesisHash;
const freezer = this.assetTestFixture.creator;
this.assetTestFixture.lastTxn = {
@@ -1527,12 +1427,12 @@ module.exports = function getSteps(options) {
When(
'I create a transaction revoking {int} assets from a second account to creator',
async function (amount) {
- this.params = await this.acl.getTransactionParams();
+ this.params = await this.v2Client.getTransactionParams().do();
this.fee = this.params.fee;
- this.fv = this.params.lastRound;
- this.lv = this.fv + 1000;
+ this.fv = this.params.firstRound;
+ this.lv = this.params.lastRound;
this.note = undefined;
- this.gh = this.params.genesishashb64;
+ this.gh = this.params.genesisHash;
const genesisID = '';
const type = 'axfer';