Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Bug with Wallet Address, Update Wasm Command, and Update Denom Utils #120

Merged
merged 8 commits into from
Oct 30, 2024

Conversation

SlayerAnsh
Copy link
Contributor

@SlayerAnsh SlayerAnsh commented Oct 24, 2024

Motivation

  • Fix bug with wallet address not being stored when wallet/chain is changed using wallet use command.
  • Updated wasm command to support raw query using key and get all contract states using wasm contract-state command
  • Fixed denom utils to properly convert macro micro denoms without losing existing decimals.
  • Added test for denom utils

Summary by CodeRabbit

Release Notes

  • New Features

    • Added a new changeset: "wild-oranges-give" for improved package management.
    • Introduced a Wallet Address cache in the CLI for better performance.
    • New commands query-raw and contract-state for enhanced contract querying capabilities.
  • Improvements

    • Updated command descriptions to include default values for better user guidance.
    • Enhanced wallet management by keeping wallet addresses up-to-date upon access.
    • Added a new script for testing in the package management system.
  • Bug Fixes

    • Various updates to NPM packages to ensure stability and performance.
  • Testing

    • Added unit tests for currency denomination utilities and CLI functionalities to validate accuracy.
    • Introduced automated testing workflows to streamline quality assurance processes.

Copy link

coderabbitai bot commented Oct 24, 2024

Walkthrough

This pull request introduces several changes across multiple files, including the addition of a new changeset entry in .changeset/pre.json, updates to NPM packages and CLI functionalities, and the introduction of a new testing workflow in GitHub Actions. Notable modifications include enhancements to wallet address management in the CLI, new commands for querying contracts, and updates to the @andromedaprotocol/andromeda.js package. Additionally, new unit tests for utility functions and Jest configuration for TypeScript testing have been implemented.

Changes

File Change Summary
.changeset/pre.json Added new changeset entry "wild-oranges-give" to the existing array.
.changeset/wild-oranges-give.md Updated several NPM packages and implemented Wallet Address cache in the CLI.
.github/workflows/test.yml Introduced a new GitHub Actions workflow for testing packages on pull requests.
package.json Added a new test script and updated dependency overrides.
packages/andrjs/CHANGELOG.md Updated to version 2.0.0-beta.3, reflecting new features and dependency updates.
packages/andrjs/jest.config.js Added Jest configuration for TypeScript testing.
packages/andrjs/package.json Updated version to 2.0.0-beta.3, added new devDependencies, and modified pnpm overrides.
packages/andrjs/src/AndromedaClient.ts Updated queryContractRaw method to accept Uint8Array and renamed queryContractRawAll to queryContractStates.
packages/andrjs/src/utils/denom.spec.ts Introduced unit tests for utility functions related to currency denomination conversions.
packages/andrjs/src/utils/denom.ts Modified conversion functions for improved decimal handling.
packages/andrjs/tsconfig.build.json Updated exclude section to also exclude TypeScript specification files.
packages/cli/CHANGELOG.md Updated to version 2.0.0-beta.3, highlighting new features and command changes.
packages/cli/package.json Updated version to 2.0.0-beta.3.
packages/cli/src/cmd.ts Modified console output formatting for update command.
packages/cli/src/handlers/gql/index.ts Updated flag descriptions in assets command to include default values.
packages/cli/src/handlers/wasm.ts Added new commands query-raw and contract-state for enhanced contract querying functionality.
packages/cli/src/index.spec.ts Introduced a test suite for validating getCurrentPackage functionality.
packages/cli/src/schema/SchemaPrompt.test.ts Deleted file containing tests for SchemaPrompt class.
packages/cli/src/state/WalletStore.ts Enhanced wallet management methods to update stored addresses.
packages/cli/tsconfig.build.json Updated exclude array to include TypeScript specification files.

Possibly related PRs

Suggested reviewers

  • daniel-wehbe
  • leifasorensen
  • crnbarr93

Poem

🐇 In the garden where wild fruits grow,
New changes sprout, as we sow.
With every update, our tools refine,
Wallets and queries, all align.
So hop along, let’s test and play,
For brighter code is here to stay! 🌼


📜 Recent review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between cafb290 and 131b98b.

📒 Files selected for processing (1)
  • .github/workflows/test.yml (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/test.yml

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Outside diff range and nitpick comments (19)
.changeset/wild-oranges-give.md (1)

Line range hint 1-8: Consider using minor/major version bumps instead of patch.

The changes described in the PR objectives include new features (Wasm command enhancements) and potentially breaking changes (denom utils modifications), which typically warrant minor or major version bumps according to semver:

  • Minor version for new features (Wasm command changes)
  • Major version for breaking changes (if denom utils changes affect existing behavior)

Additionally, the changeset description could be more detailed to help users understand the impact of these changes.

Consider this improved structure:

---
-"@andromedaprotocol/andromeda.js": patch
-"@andromedaprotocol/cli": patch
-"@andromedaprotocol/gql": patch
+"@andromedaprotocol/andromeda.js": minor
+"@andromedaprotocol/cli": minor
+"@andromedaprotocol/gql": minor
---

NPM package updates and Wallet Address cache in CLI
+
+Changes:
+- Fixed: Wallet address now persists correctly when changing wallet/chain
+- Added: Enhanced Wasm command with raw query support using keys
+- Fixed: Improved denom utils to handle macro/micro conversions accurately
+- Added: New test coverage for denom utilities
packages/andrjs/tsconfig.build.json (1)

14-15: LGTM! Consider consolidating test exclusion patterns.

The exclusion patterns correctly prevent test files from being included in the production build. However, for better maintainability, you could consolidate these patterns.

Consider this alternative pattern that covers both cases:

  "exclude": [
    "node_modules",
    "dist",
-   "test/**/*.ts",
-   "**/*.spec.ts"
+   "**/*.(spec|test).ts"
  ]

This pattern:

  • Excludes both .spec.ts and .test.ts files
  • Works for files in any directory
  • Reduces maintenance overhead
  • Is more consistent with common TypeScript project structures
packages/cli/tsconfig.build.json (1)

7-16: LGTM! Consider standardizing test file patterns.

The configuration correctly excludes test files from the build output. However, there's an opportunity to standardize the test file patterns.

Currently, you have two patterns for test files:

  • test/**/*.ts
  • src/**/*spec.ts

Consider using a consistent naming convention across the project. For example, either:

  1. Use .spec.ts for all test files and move them next to the source files
  2. Keep all test files in the test directory

This would allow you to simplify the exclude patterns to just one pattern.

.github/workflows/test.yml (1)

1-22: Consider adding test result artifacts and coverage reports.

To improve debugging and maintain quality metrics, consider adding test result artifacts and coverage reporting.

Add these steps after the test step:

      - name: Upload test results
        if: always()
        uses: actions/upload-artifact@v3
        with:
          name: test-results
          path: |
            packages/**/junit.xml
            packages/**/coverage/
          retention-days: 30

      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v3
        with:
          files: ./packages/**/coverage/coverage-final.json
packages/andrjs/CHANGELOG.md (1)

7-10: Consider adding more detailed changelog entries.

The current entries could be more descriptive to help users understand the impact and context of changes. Consider:

  • Adding specific details about the denom utilities fix
  • Including examples of the decimal places fix
  • Mentioning the test coverage details
  • Adding references to related issues/PRs

Example format:

-Fix: Denom utilities now return the correct amount of decimal places
+Fix: Denom utilities now preserve decimal places during macro/micro conversions (#120)
-Tests: Added tests for denom utilities
+Tests: Added comprehensive test suite for denom utilities covering decimal precision edge cases
packages/cli/CHANGELOG.md (1)

7-11: Enhance changelog entries with more details.

The changelog entries could be more descriptive to help users understand the impact of changes:

  • "NPM package updates" - Which packages and why?
  • "Wallet Address cache" - What's the benefit?
  • "GQL Assets default to app-contract" - What's the impact?
  • Command renames - Consider adding examples of the new usage

Consider updating the entries like this:

-NPM package updates
-Wallet Address cache
-GQL Assets default to app-contract
-wasm query-raw command changed to query raw key
+- Updated NPM dependencies for improved stability and security
+- Added Wallet Address caching to persist addresses across chain/wallet changes
+- Changed GQL Assets to default to app-contract for consistent behavior
+- Renamed commands for better clarity:
+  - `wasm query-raw` → `query raw key`
+  - Example usage: `andromeda query raw key <contract> <key>`
packages/andrjs/src/utils/denom.spec.ts (5)

4-13: Consider adding more edge cases to micro-to-macro conversion tests.

While the current test cases cover basic scenarios well, consider adding tests for:

  • Negative numbers
  • Invalid inputs (non-numeric strings)
  • Invalid denomination types

Example additions:

expect(() => convertMicroToMacro('-1000000', 'u')).toThrow();
expect(() => convertMicroToMacro('abc', 'u')).toThrow();
expect(() => convertMicroToMicro('1000000', 'x')).toThrow();

15-24: Consider adding more edge cases to macro-to-micro conversion tests.

Similar to the micro-to-macro tests, consider adding tests for:

  • Negative numbers
  • Invalid inputs (non-numeric strings)
  • Invalid denomination types

Example additions:

expect(() => convertMacroToMicro('-1.0', 'u')).toThrow();
expect(() => convertMacroToMicro('abc', 'u')).toThrow();
expect(() => convertMacroToMicro('1.0', 'x')).toThrow();

26-30: Enhance international formatting test coverage.

Consider adding test cases for:

  • Negative numbers
  • Very large numbers (billions/trillions)
  • Different locales
  • Edge cases with zero decimal places

Example additions:

expect(formatAmountToInternational(-1234.56, 2)).toBe('-1,234.56');
expect(formatAmountToInternational(1234567890.12, 2)).toBe('1,234,567,890.12');
expect(formatAmountToInternational(0.00001, 5)).toBe('0.00001');

32-45: Strengthen DENOM_EXPONENTS validation.

Consider adding tests to verify:

  • Individual exponent values (e.g., 'u' === 6)
  • Immutability of the constant

Example additions:

test('DENOM_EXPONENTS values are correct and immutable', () => {
    expect(DENOM_EXPONENTS.u).toBe(6);
    expect(() => {
        DENOM_EXPONENTS.u = 7;
    }).toThrow();
});

47-50: Expand units config retrieval test coverage.

The current tests only cover 'inj' and 'uatom'. Consider adding test cases for:

  • Invalid denominations
  • Other common tokens (e.g., 'usdc', 'eth')
  • Case sensitivity checks

Example additions:

test('getUnitsConfigFromDenom handles various cases', () => {
    expect(() => getUnitsConfigFromDenom('')).toThrow();
    expect(() => getUnitsConfigFromDenom('invalid')).toThrow();
    expect(getUnitsConfigFromDenom('UATOM')).toEqual(
        expect.objectContaining({ macroDenom: 'ATOM' })
    );
    expect(getUnitsConfigFromDenom('usdc')).toEqual(
        expect.objectContaining({ units: 6, macroDenom: 'USDC' })
    );
});
packages/cli/src/handlers/gql/index.ts (1)

Line range hint 99-103: Enhance type safety and input validation.

While the default values work, there are several improvements that could be made:

  1. Use TypeScript type annotations for better type safety
  2. Add input validation for limit/offset
  3. Convert numeric defaults at the type level rather than runtime

Consider refactoring to:

- const { type = "app-contract", search } = flags;
- const limit = parseInt(flags.limit ?? '10');
- const offset = parseInt(flags.offset ?? '0');
+ interface AssetFlags extends Flags {
+   type?: string;
+   search?: string;
+   limit?: string;
+   offset?: string;
+ }
+ 
+ const { type = "app-contract", search } = flags as AssetFlags;
+ const limit = Math.max(0, parseInt(flags.limit ?? '10'));
+ const offset = Math.max(0, parseInt(flags.offset ?? '0'));
+ 
+ if (isNaN(limit) || isNaN(offset)) {
+   throw new Error("Invalid limit or offset value");
+ }
packages/andrjs/src/utils/denom.ts (1)

Line range hint 1-144: Consider architectural improvements for better maintainability.

To enhance the codebase, consider these architectural improvements:

  1. Add a custom type for amounts to ensure type safety:
type Amount = {
  value: string;
  denom: string;
};
  1. Consider using a decimal arithmetic library like decimal.js or bignumber.js to handle precision-critical calculations more safely.

  2. Add input validation as a separate utility function to maintain DRY principle.

  3. Consider adding logging for debugging and monitoring purposes.

Would you like me to provide a detailed implementation for any of these suggestions?

packages/andrjs/src/AndromedaClient.ts (2)

207-214: Add error handling for JSON parsing and update documentation.

While the implementation looks good, consider these improvements:

  1. Add try-catch for JSON parsing to handle malformed responses gracefully
  2. Update the JSDoc to reflect the new key parameter type

Apply this diff:

   /**
    * Wrapper function for CosmWasm query
    * https://cosmos.github.io/cosmjs/latest/cosmwasm-stargate/classes/SigningCosmWasmClient.html#queryContractSmart
    * @param address
+   * @param key The key to query, either as UTF-8 string or Uint8Array
    * @returns
    */
   async queryContractRaw<T = any>(address: string, key: string | Uint8Array) {
     this.preMessage();
     const result = await this.chainClient!.queryClient!.queryContractRaw(
       address,
       typeof key === 'string' ? Buffer.from(key, 'utf8') : key
     );
     if (!result || result.length === 0) return null;
-    return JSON.parse(Buffer.from(result).toString('utf8')) as T
+    try {
+      return JSON.parse(Buffer.from(result).toString('utf8')) as T;
+    } catch (error) {
+      throw new Error(`Failed to parse contract response: ${error.message}`);
+    }
   }

Line range hint 224-238: Enhance type safety and documentation.

The implementation looks good, but could benefit from these improvements:

  1. Add an interface for the return type
  2. Enhance the documentation with parameter and return type descriptions

Apply this diff:

+  interface ContractStateResponse {
+    states: Array<{
+      key: string;
+      value: string;
+    }>;
+    pagination: {
+      nextKey: Uint8Array;
+      total: number;
+    };
+  }
+
   /**
    * Wrapper function for CosmWasm query
    * https://cosmos.github.io/cosmjs/latest/cosmwasm-stargate/classes/SigningCosmWasmClient.html#queryContractSmart
-   * @param address
-   * @param query
-   * @returns
+   * @param address The contract address to query
+   * @param pagination Pagination options for the query
+   * @returns {Promise<ContractStateResponse>} Object containing states array and pagination info
    */
-  async queryContractStates(address: string, pagination: Partial<PageRequest>) {
+  async queryContractStates(
+    address: string,
+    pagination: Partial<PageRequest>
+  ): Promise<ContractStateResponse> {
packages/cli/src/state/WalletStore.ts (1)

260-261: Add error handling for empty accounts array.

The implementation correctly caches the wallet address, fixing the reported issue. However, consider adding error handling for cases where getAccounts() might return an empty array.

Consider this safer implementation:

-    const address = await signer.getAccounts().then(accounts => accounts[0].address);
+    const accounts = await signer.getAccounts();
+    if (!accounts.length) {
+      throw new Error('No accounts found for the wallet');
+    }
+    const address = accounts[0].address;
     this.updateWallet(wallet.name, { addresses: { [wallet.prefix]: address } })
packages/cli/src/handlers/wasm.ts (3)

82-82: Correct grammatical error in description

The description should be grammatically correct for better clarity. It should read "Queries contract states" without the extra 'a'.

Apply this diff to fix the description:

        description: "Queries a contract states",
-       description: "Queries a contract states",
+       description: "Queries contract states",

293-293: Fix typo in log message

There's a typo in the log message "Querying contrac key...". It should be "Querying contract key..." to accurately reflect the action.

Apply this diff to correct the typo:

        "Querying contrac key...",
-       "Querying contrac key...",
+       "Querying contract key...",

Line range hint 331-338: Check for undefined 'nextKey' before using 'Buffer.from'

If states.pagination.nextKey is undefined, using Buffer.from on it will throw an error. It's important to check if nextKey exists before attempting to convert it.

Apply this diff to add the necessary checks:

      if (states.pagination) {
+       if (states.pagination.nextKey) {
          console.log(pc.gray(`Next Key - ${Buffer.from(states.pagination.nextKey).toString('utf8')}`));
          console.log(pc.gray(`Next Key Bytes - ${Buffer.from(states.pagination.nextKey).toString('hex')}`));
+       } else {
+         console.log(pc.gray(`Next Key - None`));
+         console.log(pc.gray(`Next Key Bytes - None`));
+       }
        console.log(pc.gray(`Total - ${states.pagination.total.toString()}`));
      }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between ba343b2 and cafb290.

⛔ Files ignored due to path filters (3)
  • packages/gql/CHANGELOG.md is excluded by !packages/gql/**
  • packages/gql/package.json is excluded by !packages/gql/**
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (20)
  • .changeset/pre.json (1 hunks)
  • .changeset/wild-oranges-give.md (1 hunks)
  • .github/workflows/test.yml (1 hunks)
  • package.json (2 hunks)
  • packages/andrjs/CHANGELOG.md (1 hunks)
  • packages/andrjs/jest.config.js (1 hunks)
  • packages/andrjs/package.json (3 hunks)
  • packages/andrjs/src/AndromedaClient.ts (2 hunks)
  • packages/andrjs/src/utils/denom.spec.ts (1 hunks)
  • packages/andrjs/src/utils/denom.ts (2 hunks)
  • packages/andrjs/tsconfig.build.json (1 hunks)
  • packages/cli/CHANGELOG.md (1 hunks)
  • packages/cli/package.json (1 hunks)
  • packages/cli/src/cmd.ts (1 hunks)
  • packages/cli/src/handlers/gql/index.ts (2 hunks)
  • packages/cli/src/handlers/wasm.ts (3 hunks)
  • packages/cli/src/index.spec.ts (1 hunks)
  • packages/cli/src/schema/SchemaPrompt.test.ts (0 hunks)
  • packages/cli/src/state/WalletStore.ts (1 hunks)
  • packages/cli/tsconfig.build.json (1 hunks)
💤 Files with no reviewable changes (1)
  • packages/cli/src/schema/SchemaPrompt.test.ts
✅ Files skipped from review due to trivial changes (3)
  • packages/andrjs/jest.config.js
  • packages/cli/package.json
  • packages/cli/src/cmd.ts
🔇 Additional comments (14)
.changeset/pre.json (1)

13-14: LGTM! The changeset entry has been properly added.

The addition of "wild-oranges-give" to the changesets array maintains the correct JSON structure and follows the existing naming convention. This changeset will appropriately track the package updates related to the wallet address fix, Wasm command updates, and denom utils improvements.

packages/cli/src/index.spec.ts (2)

1-2: LGTM! Clean and focused imports.

The imports are correctly structured, importing only what's needed for the test.


1-11: Verify test file location and configuration.

The test file is in the source directory (src/). Consider moving it to a dedicated __tests__ directory for better organization.

Let's check the test file organization in the project:

package.json (2)

34-35: LGTM: Security-related dependency override.

The addition of the dset override follows the same pattern as other security-related version constraints in the file, ensuring consistent security across packages.


8-8: ```shell
#!/bin/bash

Let's try a different approach to find test files and directories

1. Look for test directories

fd -t d "test" packages/

2. Look for files with "test" or "spec" in their names using different patterns

fd -t f "(test|spec).(ts|js|tsx|jsx|mjs)$" packages/

3. Check if there are any Jest or Vitest config files that might indicate test setup

fd -t f "(jest|vitest).config.(ts|js|mjs)$"

4. Look at package.json files in packages to see test scripts

fd -t f "package.json" packages/ -x grep -l ""test":"


</blockquote></details>
<details>
<summary>packages/andrjs/CHANGELOG.md (1)</summary><blockquote>

`10-10`: **Verify if Uint8Array support requires a minor/major version bump.**

The addition of Uint8Array key support in Query Contract Raw could potentially be a breaking change or new feature rather than a patch, depending on how it affects existing implementations.

Let's check the impact:

<details>
<summary>✅ Verification successful</summary>

Let me gather more specific information about the implementation changes.

---

**This change should remain as a patch version bump**

The modification to `queryContractRaw` is backward compatible since:
1. It maintains the existing string parameter functionality unchanged (`Buffer.from(key, 'utf8')`)
2. Only adds support for an additional input type (`Uint8Array`) without modifying the return type or behavior
3. The implementation shows this is purely an enhancement that widens the accepted input types without breaking existing string-based usage

This follows semantic versioning principles where backward compatible bug fixes should use patch version bumps.



</details>

<details>
<summary>🏁 Scripts executed</summary>

The following scripts were executed for the analysis:

Script:

```shell
#!/bin/bash
# Description: Check for existing usage of queryContractRaw to determine if this is a breaking change

# Search for queryContractRaw usage patterns
echo "Searching for queryContractRaw usage patterns..."
rg -A 3 "queryContractRaw" 

# Look for any existing tests that might need updates
echo "Checking for related tests..."
rg -l "queryContractRaw.*test|spec|test.*queryContractRaw"

Length of output: 2784


Script:

#!/bin/bash
# Check the git history for the specific change
git log -p | rg -A 10 -B 10 "queryContractRaw.*Uint8Array"

# Check the implementation before this change
git log -p packages/andrjs/src/AndromedaClient.ts | rg -A 10 -B 10 "queryContractRaw"

Length of output: 3813

packages/andrjs/package.json (3)

3-3: Version bump aligns with PR scope.

The version increment to 2.0.0-beta.3 appropriately reflects the significant changes mentioned in the PR objectives, including wallet address fixes, Wasm command updates, and denom utils improvements.


50-50: Test infrastructure additions support PR objectives.

The addition of Jest-related dependencies (@types/jest and ts-jest) aligns with the PR's objective to add tests for denom utilities. These are industry-standard testing tools for TypeScript projects.

Also applies to: 56-56


71-72: Security override added for dset package.

The addition of "dset@<3.1.4": ">=3.1.4" is a security-focused override that ensures the use of a patched version of the dset package.

Let's verify if this security override is necessary by checking for any security advisories:

packages/cli/CHANGELOG.md (1)

12-13: LGTM: Dependency update is properly documented.

The dependency update to @andromedaprotocol/[email protected] is clearly specified.

packages/andrjs/src/utils/denom.spec.ts (1)

1-3: LGTM! Well-structured test organization.

The test file follows Jest best practices with clear imports and proper test organization using describe blocks.

packages/cli/src/handlers/gql/index.ts (2)

32-32: LGTM: Improved flag descriptions with default values.

The updated flag descriptions now clearly communicate default values to users, improving the CLI's usability.

Also applies to: 40-40, 44-44


98-99: Verify wallet address handling.

Given the PR's focus on fixing wallet address storage issues, let's verify the wallet address handling implementation.

✅ Verification successful

Wallet address handling implementation is correct

The implementation properly handles wallet address verification:

  • WalletStore correctly manages wallet address retrieval with proper null checks
  • The GQL handler appropriately throws an error when no wallet is assigned
  • Error message is clear and descriptive: "No wallet currently assigned"
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for wallet address handling implementations
echo "Searching for wallet address implementations..."
rg -l "currentWalletAddress" 

# Search for wallet state management
echo "\nSearching for wallet state management..."
rg -l "State\.wallets"

Length of output: 920


Script:

#!/bin/bash
# Check the implementation of currentWalletAddress and error handling
echo "Checking WalletStore implementation..."
rg -A 5 "currentWalletAddress" packages/cli/src/state/WalletStore.ts

# Check how wallet address is used in the GQL handler
echo "\nChecking GQL handler implementation..."
rg -B 2 -A 5 "walletAddr" packages/cli/src/handlers/gql/index.ts

# Check wallet state initialization
echo "\nChecking wallet state initialization..."
rg -A 5 "State\.wallets" packages/cli/src/cmd.ts

Length of output: 1584

packages/andrjs/src/utils/denom.ts (1)

52-58: ⚠️ Potential issue

Fix syntax error and add input validation.

There are several issues to address:

  1. Double semicolon on line 53.
  2. Missing input validation.
  3. Potential precision loss with large numbers.

Apply these fixes:

 export const convertMacroToMicro = (amount: string, unit: UNITS) => {
+    if (!/^-?\d+\.?\d*$/.test(amount)) {
+        throw new Error('Invalid amount format');
+    }
     const numZeroes = typeof unit === 'number' ? unit : DENOM_EXPONENTS[unit];
     let [result, decimals = ''] = amount.split('.');
+    const isNegative = result.startsWith('-');
+    result = isNegative ? result.slice(1) : result;
     const shiftedDecimals = decimals.substring(0, numZeroes).padEnd(numZeroes, '0');
-    const remainingDecimals = decimals.substring(numZeroes).replace(/0+$/, '');;
+    const remainingDecimals = decimals.substring(numZeroes).replace(/0+$/, '');
     result = result.concat(shiftedDecimals).replace(/^0+/, '').padEnd(1, '0');
     if (remainingDecimals) {
         result = result.concat('.').concat(remainingDecimals);
     }
-    return result;
+    return `${isNegative ? '-' : ''}${result}`;

Let's verify the test coverage for these functions:

Comment on lines +4 to +11
describe("getPackageVersion", () => {
it("should return the correct version of the current package", () => {
const packageInfo = getCurrentPackage();
expect(packageInfo.version).toBeDefined();
expect(typeof packageInfo.version).toBe("string");
expect(packageInfo.version).toBe(packageJson.version);
});
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider enhancing test coverage with additional test cases.

While the current test case validates the basic functionality, consider adding:

  1. Error cases (e.g., when package.json is malformed)
  2. Tests for other properties returned by getCurrentPackage
  3. Mock package.json to avoid dependency on the actual file

Here's a suggested enhancement:

 describe("getPackageVersion", () => {
+    const mockPackageJson = {
+        version: '1.0.0',
+        name: '@andromedaprotocol/cli'
+    };
+
+    beforeEach(() => {
+        jest.mock('../package.json', () => mockPackageJson);
+    });
+
     it("should return the correct version of the current package", () => {
         const packageInfo = getCurrentPackage();
         expect(packageInfo.version).toBeDefined();
         expect(typeof packageInfo.version).toBe("string");
-        expect(packageInfo.version).toBe(packageJson.version);
+        expect(packageInfo.version).toBe(mockPackageJson.version);
     });
+
+    it("should return the correct package name", () => {
+        const packageInfo = getCurrentPackage();
+        expect(packageInfo.name).toBe(mockPackageJson.name);
+    });
+
+    it("should handle missing package.json gracefully", () => {
+        jest.mock('../package.json', () => {
+            throw new Error('File not found');
+        });
+        expect(() => getCurrentPackage()).toThrow();
+    });
 });

Committable suggestion was skipped due to low confidence.

.github/workflows/test.yml Outdated Show resolved Hide resolved
Comment on lines 12 to 22
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: "20.x"
registry-url: "https://registry.npmjs.org"
- run: pnpm install
- run: pnpm run build
- run: pnpm run test
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Optimize the job configuration for better performance and reliability.

The current configuration could benefit from caching, timeouts, and proper pnpm setup.

Apply these improvements:

 jobs:
   build:
     runs-on: ubuntu-latest
+    timeout-minutes: 15
     steps:
       - uses: actions/checkout@v3
+      - uses: pnpm/action-setup@v2
+        with:
+          version: 8
       - uses: actions/setup-node@v3
         with:
           node-version: "20.x"
           registry-url: "https://registry.npmjs.org"
+          cache: 'pnpm'
+      - name: Get pnpm store directory
+        shell: bash
+        run: |
+          echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
+      - uses: actions/cache@v3
+        with:
+          path: ${{ env.STORE_PATH }}
+          key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
+          restore-keys: |
+            ${{ runner.os }}-pnpm-store-
       - run: pnpm install
       - run: pnpm run build
-      - run: pnpm run test
+      - name: Run tests
+        run: pnpm run test
+        env:
+          CI: true
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: "20.x"
registry-url: "https://registry.npmjs.org"
- run: pnpm install
- run: pnpm run build
- run: pnpm run test
build:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v3
- uses: pnpm/action-setup@v2
with:
version: 8
- uses: actions/setup-node@v3
with:
node-version: "20.x"
registry-url: "https://registry.npmjs.org"
cache: 'pnpm'
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v3
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- run: pnpm install
- run: pnpm run build
- name: Run tests
run: pnpm run test
env:
CI: true

packages/cli/CHANGELOG.md Outdated Show resolved Hide resolved
Comment on lines +1 to +51
import { convertMicroToMacro, convertMacroToMicro, formatAmountToInternational, DENOM_EXPONENTS, getUnitsConfigFromDenom } from './denom';

describe('Denom Utility Functions', () => {
test('converts micro to macro correctly', () => {
expect(convertMicroToMacro('1000000', 'u')).toBe('1.0');
expect(convertMicroToMacro('1000000', 6)).toBe('1.0');
expect(convertMicroToMacro('500000', 'm')).toBe('500.0');
expect(convertMicroToMacro('1234567.89', 'u')).toBe('1.23456789');
expect(convertMicroToMacro('1000000.123456', 'm')).toBe('1000.000123456');
expect(convertMicroToMacro('1', 'u')).toBe('0.000001');
expect(convertMicroToMacro('0', 'u')).toBe('0.0');
expect(convertMicroToMacro('0.0', 'u')).toBe('0.0');
});

test('converts macro to micro correctly', () => {
expect(convertMacroToMicro('1.000000', 'u')).toBe('1000000');
expect(convertMacroToMicro('1.000000', 6)).toBe('1000000');
expect(convertMacroToMicro('0.500000', 'm')).toBe('500');
expect(convertMacroToMicro('1.23456789', 'u')).toBe('1234567.89');
expect(convertMacroToMicro('1000.000123456', 'm')).toBe('1000000.123456');
expect(convertMacroToMicro('1', 'u')).toBe('1000000');
expect(convertMacroToMicro('0', 'u')).toBe('0');
expect(convertMacroToMicro('0.0', 'u')).toBe('0');
});

test('formatAmountToInternational formats numbers correctly', () => {
expect(formatAmountToInternational(1234567.89, 2)).toBe('1,234,567.89');
expect(formatAmountToInternational(1000, 0)).toBe('1,000');
expect(formatAmountToInternational(1234.5678, 3)).toBe('1,234.567');
});

test('DENOM_EXPONENTS contains correct values', () => {
expect(DENOM_EXPONENTS).toEqual({
'd': 1,
'c': 2,
'm': 3,
'u': 6,
'n': 9,
'p': 12,
'f': 15,
'a': 18,
'z': 21,
'y': 24,
});
});

test('getUnitsConfigFromDenom returns correct values', () => {
expect(getUnitsConfigFromDenom('inj')).toEqual({ units: 18, microDenom: 'inj', macroDenom: 'inj' });
expect(getUnitsConfigFromDenom('uatom')).toEqual({ units: 6, microDenom: 'uatom', macroDenom: 'ATOM' });
});
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Test coverage is comprehensive but missing validation for compareStringNumber function

The test suite provides good coverage for most utility functions, but it's missing tests for the compareStringNumber function which is part of the implementation. The current tests effectively validate:

  • Micro to macro conversions with various units and edge cases
  • Macro to micro conversions with different scenarios
  • Amount formatting with internationalization
  • Denom exponents constants
  • Unit configuration retrieval

However, there are opportunities for improvement:

  • Add test cases for compareStringNumber function, including ascending and descending order scenarios
  • Add error cases for invalid unit types in conversion functions
  • Include edge cases for very large numbers in formatting
🔗 Analysis chain

Well-structured test suite with good coverage.

The test suite provides comprehensive coverage of the core functionality for denomination utilities. While there are suggestions for additional test cases, the current implementation effectively validates the key requirements mentioned in the PR objectives, particularly ensuring correct conversions between macro and micro denominations.

Let's verify the test coverage:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if there are any TODOs or FIXMEs in the denom implementation
rg -i "todo|fixme" "packages/andrjs/src/utils/denom.ts"

# Check for any error handling in the implementation
rg "throw|Error" "packages/andrjs/src/utils/denom.ts"

Length of output: 109


Script:

#!/bin/bash
# Let's first check the actual implementation file to understand what's being tested
cat packages/andrjs/src/utils/denom.ts

# Also check for any other test files related to denom
fd denom.spec -e ts -e js

Length of output: 4774

Comment on lines +34 to +35
const decimals = (amount.substring(amount.length - numZeroes)).concat(subDecimals.join()).replace(/0+$/, '').padEnd(1, '0');
return fixed.concat('.').concat(decimals);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add input validation and fix decimal handling.

The current implementation has a few potential issues:

  1. No validation for negative numbers or invalid input.
  2. Using .join() without a separator could cause issues if there are multiple subDecimals.

Consider applying these improvements:

 export const convertMicroToMacro = (amount: string, unit: UNITS) => {
+    if (!/^-?\d+\.?\d*$/.test(amount)) {
+        throw new Error('Invalid amount format');
+    }
     const [realAmount, ...subDecimals] = amount.split('.');
-    amount = realAmount;
+    const isNegative = realAmount.startsWith('-');
+    amount = isNegative ? realAmount.slice(1) : realAmount;
     let numZeroes = typeof unit === 'number' ? unit : DENOM_EXPONENTS[unit];
     amount = amount.padStart(numZeroes + 1, '0');
     const fixed = amount.substring(0, amount.length - numZeroes);
-    const decimals = (amount.substring(amount.length - numZeroes)).concat(subDecimals.join()).replace(/0+$/, '').padEnd(1, '0');
-    return fixed.concat('.').concat(decimals);
+    const decimals = (amount.substring(amount.length - numZeroes))
+        .concat(subDecimals.join(''))
+        .replace(/0+$/, '')
+        .padEnd(1, '0');
+    return `${isNegative ? '-' : ''}${fixed}.${decimals}`;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const decimals = (amount.substring(amount.length - numZeroes)).concat(subDecimals.join()).replace(/0+$/, '').padEnd(1, '0');
return fixed.concat('.').concat(decimals);
export const convertMicroToMacro = (amount: string, unit: UNITS) => {
if (!/^-?\d+\.?\d*$/.test(amount)) {
throw new Error('Invalid amount format');
}
const [realAmount, ...subDecimals] = amount.split('.');
const isNegative = realAmount.startsWith('-');
amount = isNegative ? realAmount.slice(1) : realAmount;
let numZeroes = typeof unit === 'number' ? unit : DENOM_EXPONENTS[unit];
amount = amount.padStart(numZeroes + 1, '0');
const fixed = amount.substring(0, amount.length - numZeroes);
const decimals = (amount.substring(amount.length - numZeroes))
.concat(subDecimals.join(''))
.replace(/0+$/, '')
.padEnd(1, '0');
return `${isNegative ? '-' : ''}${fixed}.${decimals}`;

Comment on lines +288 to +289
const encodedKey = !!flags.encoded;
const keyBytes = encodedKey ? Uint8Array.from(Buffer.from(key, 'hex')) : Uint8Array.from(Buffer.from(key, 'utf8'));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add error handling for key parsing

When the encoded flag is set, parsing the key with Buffer.from(key, 'hex') may throw an exception if the key is not valid hex. Adding error handling will provide a user-friendly error message and prevent the program from crashing.

Apply this diff to add error handling:

      const encodedKey = !!flags.encoded;
-     const keyBytes = encodedKey ? Uint8Array.from(Buffer.from(key, 'hex')) : Uint8Array.from(Buffer.from(key, 'utf8'));
+     let keyBytes;
+     try {
+       keyBytes = encodedKey
+         ? Uint8Array.from(Buffer.from(key, 'hex'))
+         : Uint8Array.from(Buffer.from(key, 'utf8'));
+     } catch (error) {
+       console.log();
+       console.log(pc.red("Invalid key format."));
+       return;
+     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const encodedKey = !!flags.encoded;
const keyBytes = encodedKey ? Uint8Array.from(Buffer.from(key, 'hex')) : Uint8Array.from(Buffer.from(key, 'utf8'));
const encodedKey = !!flags.encoded;
let keyBytes;
try {
keyBytes = encodedKey
? Uint8Array.from(Buffer.from(key, 'hex'))
: Uint8Array.from(Buffer.from(key, 'utf8'));
} catch (error) {
console.log();
console.log(pc.red("Invalid key format."));
return;
}

Comment on lines +68 to +70
{
requestMessage: "Input Key:",
},
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add Input Validation for 'Input Key'

The 'Input Key' prompt currently lacks input validation. To ensure the key is provided in the correct format and to prevent potential errors during execution, it's recommended to add a validation function.

Apply this diff to add input validation:

          {
            requestMessage: "Input Key:",
+           validate: (input: string) => {
+             if (input.length === 0) {
+               console.log();
+               console.log(pc.red("Key cannot be empty."));
+               return false;
+             }
+             return true;
+           },
          },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{
requestMessage: "Input Key:",
},
{
requestMessage: "Input Key:",
validate: (input: string) => {
if (input.length === 0) {
console.log();
console.log(pc.red("Key cannot be empty."));
return false;
}
return true;
},
},

Copy link
Contributor

@leifasorensen leifasorensen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review and local based testing completed without any noticed issues. Additional confirmation is being expected to be provided by Dany W. within the next 24 hours.

Copy link
Contributor

@leifasorensen leifasorensen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@daniel-wehbe has provided a verbal confirmation on testing. Should be good to move forward with the release.

@SlayerAnsh SlayerAnsh merged commit 7eaeda1 into development Oct 30, 2024
2 checks passed
@SlayerAnsh SlayerAnsh deleted the fix/audit-and-wallet-address branch October 30, 2024 12:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants