Repository: algorand/js-algorand-sdk
Pull request #703 (2022-12-05 18:11:27)

FOR REVIEW ONLY - Release v1.24.0
<!-- Release notes generated using configuration in .github/release.yml at release/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


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 968d890..e6713e4 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 9dbf899..2571126 100644
--- a/README.md
+++ b/README.md
@@ -22,8 +22,8 @@ Include a minified browser bundle directly in your HTML like so:
 
 ```html
 <script
-  src="https://unpkg.com/algosdk@v1.23.2/dist/browser/algosdk.min.js"
-  integrity="sha384-1gIB0FiLMNmJ7adAfBOdH20Mnw0DZarB9D3PTozUAhKn/uT9CpHdaSbBIpmZTgrU"
+  src="https://unpkg.com/algosdk@v1.24.0/dist/browser/algosdk.min.js"
+  integrity="sha384-PgD+QJZqpxjiZn/vLc2OPg8jbbOv7i0Scv2y3aB+VoUNIP4P93CR96QdzEQctWY9"
   crossorigin="anonymous"
 ></script>
 ```
@@ -32,8 +32,8 @@ or
 
 ```html
 <script
-  src="https://cdn.jsdelivr.net/npm/algosdk@v1.23.2/dist/browser/algosdk.min.js"
-  integrity="sha384-1gIB0FiLMNmJ7adAfBOdH20Mnw0DZarB9D3PTozUAhKn/uT9CpHdaSbBIpmZTgrU"
+  src="https://cdn.jsdelivr.net/npm/algosdk@v1.24.0/dist/browser/algosdk.min.js"
+  integrity="sha384-PgD+QJZqpxjiZn/vLc2OPg8jbbOv7i0Scv2y3aB+VoUNIP4P93CR96QdzEQctWY9"
   crossorigin="anonymous"
 ></script>
 ```
diff --git a/package-lock.json b/package-lock.json
index fcca6b3..72870c9 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 7795dbf..22b5815 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 4c0d632..3ea89e6 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 5e53801..98fbe15 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 297c9a7..8efd579 100644
--- a/src/multisig.ts
+++ b/src/multisig.ts
@@ -42,7 +42,7 @@ interface MultisigMetadataWithPks extends Omit<MultisigMetadata, 'addrs'> {
 }
 
 /**
- * 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


Test patch:
diff --git a/tests/10.ABI.ts b/tests/10.ABI.ts
index ca90f6f..68447aa 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<T> = {
+    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<T>(a: ABIType, b: T, c: Uint8Array): TestCase<T> {
+    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 8a4b14d..53d9613 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';