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

feat: add wallet contract #2314

Open
wants to merge 5 commits into
base: v1.6-dev-ugly
Choose a base branch
from

Conversation

HashEngineering
Copy link
Contributor

@HashEngineering HashEngineering commented Nov 5, 2024

Issue being fixed or feature implemented

Add a Wallet system contract:

  1. store encrypted transaction metadata
  2. store username request information to help masternode voters distinguish

What was done?

Add Wallet system contract. This is called "wallet" because it stores wallet-level

Preliminary documentation on the contract:
Transaction Metadata: https://docs.google.com/document/d/1aLDZmum_MOWF_QVkFbkAVR-m3Wx-FqINiVhCRYBMZXw/edit?tab=t.0

  1. This document still refers to using CBOR for storage before encryption, but it will be changed to ProtoBuf.

Identity Verify - This document stores a normalizedLabel and normalizedParentDomainName and a url to a social media post or some kind of post that helps prove the online identity of a platform identity. It supports one index to allow matching an identity with a particular username (normalizedLabel, normalizedParentDomainName).

This documentation will need to be converted to a DIP.

How Has This Been Tested?

This was not tested. My local systems would not run the yarn setup or yarn start successfully to execute the tests, perhaps due to configuration issues.

Breaking Changes

There should be no breaking changes.

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have added "!" to the title and described breaking changes in the corresponding section if my code contains any
  • I have made corresponding changes to the documentation if needed

For repository code-owners and collaborators only

  • I have assigned this pull request to a milestone

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced the wallet-contract package for managing wallet data, including a JSON schema for documents.
    • Added ESLint and Mocha configurations for improved code quality and testing.
    • Implemented comprehensive unit tests for Wallet Contract functionalities.
    • Defined new schemas for txMetadata and identityVerify to enhance document structure.
  • Documentation

    • Created a README.md file detailing installation, usage, and contribution guidelines.
    • Added MIT License to the package.
  • Bug Fixes

    • Enhanced error handling for version mismatches and schema validation in the wallet contract.

Copy link
Contributor

coderabbitai bot commented Nov 5, 2024

Walkthrough

The pull request introduces a new package named wallet-contract within the workspace, along with updates to the Cargo.toml file to include this package and specify dependencies. A series of configuration files for ESLint and Mocha are added, along with a comprehensive README.md and LICENSE file. The package includes various Rust and JavaScript files that define error handling, document schemas, and unit tests, establishing a foundational structure for wallet-related functionalities.

Changes

File Path Change Summary
Cargo.toml Added new member packages/wallet-contract, specified Rust version as 1.80, and updated dependencies from Git.
packages/wallet-contract/.eslintrc Introduced ESLint configuration extending airbnb-base with custom rules.
packages/wallet-contract/.mocharc.yml Added Mocha configuration with require: test/bootstrap.js and recursive: true.
packages/wallet-contract/Cargo.toml New package defined with metadata, version 1.5.0, and dependencies including thiserror and serde_json.
packages/wallet-contract/LICENSE Added MIT License text.
packages/wallet-contract/README.md Created README file with package details, installation instructions, and licensing information.
packages/wallet-contract/lib/systemIds.js Introduced module exports for ownerId and contractId.
packages/wallet-contract/package.json Updated version to 1.5.0 with existing scripts for linting and testing, contributors, and development dependencies.
packages/wallet-contract/schema/v1/wallet-contract-documents.json Defined schemas for txMetadata and identityVerify with validation rules.
packages/wallet-contract/src/error.rs Added Error enum for enhanced error handling with variants for version mismatches and JSON schema errors.
packages/wallet-contract/src/lib.rs Introduced error handling module and functions for loading definitions and document schemas.
packages/wallet-contract/src/v1/mod.rs Added document_types module with constants and function for loading document schemas.
packages/wallet-contract/test/.eslintrc Created ESLint configuration for test directory with Node.js and Mocha settings.
packages/wallet-contract/test/bootstrap.js Established testing environment with Mocha, Sinon, and Chai, exporting lifecycle hooks.
packages/wallet-contract/test/unit/walletContract.spec.js Added unit tests for Wallet Contract functionality, validating document schemas and error handling.

Possibly related PRs

Suggested labels

enhancement, js-sdk

Suggested reviewers

  • QuantumExplorer
  • shumkov

🐰 "In the garden of code, we hop and play,
New contracts bloom, brightening the day.
With licenses and tests, our work is done,
A wallet for all, let’s have some fun!
So gather your scripts, let’s dance and cheer,
For the wallet-contract is finally here!" 🌼


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.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

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
Contributor

@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: 7

🧹 Outside diff range and nitpick comments (18)
packages/wallet-contract/.eslintrc (4)

4-4: Consider keeping the no-plusplus rule enabled.

Disabling no-plusplus might lead to subtle bugs in certain cases due to automatic semicolon insertion (ASI) in JavaScript. Consider using +=1 or -=1 instead, which are more explicit and safer alternatives.

-    "no-plusplus": 0,
+    "no-plusplus": ["error", { "allowForLoopAfterthoughts": true }]

9-9: Reconsider disabling class-methods-use-this.

Completely disabling class-methods-use-this might lead to instance methods that should be static. Consider enabling it with exceptions where necessary.

-    "class-methods-use-this": "off",
+    "class-methods-use-this": ["error", {
+      "exceptMethods": [
+        // Add specific method names that need to be excluded
+      ]
+    }]

15-17: Consider environment configuration for BigInt.

Instead of declaring BigInt as a global, consider using the env configuration with a modern ECMAScript version that includes BigInt support.

-  "globals": {
-    "BigInt": true
-  }
+  "env": {
+    "es2020": true
+  }

1-18: Add missing TypeScript-related configurations.

Since this is a new contract implementation that will likely handle critical wallet operations, consider adding TypeScript support to catch type-related issues early.

Add these configurations to enhance type safety:

{
  "extends": [
    "airbnb-base",
+   "plugin:@typescript-eslint/recommended"
  ],
+  "parser": "@typescript-eslint/parser",
+  "plugins": ["@typescript-eslint"],
  // ... rest of your config
}
packages/wallet-contract/src/error.rs (2)

5-14: Enhance error documentation for better maintainability.

While the error structure is well-designed, the documentation could be more descriptive:

 pub enum Error {
-    /// Platform expected some specific versions
+    /// Error returned when a method is called with an unsupported platform version.
+    /// This typically occurs during feature version validation when processing
+    /// wallet-related operations.
     #[error("platform unknown version on {method}, received: {received}")]
     UnknownVersionMismatch {
-        /// method
+        /// Name of the method where version mismatch occurred
         method: String,
-        /// the allowed versions for this method
+        /// List of platform versions that are supported by this method
         known_versions: Vec<FeatureVersion>,
-        /// requested core height
+        /// The platform version that was actually received in the request
         received: FeatureVersion,
     },

4-17: Consider adding error variants for wallet-specific operations.

Given that this contract will handle encrypted transaction metadata and username request information, consider adding error variants for:

  • Encryption/decryption failures
  • Username validation errors
  • Storage operation failures
  • Invalid metadata format

This will help in providing more specific error handling for wallet operations.

packages/wallet-contract/test/bootstrap.js (3)

7-9: Consider adding error handling for WebAssembly loading.

The WebAssembly DPP loading is critical for tests. Consider wrapping it in a try-catch block to handle potential loading failures gracefully.

 const {
   default: loadWasmDpp,
 } = require('@dashevo/wasm-dpp');
+
+async function loadWasmDppSafely() {
+  try {
+    await loadWasmDpp();
+  } catch (error) {
+    console.error('Failed to load WebAssembly DPP:', error);
+    throw error;
+  }
+}

17-23: Simplify sinon sandbox initialization.

The current sandbox initialization logic can be simplified by always creating a new sandbox.

   beforeEach() {
-    if (!this.sinon) {
-      this.sinon = sinon.createSandbox();
-    } else {
-      this.sinon.restore();
-    }
+    this.sinon = sinon.createSandbox();
   },

30-30: Add a comment explaining global expect usage.

Consider documenting why expect is made globally available.

+// Make Chai's expect globally available for all test files
 global.expect = expect;
packages/wallet-contract/src/v1/mod.rs (2)

4-14: Add documentation for the document types module.

While the structure is clean, adding documentation comments would help explain:

  • The purpose of each constant
  • The expected format/constraints of each field
  • Any security considerations for handling encrypted metadata

Example documentation:

/// Module containing document type definitions for transaction metadata
pub mod document_types {
    /// Transaction metadata document type and its properties
    pub mod tx_metadata {
        /// Name identifier for transaction metadata documents
        pub const NAME: &str = "tx_metadata";

        /// Property keys used in transaction metadata documents
        pub mod properties {
            /// Index key for identifying the metadata entry
            pub const KEY_INDEX: &str = "keyIndex";
            /// Index for the encryption key used to secure the metadata
            pub const ENCRYPTION_KEY_INDEX: &str = "encryptionKeyIndex";
            /// The actual encrypted metadata content
            pub const ENCRYPTED_METADATA: &str = "encryptedMetadata";
        }
    }
}

16-19: Consider adding schema validation and improving error handling.

While the current implementation works, consider these improvements:

  1. Add schema validation after loading to ensure it matches expected structure
  2. Provide more specific error types for different failure scenarios

Example implementation:

use serde_json::Value;
use thiserror::Error;

#[derive(Error, Debug)]
pub enum SchemaError {
    #[error("Failed to parse schema JSON: {0}")]
    InvalidJson(#[from] serde_json::Error),
    #[error("Schema validation failed: {0}")]
    ValidationError(String),
}

pub fn load_documents_schemas() -> Result<Value, Error> {
    let schema: Value = serde_json::from_str(include_str!("../../schema/v1/wallet-contract-documents.json"))
        .map_err(Error::InvalidSchemaJson)?;
    
    // Validate required structure
    if !schema.get("definitions")
        .and_then(|d| d.get("tx_metadata"))
        .and_then(|t| t.get("properties"))
        .is_some() {
        return Err(Error::InvalidSchemaJson(
            serde_json::Error::custom("Missing required schema structure")
        ));
    }
    
    Ok(schema)
}
packages/wallet-contract/schema/v1/wallet-contract-documents.json (1)

56-57: Document deletion constraints for identityVerify.

While the schema indicates that documents are mutable and can be deleted (documentsMutable and canBeDeleted), there's no documentation about:

  1. Who can delete/modify these documents
  2. The impact of deletion on dependent systems
  3. Any cooldown periods between modifications

Consider adding documentation that covers:

  • Access control for modifications and deletions
  • The impact of changes on the identity verification process
  • Any rate limiting or cooldown periods between modifications
packages/wallet-contract/test/unit/walletContract.spec.js (6)

64-64: Consider assigning undefined instead of using delete for better performance

Using the delete operator can impact performance because it alters the object's structure, leading to de-optimization in JavaScript engines. Assigning undefined to the property is a more performant alternative when you need to unset a property.

Apply this diff to modify the code:

- delete rawTxMetadataDocument.keyIndex;
+ rawTxMetadataDocument.keyIndex = undefined;
🧰 Tools
🪛 Biome

[error] 64-64: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


81-81: Consider assigning undefined instead of using delete for better performance

Similar to line 64, replacing delete with an assignment to undefined can improve performance by avoiding de-optimization.

Apply this diff:

- delete rawTxMetadataDocument.encryptionKeyIndex;
+ rawTxMetadataDocument.encryptionKeyIndex = undefined;
🧰 Tools
🪛 Biome

[error] 81-81: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


98-98: Consider assigning undefined instead of using delete for better performance

Again, for consistency and to enhance performance, consider assigning undefined instead of deleting the property.

Apply this diff:

- delete rawTxMetadataDocument.encryptedMetadata;
+ rawTxMetadataDocument.encryptedMetadata = undefined;
🧰 Tools
🪛 Biome

[error] 98-98: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


184-184: Consider assigning undefined instead of using delete for better performance

In the verifyIdentity tests, replacing delete with an assignment to undefined helps maintain object shape and performance.

Apply this diff:

- delete rawIdentityVerifyDocument.normalizedLabel;
+ rawIdentityVerifyDocument.normalizedLabel = undefined;
🧰 Tools
🪛 Biome

[error] 184-184: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


231-231: Consider assigning undefined instead of using delete for better performance

As before, assigning undefined can be a better choice than using delete for performance optimization.

Apply this diff:

- delete rawIdentityVerifyDocument.normalizedParentDomainName;
+ rawIdentityVerifyDocument.normalizedParentDomainName = undefined;
🧰 Tools
🪛 Biome

[error] 231-231: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


278-278: Consider assigning undefined instead of using delete for better performance

Continuing the pattern, consider this change for consistency and performance benefits.

Apply this diff:

- delete rawIdentityVerifyDocument.url;
+ rawIdentityVerifyDocument.url = undefined;
🧰 Tools
🪛 Biome

[error] 278-278: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between cafda11 and 69f98e7.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (16)
  • Cargo.toml (1 hunks)
  • config/local_seed.json (1 hunks)
  • packages/wallet-contract/.eslintrc (1 hunks)
  • packages/wallet-contract/.mocharc.yml (1 hunks)
  • packages/wallet-contract/Cargo.toml (1 hunks)
  • packages/wallet-contract/LICENSE (1 hunks)
  • packages/wallet-contract/README.md (1 hunks)
  • packages/wallet-contract/lib/systemIds.js (1 hunks)
  • packages/wallet-contract/package.json (1 hunks)
  • packages/wallet-contract/schema/v1/wallet-contract-documents.json (1 hunks)
  • packages/wallet-contract/src/error.rs (1 hunks)
  • packages/wallet-contract/src/lib.rs (1 hunks)
  • packages/wallet-contract/src/v1/mod.rs (1 hunks)
  • packages/wallet-contract/test/.eslintrc (1 hunks)
  • packages/wallet-contract/test/bootstrap.js (1 hunks)
  • packages/wallet-contract/test/unit/walletContract.spec.js (1 hunks)
✅ Files skipped from review due to trivial changes (7)
  • config/local_seed.json
  • packages/wallet-contract/.mocharc.yml
  • packages/wallet-contract/Cargo.toml
  • packages/wallet-contract/LICENSE
  • packages/wallet-contract/lib/systemIds.js
  • packages/wallet-contract/package.json
  • packages/wallet-contract/test/.eslintrc
🧰 Additional context used
🪛 LanguageTool
packages/wallet-contract/README.md

[style] ~28-~28: The phrase ‘feel free to’ is used quite frequently. Consider using a less frequent alternative to set your writing apart from others and make it sound more professional.
Context: ... sh # TODO ... ## Contributing Feel free to dive in! [Open an issue](https://github...

(FEEL_FREE_TO_STYLE_ME)

🪛 Biome
packages/wallet-contract/test/unit/walletContract.spec.js

[error] 64-64: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


[error] 81-81: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


[error] 98-98: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


[error] 184-184: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


[error] 231-231: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


[error] 278-278: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

🔇 Additional comments (17)
packages/wallet-contract/.eslintrc (3)

1-2: LGTM: Good choice of base configuration.

Extending airbnb-base is a solid choice as it provides a comprehensive set of rules that enforce consistent code style and catch common JavaScript pitfalls.


5-8: LGTM: Consistent line endings.

Enforcing consistent line endings with eol-last is good for version control systems and cross-platform compatibility.


10-13: LGTM: Enforcing curly braces.

Enforcing curly braces for all control statements helps prevent errors and improves code readability.

packages/wallet-contract/src/error.rs (2)

1-3: LGTM! Good choice of error handling approach.

The use of thiserror for deriving error implementations is a good practice, and the explicit import of FeatureVersion shows proper version management.


15-16: Verify the long-term need for JSON schema validation.

The PR objectives mention a planned transition from CBOR to ProtoBuf for storage. Please confirm if JSON schema validation will still be needed after this transition.

Let's verify the usage of JSON schemas in the codebase:

✅ Verification successful

Let me analyze the JSON schema usage further by checking its specific usage in the codebase:


Based on the analysis of the JSON schema usage in the codebase, I can now provide a final response:

JSON schema validation remains necessary even with ProtoBuf transition

The JSON schema validation is used across multiple contracts for document validation, including the wallet contract. This validation occurs at the application level for document structure verification, which is separate from the storage serialization format (CBOR/ProtoBuf). The transition to ProtoBuf for storage does not eliminate the need for JSON schema validation as they serve different purposes:

  • ProtoBuf: Used for efficient data serialization in storage
  • JSON Schema: Used for document structure validation and ensuring data integrity at the application level
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for JSON schema related files and usage
# to understand the scope of JSON schema validation

# Look for JSON schema files
echo "Looking for JSON schema files:"
fd -e json -e jsonschema

# Check for JSON schema related code
echo -e "\nChecking for JSON schema related code:"
rg -l "schema|json" --type rust

Length of output: 81504


Script:

#!/bin/bash
# Check for JSON schema validation usage in the codebase
echo "Checking JSON schema validation usage:"
rg -A 5 "InvalidSchemaJson" --type rust

# Check for JSON schema validation in the wallet contract
echo -e "\nChecking wallet contract JSON schema usage:"
rg -A 10 "schema" packages/wallet-contract/

Length of output: 7199

packages/wallet-contract/test/bootstrap.js (2)

1-6: LGTM: Testing dependencies are well-structured.

The combination of Sinon for mocking and Chai with Dirty-Chai for assertions provides a robust testing foundation.


11-12: LGTM: Chai plugins are properly configured.

The setup correctly integrates both dirty-chai and sinon-chai plugins.

packages/wallet-contract/src/v1/mod.rs (3)

1-2: LGTM! Clean and minimal imports.

The imports are specific and necessary for the functionality provided.


4-14: Verify schema property names.

Let's ensure the constant values match the schema definition.

✅ Verification successful

Property names match the schema definition

The constant values in the code exactly match the property names defined in the schema:

  • KEY_INDEX: "keyIndex"
  • ENCRYPTION_KEY_INDEX: "encryptionKeyIndex"
  • ENCRYPTED_METADATA: "encryptedMetadata"

These property names are correctly used throughout the codebase, including tests and schema definition.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that the property names in the code match the schema definition
# Expected: Property names in schema should match the constants

# Get the schema content and check for property names
cat packages/wallet-contract/schema/v1/wallet-contract-documents.json | jq '.definitions.tx_metadata.properties | keys'

Length of output: 173


Script:

#!/bin/bash
# Let's first check if the schema file exists and see its content
cat packages/wallet-contract/schema/v1/wallet-contract-documents.json

Length of output: 3649


Script:

#!/bin/bash
# Let's also search for any other schema files that might contain tx_metadata
fd -e json -e yaml -e yml . packages/wallet-contract/schema

Length of output: 127


Script:

#!/bin/bash
# Search for any references to these property names in the codebase
rg -i "keyIndex|encryptionKeyIndex|encryptedMetadata" packages/wallet-contract

Length of output: 2630


1-19: Security considerations for encrypted metadata handling.

Since this code handles encrypted transaction metadata in a wallet context:

  1. Ensure encryption/decryption operations are performed in a secure context
  2. Consider adding input validation for metadata size limits
  3. Implement proper access controls for metadata operations
✅ Verification successful

Let me analyze the encryption and access control related code more specifically for the wallet contract context by examining the implementation details.


Let me check the schema file that defines the validation rules for these fields.


Security review for encrypted metadata handling is satisfied

The implementation has appropriate security measures in place:

  1. The schema enforces proper validation:

    • Encrypted metadata has size limits (32-4096 bytes)
    • Required key indices with minimum value constraints
    • Strict schema validation with additionalProperties: false
  2. The metadata structure follows security best practices:

    • Uses two-factor key derivation (keyIndex + encryptionKeyIndex)
    • Enforces minimum size for encrypted data (32 bytes) ensuring proper encryption
    • Documentation indicates AES-CBC-256 encryption
  3. Access control is inherently handled through the platform's identity system via $ownerId indices.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for potential security-sensitive operations in the codebase
# Look for encryption-related code and access controls

# Search for encryption-related code
echo "Checking for encryption-related code:"
rg -l "encrypt|decrypt" --type rust

# Search for access control implementations
echo "Checking for access control implementations:"
rg -l "authorize|permission|access" --type rust

Length of output: 36967


Script:

#!/bin/bash
# Check the wallet contract implementation for encryption and access control
# Look for encryption key usage and metadata handling

# Check wallet contract implementation details
echo "Checking wallet contract implementation:"
rg -A 10 "encryptedMetadata|encryptionKeyIndex|keyIndex" packages/wallet-contract/src/

# Check for any validation or size limit implementations
echo "Checking for validation implementations:"
ast-grep --pattern 'fn validate($$$) { $$$ }' packages/wallet-contract/src/

Length of output: 1183


Script:

#!/bin/bash
# Check the schema file for metadata validation rules
echo "Checking wallet contract schema:"
cat packages/wallet-contract/schema/v1/wallet-contract-documents.json

# Look for any additional validation logic in the codebase
echo "Checking for additional validation logic:"
rg -A 5 "tx_metadata" packages/wallet-contract/src/

Length of output: 4438

Cargo.toml (2)

31-31: LGTM! The wallet-contract package addition follows workspace conventions.

The new package follows the established naming pattern and is correctly placed in the workspace members list.


31-31: Verify the wallet-contract package configuration.

Let's ensure the wallet-contract package is properly configured with necessary dependencies and metadata.

✅ Verification successful

The wallet-contract package is properly configured with consistent dependencies

The wallet-contract package has all the necessary dependencies aligned with other contract packages in the codebase:

  • Has the required metadata fields (name, description, version, edition, etc.)
  • Contains the same core dependencies as other contracts:
    • thiserror = "1.0.64"
    • platform-version (local)
    • serde_json = "1.0"
    • platform-value (local)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the wallet-contract package setup and dependencies

# Test 1: Check if the package's Cargo.toml exists and contains required fields
echo "Checking wallet-contract package configuration..."
cat packages/wallet-contract/Cargo.toml 2>/dev/null || echo "Error: wallet-contract Cargo.toml not found"

# Test 2: Verify package dependencies align with other contract packages
echo -e "\nComparing dependencies with other contract packages..."
for contract in packages/*-contract/Cargo.toml; do
    if [ -f "$contract" ]; then
        echo "=== $contract ==="
        grep "^\[dependencies\]" -A 10 "$contract" 2>/dev/null
    fi
done

Length of output: 3538

packages/wallet-contract/src/lib.rs (3)

1-7: LGTM! Clean module organization and imports.

The module structure follows good practices with separate error handling and versioned implementations.


9-17: ⚠️ Potential issue

Security concern: Verify the OWNER_ID initialization.

The OWNER_ID_BYTES is initialized to all zeros, which could be a security risk if used in production. This might allow unauthorized access if not properly updated.

Additionally, please add documentation explaining:

  1. The significance and generation method of ID_BYTES
  2. Whether OWNER_ID_BYTES should be configured during deployment

1-37: Verify implementation completeness against PR objectives.

The current implementation provides the basic contract structure but appears to be missing key functionality mentioned in the PR objectives:

  1. Storage structures for encrypted transaction metadata
  2. Username request information handling
  3. Implementation of the transition from CBOR to ProtoBuf

Please confirm if these features will be added in subsequent PRs or if they should be included here.

packages/wallet-contract/schema/v1/wallet-contract-documents.json (2)

109-116: ⚠️ Potential issue

Review uniqueUsernameIndex for potential collisions.

The current uniqueUsernameIndex only includes normalizedLabel, which might not prevent duplicate usernames across different parent domains. Consider including both normalizedLabel and normalizedParentDomainName in the unique index.

Let's check if there are any existing username-related tests:

#!/bin/bash
# Search for username-related tests
rg -i "username|duplicate|collision" --type js

Apply this diff to strengthen uniqueness constraints:

       {
         "name": "uniqueUsernameIndex",
         "properties": [
           {
             "normalizedLabel": "asc"
-          }
+          },
+          {
+            "normalizedParentDomainName": "asc"
+          }
         ]
       }

38-45: Document the encryption format in encryptedMetadata.

The description mentions AES-CBC-256 but doesn't specify:

  1. The format of the encrypted data (CBOR/ProtoBuf)
  2. The IV/nonce handling
  3. The padding scheme used

Let's check if there's any encryption-related documentation:

Consider adding detailed encryption documentation that covers:

  • The exact encryption scheme (AES-CBC-256)
  • The format of the plaintext before encryption (CBOR/ProtoBuf)
  • How the IV/nonce is handled
  • The padding scheme used

Comment on lines +14 to +16
exports.mochaHooks = {
beforeAll: loadWasmDpp,

Copy link
Contributor

@coderabbitai coderabbitai bot Nov 5, 2024

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Make beforeAll hook async to handle WebAssembly loading.

The beforeAll hook should be async to properly handle the WebAssembly loading promise.

 exports.mochaHooks = {
-  beforeAll: loadWasmDpp,
+  beforeAll: async function() {
+    await loadWasmDpp();
+  },
📝 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
exports.mochaHooks = {
beforeAll: loadWasmDpp,
exports.mochaHooks = {
beforeAll: async function() {
await loadWasmDpp();
},

Copy link
Member

Choose a reason for hiding this comment

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

loadWasmDpp is async too

Copy link
Contributor

Choose a reason for hiding this comment

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

@shumkov, thank you for pointing that out. Since loadWasmDpp is already async, assigning it directly to beforeAll is sufficient.

(^.^)?


✏️ Learnings added
Learnt from: shumkov
PR: dashpay/platform#2314
File: packages/wallet-contract/test/bootstrap.js:14-16
Timestamp: 2024-11-06T07:27:01.446Z
Learning: In `packages/wallet-contract/test/bootstrap.js`, for Mocha tests in Node.js, async functions like `loadWasmDpp` can be assigned directly to `beforeAll` without wrapping them in another async function.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Comment on lines 18 to 27
pub fn load_definitions(platform_version: &PlatformVersion) -> Result<Option<Value>, Error> {
match platform_version.system_data_contracts.withdrawals {
1 => Ok(None),
version => Err(Error::UnknownVersionMismatch {
method: "dpns_contract::load_definitions".to_string(),
known_versions: vec![1],
received: version,
}),
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix incorrect error message in load_definitions.

The error message references "dpns_contract" instead of "wallet_contract", which appears to be a copy-paste error.

-            method: "dpns_contract::load_definitions".to_string(),
+            method: "wallet_contract::load_definitions".to_string(),
📝 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
pub fn load_definitions(platform_version: &PlatformVersion) -> Result<Option<Value>, Error> {
match platform_version.system_data_contracts.withdrawals {
1 => Ok(None),
version => Err(Error::UnknownVersionMismatch {
method: "dpns_contract::load_definitions".to_string(),
known_versions: vec![1],
received: version,
}),
}
}
pub fn load_definitions(platform_version: &PlatformVersion) -> Result<Option<Value>, Error> {
match platform_version.system_data_contracts.withdrawals {
1 => Ok(None),
version => Err(Error::UnknownVersionMismatch {
method: "wallet_contract::load_definitions".to_string(),
known_versions: vec![1],
received: version,
}),
}
}

Comment on lines 18 to 37
pub fn load_definitions(platform_version: &PlatformVersion) -> Result<Option<Value>, Error> {
match platform_version.system_data_contracts.withdrawals {
1 => Ok(None),
version => Err(Error::UnknownVersionMismatch {
method: "dpns_contract::load_definitions".to_string(),
known_versions: vec![1],
received: version,
}),
}
}
pub fn load_documents_schemas(platform_version: &PlatformVersion) -> Result<Value, Error> {
match platform_version.system_data_contracts.withdrawals {
1 => v1::load_documents_schemas(),
version => Err(Error::UnknownVersionMismatch {
method: "dpns_contract::load_documents_schemas".to_string(),
known_versions: vec![1],
received: version,
}),
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add documentation and consider version handling.

Please add documentation explaining:

  1. The purpose and functionality of these contract functions
  2. The relationship with the withdrawals version
  3. Expected return values and their significance

Also, consider:

  1. Adding constants for supported versions instead of magic numbers
  2. Adding logging for version mismatches to aid debugging
+/// Version 1 is currently the only supported version
+const SUPPORTED_VERSION: u32 = 1;
+
+/// Loads contract definitions based on the platform version.
+/// Returns None for version 1 as no definitions are needed.
 pub fn load_definitions(platform_version: &PlatformVersion) -> Result<Option<Value>, Error> {
     match platform_version.system_data_contracts.withdrawals {
-        1 => Ok(None),
+        SUPPORTED_VERSION => Ok(None),
         version => Err(Error::UnknownVersionMismatch {
             method: "wallet_contract::load_definitions".to_string(),
-            known_versions: vec![1],
+            known_versions: vec![SUPPORTED_VERSION],
             received: version,
         }),
     }
 }

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +26 to +31
"keyIndex": {
"type": "integer",
"minimum": 0,
"description": "The index of the owners identity public key used to derive the encryption key.",
"position": 0
},
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add maximum bounds for key indices.

The keyIndex and encryptionKeyIndex properties should have maximum values to prevent potential resource exhaustion attacks.

Apply this diff:

       "keyIndex": {
         "type": "integer",
         "minimum": 0,
+        "maximum": 2147483647,
         "description": "The index of the owners identity public key used to derive the encryption key.",
         "position": 0
       },
       "encryptionKeyIndex": {
         "type": "integer",
         "minimum": 0,
+        "maximum": 2147483647,
         "description": "The secondary index used to derive the encryption key that is used to encrypt and decrypt encryptedData.",
         "position": 1
       },

Also applies to: 32-37

Comment on lines +77 to +84
"url": {
"position": 2,
"type": "string",
"description": "The identity verification URL to be stored.",
"maxLength": 128,
"pattern": "^https?://.*",
"format": "uri"
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Enforce HTTPS-only URLs for security.

The current URL pattern allows both HTTP and HTTPS protocols. For security reasons, especially when dealing with identity verification, only HTTPS URLs should be allowed.

Apply this diff:

       "url": {
         "position": 2,
         "type": "string",
         "description": "The identity verification URL to be stored.",
         "maxLength": 128,
-        "pattern": "^https?://.*",
+        "pattern": "^https://.*",
         "format": "uri"
       }
📝 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
"url": {
"position": 2,
"type": "string",
"description": "The identity verification URL to be stored.",
"maxLength": 128,
"pattern": "^https?://.*",
"format": "uri"
}
"url": {
"position": 2,
"type": "string",
"description": "The identity verification URL to be stored.",
"maxLength": 128,
"pattern": "^https://.*",
"format": "uri"
}

it('should be defined', async () => {
delete rawIdentityVerifyDocument.normalizedLabel;

const document = dpp.document.create(dataContract, identityId, 'domain', rawIdentityVerifyDocument);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Correct the document type in dpp.document.create

In the verifyIdentity tests, the document is being created with the type 'domain' instead of 'verifyIdentity'. This could lead to incorrect validation against the wrong document schema.

Apply this diff to fix the document type:

- const document = dpp.document.create(dataContract, identityId, 'domain', rawIdentityVerifyDocument);
+ const document = dpp.document.create(dataContract, identityId, 'verifyIdentity', rawIdentityVerifyDocument);

Please make this change in all instances within the verifyIdentity tests where 'domain' is used instead of 'verifyIdentity'.

Also applies to: 201-201, 217-217, 233-233, 248-248, 263-263, 280-280, 295-295, 310-310, 324-324

@@ -0,0 +1,5 @@
{
Copy link
Member

Choose a reason for hiding this comment

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

Why do we have these two files?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

oh, that is a mistake

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

@@ -0,0 +1,29 @@
{
"name": "@dashevo/wallet-contract",
"version": "1.4.1",
Copy link
Member

Choose a reason for hiding this comment

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

1.5.0

Copy link
Contributor Author

Choose a reason for hiding this comment

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

reset

[package]
name = "wallet-contract"
description = "Wallet data contract schema and tools"
version = "1.4.1"
Copy link
Member

Choose a reason for hiding this comment

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

1.5.0

Copy link
Contributor Author

Choose a reason for hiding this comment

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

reset

],
"additionalProperties": false
},
"identityVerify": {
Copy link
Member

Choose a reason for hiding this comment

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

What is it for? How is it related to the wallet?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In the DashPay app, when a user requests a contested username, we allow the user to specify a social media post to "prove" an identity.

If two people wanted bob each can specify a url to a social media post that says something like "I am the real bob and my identity id is Abs19....47k."

Masternode owners using DashPay can view this see this URL in the username request details page of the Username Voting screen.

This contact might not be the best place for it. If it isn't, I am not sure if it should be in a new contract or the dashpay contract.

Comment on lines +14 to +16
exports.mochaHooks = {
beforeAll: loadWasmDpp,

Copy link
Member

Choose a reason for hiding this comment

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

loadWasmDpp is async too

@HashEngineering
Copy link
Contributor Author

Thank you. I started this PR when 1.4.1 the latest version, so some of these things are out of date. I will need to rebase against 1.6-dev and then make required changes.

Copy link
Contributor

@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: 6

🧹 Outside diff range and nitpick comments (8)
packages/wallet-contract/README.md (2)

6-6: Enhance package description

The current description "JSON Contracts for Dash Wallet apps" is quite brief. Consider expanding it to include the key functionalities mentioned in the PR objectives, specifically about transaction metadata storage and username request information.

-JSON Contracts for Dash Wallet apps
+JSON Contracts for Dash Wallet apps that provide encrypted transaction metadata storage and username request information management to assist masternode voters in user verification.

29-29: Consider more formal contributing guidance

While the current contributing section is welcoming, it could be more professional and informative.

-Feel free to dive in! [Open an issue](https://github.com/dashpay/platform/issues/new/choose) or submit PRs.
+We welcome contributions! Please [open an issue](https://github.com/dashpay/platform/issues/new/choose) for bug reports or feature requests. For code contributions, please submit a pull request following our contribution guidelines.
packages/wallet-contract/src/lib.rs (1)

9-17: Add documentation for contract identifiers.

Please add documentation comments explaining:

  • The purpose and significance of these identifiers
  • How they are used in the contract
  • Why OWNER_ID_BYTES is set to zeros (if intentional)
packages/wallet-contract/schema/v1/wallet-contract-documents.json (2)

38-44: Consider adding encryption algorithm version.

Since the metadata is using AES-CBC-256 encryption, it would be beneficial to add a version field to support future encryption algorithm changes without breaking existing data.

     "encryptedMetadata": {
       "type": "array",
       "byteArray": true,
       "minItems": 32,
       "maxItems": 4096,
       "description": "encrypted metadata using AES-CBC-256",
+      "version": {
+        "type": "integer",
+        "minimum": 1,
+        "maximum": 1,
+        "description": "Version of the encryption algorithm (1 = AES-CBC-256)",
+        "position": 3
+      },
       "position": 2
     }

55-85: Consider moving identity verification to a separate contract.

Based on the PR comments discussion, this functionality might be better suited in a separate identity verification contract or the DashPay contract since:

  1. It's specifically for username dispute resolution in DashPay
  2. It's not directly related to wallet functionality
  3. It would improve separation of concerns

This would make the wallet contract more focused and maintainable.

packages/wallet-contract/test/unit/walletContract.spec.js (3)

12-26: Consider enhancing the error assertion helper function.

The expectJsonSchemaError helper could be more reusable and provide better error messages by:

  1. Adding an optional parameter for expected keyword
  2. Adding an optional parameter for expected instancePath
  3. Including the actual error message in the assertion output
-const expectJsonSchemaError = (validationResult, errorCount = 1) => {
+const expectJsonSchemaError = (validationResult, {
+  errorCount = 1,
+  expectedKeyword = null,
+  expectedPath = null
+} = {}) => {
   const errors = validationResult.getErrors();
   expect(errors)
     .to
     .have
     .length(errorCount);

   const error = validationResult.getErrors()[0];
   expect(error)
     .to
     .be
     .instanceof(JsonSchemaError);
+  
+  if (expectedKeyword) {
+    expect(error.keyword, `Expected error keyword "${expectedKeyword}" but got "${error.keyword}"`)
+      .to.equal(expectedKeyword);
+  }
+  
+  if (expectedPath) {
+    expect(error.instancePath, `Expected error path "${expectedPath}" but got "${error.instancePath}"`)
+      .to.equal(expectedPath);
+  }

   return error;
 };

40-40: Consider adding a named constant for the contract version.

The BigInt(1) value appears to be a contract version number. Consider extracting it to a named constant for better code clarity and maintainability.

+const CONTRACT_VERSION = BigInt(1);
-dataContract = dpp.dataContract.create(identityId, BigInt(1), walletContractDocumentsSchema);
+dataContract = dpp.dataContract.create(identityId, CONTRACT_VERSION, walletContractDocumentsSchema);

64-64: Consider using undefined assignment instead of delete operator.

The delete operator can impact performance. Consider using undefined assignment instead.

-delete rawTxMetadataDocument.keyIndex;
+rawTxMetadataDocument.keyIndex = undefined;

Apply similar changes to other instances where delete is used.

Also applies to: 81-81, 98-98

🧰 Tools
🪛 Biome

[error] 64-64: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 69f98e7 and 2e16647.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (15)
  • Cargo.toml (1 hunks)
  • packages/wallet-contract/.eslintrc (1 hunks)
  • packages/wallet-contract/.mocharc.yml (1 hunks)
  • packages/wallet-contract/Cargo.toml (1 hunks)
  • packages/wallet-contract/LICENSE (1 hunks)
  • packages/wallet-contract/README.md (1 hunks)
  • packages/wallet-contract/lib/systemIds.js (1 hunks)
  • packages/wallet-contract/package.json (1 hunks)
  • packages/wallet-contract/schema/v1/wallet-contract-documents.json (1 hunks)
  • packages/wallet-contract/src/error.rs (1 hunks)
  • packages/wallet-contract/src/lib.rs (1 hunks)
  • packages/wallet-contract/src/v1/mod.rs (1 hunks)
  • packages/wallet-contract/test/.eslintrc (1 hunks)
  • packages/wallet-contract/test/bootstrap.js (1 hunks)
  • packages/wallet-contract/test/unit/walletContract.spec.js (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • packages/wallet-contract/Cargo.toml
🚧 Files skipped from review as they are similar to previous changes (10)
  • Cargo.toml
  • packages/wallet-contract/.eslintrc
  • packages/wallet-contract/.mocharc.yml
  • packages/wallet-contract/LICENSE
  • packages/wallet-contract/lib/systemIds.js
  • packages/wallet-contract/package.json
  • packages/wallet-contract/src/error.rs
  • packages/wallet-contract/src/v1/mod.rs
  • packages/wallet-contract/test/.eslintrc
  • packages/wallet-contract/test/bootstrap.js
🧰 Additional context used
🪛 LanguageTool
packages/wallet-contract/README.md

[style] ~28-~28: The phrase ‘feel free to’ is used quite frequently. Consider using a less frequent alternative to set your writing apart from others and make it sound more professional.
Context: ... sh # TODO ... ## Contributing Feel free to dive in! [Open an issue](https://github...

(FEEL_FREE_TO_STYLE_ME)

🪛 Biome
packages/wallet-contract/test/unit/walletContract.spec.js

[error] 64-64: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


[error] 81-81: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


[error] 98-98: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


[error] 184-184: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


[error] 231-231: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


[error] 278-278: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

🔇 Additional comments (6)
packages/wallet-contract/src/lib.rs (2)

1-8: LGTM! Clean module structure and imports.

The module organization and imports are well-structured and appropriate for the contract's functionality.


14-14: ⚠️ Potential issue

Security concern: OWNER_ID_BYTES initialized to zeros.

Using an all-zero identifier for ownership could pose security risks if used in production. Please verify if this is intentional or a placeholder.

packages/wallet-contract/schema/v1/wallet-contract-documents.json (3)

38-45: Verify encrypted metadata size constraints.

The current size constraints for encryptedMetadata (32-4096 bytes) need verification:

  • Minimum size (32 bytes) seems appropriate for AES-CBC-256 encryption
  • Maximum size (4096 bytes) might need adjustment based on:
    • Expected payload sizes
    • Network bandwidth considerations
    • Storage costs

86-116: LGTM: Well-designed indices for efficient querying.

The indices are well-structured for:

  1. Querying by owner ID
  2. Ensuring username uniqueness
  3. Supporting hierarchical domain queries

60-67: Add validation for homograph attack mitigation.

While the schema includes patterns to prevent homograph attacks, consider adding server-side validation to ensure:

  1. The replacement of "o", "i", and "l" with "0" and "1" is correctly applied
  2. The normalization process is consistent across the platform
✅ Verification successful

Let's search for any normalization, homograph prevention, or label transformation implementations in the codebase to verify if there's consistent handling of these cases.


Let's search for the implementation of label normalization and validation to verify if homograph attack mitigation is properly implemented.


Let's search for the actual implementation of homograph attack mitigation and its tests to verify if it's properly implemented and validated.


Based on the search results, I can now provide a definitive response about the homograph attack mitigation implementation:

Server-side validation for homograph attack mitigation is properly implemented.

The codebase shows comprehensive protection through:

  1. Schema validation in normalizedLabel and normalizedParentDomainName fields with pattern ^[a-hj-km-np-z0-9][a-hj-km-np-z0-9-]{0,61}[a-hj-km-np-z0-9]$ that explicitly excludes homograph-prone characters.

  2. Server-side implementation in convert_to_homograph_safe_chars() function that:

    • Converts input to lowercase
    • Replaces 'o' with '0'
    • Replaces 'l' and 'i' with '1'
  3. Data trigger validation in dpns/v0/mod.rs that enforces the normalized form matches the conversion rules by comparing normalized_label with convert_to_homograph_safe_chars(label).

  4. Consistent implementation across platform components including domain registration, queries, and validation.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other username normalization implementations
rg -A 5 "normaliz(e|ing) (username|label)"

Length of output: 44


Script:

#!/bin/bash
# Search for any normalization related functions or implementations
rg -A 5 "normaliz" --type ts --type js

# Search for homograph attack prevention patterns
rg -A 5 "homograph"

# Search for label transformation or validation patterns
rg -A 5 "label.*transform|transform.*label"

# Look for any string validation or sanitization patterns
ast-grep --pattern 'function $_ ($$$) {
  $$$
  .replace(/[oil]/g, $$$)
  $$$
}'

Length of output: 197038


Script:

#!/bin/bash
# Search for label normalization or transformation implementations
ast-grep --pattern 'function $_ ($$$) {
  $$$
  let $_ = $_.toLowerCase()
  $$$
}'

# Look for any string conversion functions
ast-grep --pattern 'function convertToHomographSafeChars($$$) {
  $$$
}'

# Search for any label validation functions
rg -A 5 "validateLabel|validateNormalizedLabel"

# Search for any test cases related to label normalization
rg -A 5 "test.*label.*normalization|test.*normalized.*label"

Length of output: 102503


Script:

#!/bin/bash
# Search for the implementation of homograph safe conversion
rg -A 10 "convert_to_homograph_safe_chars"

# Look for any tests related to homograph attack prevention
rg -A 5 "test.*homograph|homograph.*test"

# Search for data trigger validation implementations
rg -A 10 "data_triggers.*dpns"

Length of output: 162228

packages/wallet-contract/test/unit/walletContract.spec.js (1)

186-186: Fix incorrect document type in verifyIdentity tests.

This issue was previously identified. The document type should be 'verifyIdentity' instead of 'domain'.

Also applies to: 201-201, 216-216, 233-233, 248-248, 263-263, 280-280, 295-295, 310-310, 324-324

# Wallet Contract

[![Build Status](https://github.com/dashpay/platform/actions/workflows/release.yml/badge.svg)](https://github.com/dashpay/platform/actions/workflows/release.yml)
[![NPM version](https://img.shields.io/npm/v/@dashevo/dpns-contract.svg?style=flat-square)](https://npmjs.org/package/@dashevo/dpns-contract)
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix incorrect NPM badge package reference

The NPM badge is currently referencing @dashevo/dpns-contract instead of @dashevo/wallet-contract.

-[![NPM version](https://img.shields.io/npm/v/@dashevo/dpns-contract.svg?style=flat-square)](https://npmjs.org/package/@dashevo/dpns-contract)
+[![NPM version](https://img.shields.io/npm/v/@dashevo/wallet-contract.svg?style=flat-square)](https://npmjs.org/package/@dashevo/wallet-contract)
📝 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
[![NPM version](https://img.shields.io/npm/v/@dashevo/dpns-contract.svg?style=flat-square)](https://npmjs.org/package/@dashevo/dpns-contract)
[![NPM version](https://img.shields.io/npm/v/@dashevo/wallet-contract.svg?style=flat-square)](https://npmjs.org/package/@dashevo/wallet-contract)

Comment on lines +17 to +19
```sh
npm install @dashevo/wallet-contract
```
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

Package installation command needs to be updated

The package @dashevo/wallet-contract is not published on npm registry yet, despite being defined in package.json. The installation command in the README won't work for users. This needs to be either:

  • Published to npm registry before the documentation is updated, or
  • Updated with alternative installation instructions (e.g., installing from GitHub repository)
🔗 Analysis chain

Verify package installation command

The installation command references a package that might not be published yet.


Let me check the package.json to understand if this is a local package that needs to be published.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify if the package exists on npm registry
# Test: Check if the package exists and get its details
npm view @dashevo/wallet-contract --json || echo "Package not found"

Length of output: 1022


Script:

#!/bin/bash
# Check package.json in the wallet-contract directory
cat packages/wallet-contract/package.json

Length of output: 779

Comment on lines 28 to 37
pub fn load_documents_schemas(platform_version: &PlatformVersion) -> Result<Value, Error> {
match platform_version.system_data_contracts.withdrawals {
1 => v1::load_documents_schemas(),
version => Err(Error::UnknownVersionMismatch {
method: "dpns_contract::load_documents_schemas".to_string(),
known_versions: vec![1],
received: version,
}),
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling for schema loading.

The function should handle potential errors from v1::load_documents_schemas(). Consider adding error context to help with debugging.

 pub fn load_documents_schemas(platform_version: &PlatformVersion) -> Result<Value, Error> {
     match platform_version.system_data_contracts.withdrawals {
-        1 => v1::load_documents_schemas(),
+        1 => v1::load_documents_schemas().map_err(|e| Error::InvalidSchemaJson {
+            method: "wallet_contract::load_documents_schemas".to_string(),
+            error: e.to_string(),
+        }),
         version => Err(Error::UnknownVersionMismatch {
             method: "wallet_contract::load_documents_schemas".to_string(),
             known_versions: vec![1],

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines 112 to 125
it('should be not shorter than 32 bytes', async () => {
rawTxMetadataDocument.encryptedMetadata = crypto.randomBytes(31);

const document = dpp.document.create(dataContract, identityId, 'txMetadata', rawTxMetadataDocument);
const validationResult = document.validate(dpp.protocolVersion);
const error = expectJsonSchemaError(validationResult);

expect(error.keyword)
.to
.equal('maxItems');
expect(error.instancePath)
.to
.equal('/encryptedMetadata');
});
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix incorrect error assertions in byte length tests.

The tests for byte length constraints are using maxItems keyword, which is incorrect for byte array length validation. The schema likely uses minBytes and maxBytes or similar keywords.

 expect(error.keyword)
     .to
-    .equal('maxItems');
+    .equal('minBytes');
 expect(error.instancePath)
     .to
     .equal('/encryptedMetadata');

Apply similar fix to the maxBytes test.

Also applies to: 127-140

Comment on lines 292 to 305
it('should be less than 128 chars', async () => {
rawIdentityVerifyDocument.normalizedParentDomainName = 'a'.repeat(129);

const document = dpp.document.create(dataContract, identityId, 'domain', rawIdentityVerifyDocument);
const validationResult = document.validate(dpp.protocolVersion);
const error = expectJsonSchemaError(validationResult, 2);

expect(error.keyword)
.to
.equal('pattern');
expect(error.instancePath)
.to
.equal('/url');
});
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix incorrect property in url length test.

The test for url length is incorrectly modifying normalizedParentDomainName instead of url.

-rawIdentityVerifyDocument.normalizedParentDomainName = 'a'.repeat(129);
+rawIdentityVerifyDocument.url = 'a'.repeat(129);
📝 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
it('should be less than 128 chars', async () => {
rawIdentityVerifyDocument.normalizedParentDomainName = 'a'.repeat(129);
const document = dpp.document.create(dataContract, identityId, 'domain', rawIdentityVerifyDocument);
const validationResult = document.validate(dpp.protocolVersion);
const error = expectJsonSchemaError(validationResult, 2);
expect(error.keyword)
.to
.equal('pattern');
expect(error.instancePath)
.to
.equal('/url');
});
it('should be less than 128 chars', async () => {
rawIdentityVerifyDocument.url = 'a'.repeat(129);
const document = dpp.document.create(dataContract, identityId, 'domain', rawIdentityVerifyDocument);
const validationResult = document.validate(dpp.protocolVersion);
const error = expectJsonSchemaError(validationResult, 2);
expect(error.keyword)
.to
.equal('pattern');
expect(error.instancePath)
.to
.equal('/url');
});

Copy link
Contributor

@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: 2

🧹 Outside diff range and nitpick comments (8)
packages/wallet-contract/Cargo.toml (1)

9-13: Consider standardizing dependency specifications.

A few suggestions to improve dependency management:

  1. Consider using workspace-level version management for thiserror and serde_json
  2. The serde_json dependency might need specific features enabled for contract serialization
  3. Consider adding typical testing dependencies (e.g., rstest, mockall) for contract testing

Example improvement:

 [dependencies]
-thiserror = "1.0.64"
+thiserror.workspace = true
 platform-version = { path = "../rs-platform-version" }
-serde_json = { version = "1.0" }
+serde_json = { workspace = true, features = ["preserve_order"] }
 platform-value = { path = "../rs-platform-value" }

+[dev-dependencies]
+rstest.workspace = true
+mockall.workspace = true
packages/wallet-contract/README.md (1)

27-29: Enhance contributing guidelines

Consider expanding the contributing section with more specific guidance:

 ## Contributing
 
-Feel free to dive in! [Open an issue](https://github.com/dashpay/platform/issues/new/choose) or submit PRs.
+We welcome contributions! Here's how you can help:
+
+1. Check existing issues or create a new one to discuss your ideas
+2. Fork the repository and create a feature branch
+3. Write tests for any new functionality
+4. Ensure your code follows our coding standards
+5. Submit a pull request with a clear description of your changes
+
+For more details, see our [contribution guidelines](../CONTRIBUTING.md).
🧰 Tools
🪛 LanguageTool

[style] ~28-~28: The phrase ‘feel free to’ is used quite frequently. Consider using a less frequent alternative to set your writing apart from others and make it sound more professional.
Context: ... sh # TODO ... ## Contributing Feel free to dive in! [Open an issue](https://github...

(FEEL_FREE_TO_STYLE_ME)

packages/wallet-contract/src/lib.rs (2)

9-12: Document the significance of ID_BYTES.

Please add documentation explaining:

  • The purpose and significance of this byte sequence
  • How it was generated
  • Any implications for changing it

18-27: Extract common version handling logic.

Both functions share similar version handling logic. Consider extracting this into a common helper function to improve maintainability and reduce code duplication.

+/// Checks if the given version is supported
+fn check_version(version: u32, method: &str) -> Result<(), Error> {
+    const SUPPORTED_VERSION: u32 = 1;
+    if version != SUPPORTED_VERSION {
+        return Err(Error::UnknownVersionMismatch {
+            method: method.to_string(),
+            known_versions: vec![SUPPORTED_VERSION],
+            received: version,
+        });
+    }
+    Ok(())
+}

 pub fn load_definitions(platform_version: &PlatformVersion) -> Result<Option<Value>, Error> {
-    match platform_version.system_data_contracts.withdrawals {
-        1 => Ok(None),
-        version => Err(Error::UnknownVersionMismatch {
-            method: "wallet_contract::load_definitions".to_string(),
-            known_versions: vec![1],
-            received: version,
-        }),
-    }
+    check_version(platform_version.system_data_contracts.withdrawals, 
+        "wallet_contract::load_definitions")?;
+    Ok(None)
 }

 pub fn load_documents_schemas(platform_version: &PlatformVersion) -> Result<Value, Error> {
-    match platform_version.system_data_contracts.withdrawals {
-        1 => v1::load_documents_schemas(),
-        version => Err(Error::UnknownVersionMismatch {
-            method: "wallet_contract::load_documents_schemas".to_string(),
-            known_versions: vec![1],
-            received: version,
-        }),
-    }
+    check_version(platform_version.system_data_contracts.withdrawals,
+        "wallet_contract::load_documents_schemas")?;
+    v1::load_documents_schemas()
 }

Also applies to: 28-37

packages/wallet-contract/test/unit/walletContract.spec.js (4)

28-48: Consider adding more comprehensive contract validation.

While the basic contract creation test is good, consider adding tests for:

  • Schema validation
  • Contract version validation
  • Invalid identityId scenarios

64-64: Consider using undefined assignment instead of delete operator.

For better performance, consider replacing delete operations with undefined assignments:

-delete rawTxMetadataDocument.keyIndex;
+rawTxMetadataDocument.keyIndex = undefined;

Apply similar changes to other delete operations in the txMetadata tests.

Also applies to: 81-81, 98-98

🧰 Tools
🪛 Biome

[error] 64-64: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


184-184: Replace delete operations in verifyIdentity tests.

For better performance, consider replacing delete operations with undefined assignments:

-delete rawIdentityVerifyDocument.normalizedLabel;
+rawIdentityVerifyDocument.normalizedLabel = undefined;

Apply similar changes to other delete operations in the verifyIdentity tests.

Also applies to: 231-231, 278-278

🧰 Tools
🪛 Biome

[error] 184-184: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


198-211: Enhance pattern validation tests.

The pattern validation tests could be more specific:

  1. Add test cases with specific invalid characters
  2. Test edge cases (e.g., spaces at start/end)
  3. Document the expected pattern in test descriptions

Example enhancement:

it('should not allow special characters except hyphen and underscore', async () => {
  rawIdentityVerifyDocument.normalizedLabel = 'invalid@label';
  // ... rest of the test
});

Also applies to: 260-273, 307-320

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 2e16647 and c265209.

📒 Files selected for processing (5)
  • packages/wallet-contract/Cargo.toml (1 hunks)
  • packages/wallet-contract/README.md (1 hunks)
  • packages/wallet-contract/package.json (1 hunks)
  • packages/wallet-contract/src/lib.rs (1 hunks)
  • packages/wallet-contract/test/unit/walletContract.spec.js (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/wallet-contract/package.json
🧰 Additional context used
🪛 LanguageTool
packages/wallet-contract/README.md

[style] ~28-~28: The phrase ‘feel free to’ is used quite frequently. Consider using a less frequent alternative to set your writing apart from others and make it sound more professional.
Context: ... sh # TODO ... ## Contributing Feel free to dive in! [Open an issue](https://github...

(FEEL_FREE_TO_STYLE_ME)

🪛 Biome
packages/wallet-contract/test/unit/walletContract.spec.js

[error] 64-64: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


[error] 81-81: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


[error] 98-98: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


[error] 184-184: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


[error] 231-231: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


[error] 278-278: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

🔇 Additional comments (6)
packages/wallet-contract/Cargo.toml (1)

1-8: LGTM! Package metadata is well-structured.

The package metadata follows Rust conventions and aligns with the project's versioning (1.5.0).

Let's verify the version alignment with other packages:

packages/wallet-contract/src/lib.rs (2)

1-8: LGTM! Well-structured module organization.

The module declarations and imports are clean, following Rust best practices with specific imports and clear module organization.


14-14: ⚠️ Potential issue

Verify the zero initialization of OWNER_ID_BYTES.

An all-zero identifier in a production system seems unusual and could potentially cause security issues. Please verify if this is intentional or if it should be initialized with a specific value.

packages/wallet-contract/test/unit/walletContract.spec.js (3)

1-27: LGTM! Well-structured test setup.

The test setup and helper functions are well-organized. The expectJsonSchemaError helper function is particularly well-designed for reuse across test cases.


127-140: Fix incorrect assertion in maxBytes test.

The test for maximum byte length is using the wrong assertion keyword.


186-186: Fix incorrect document type in verifyIdentity tests.

The document type should be 'verifyIdentity' instead of 'domain'.

Also applies to: 201-201, 216-216, 233-233, 248-248, 263-263, 280-280, 295-295, 310-310, 324-324

Comment on lines +21 to +25
## Usage

```sh
# TODO ...
```
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Replace TODO with comprehensive documentation

Based on the contract's purposes, please replace the TODO with detailed documentation covering:

-## Usage
-
-```sh
-# TODO ...
-```
+## Usage
+
+### Transaction Metadata Storage
+
+```javascript
+// Example: Storing encrypted transaction metadata
+const metadata = {
+  txId: "your-tx-id",
+  encryptedData: "encrypted-payload"
+};
+
+await walletContract.storeTransactionMetadata(metadata);
+
+// Example: Retrieving transaction metadata
+const storedMetadata = await walletContract.getTransactionMetadata(txId);
+```
+
+### Username Request Management
+
+```javascript
+// Example: Storing username request information
+const requestInfo = {
+  username: "alice",
+  normalizedLabel: "alice",
+  parentDomain: "dash",
+  socialMediaUrl: "https://twitter.com/alice/status/123"
+};
+
+await walletContract.storeUsernameRequest(requestInfo);
+
+// Example: Retrieving username requests for voting
+const requests = await walletContract.getUsernameRequests();
+```
+
+### Error Handling
+
+```javascript
+try {
+  await walletContract.storeTransactionMetadata(metadata);
+} catch (error) {
+  if (error.code === 'INVALID_METADATA') {
+    // Handle validation errors
+  }
+  // Handle other errors
+}

<!-- This is an auto-generated comment by CodeRabbit -->

[![Build Status](https://github.com/dashpay/platform/actions/workflows/release.yml/badge.svg)](https://github.com/dashpay/platform/actions/workflows/release.yml)
[![NPM version](https://img.shields.io/npm/v/@dashevo/wallet-contract.svg?style=flat-square)](https://npmjs.org/package/@dashevo/wallet-contract)

JSON Contracts for Dash Wallet apps
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance the package description

The current description is too brief. Consider expanding it to better reflect the contract's key functionalities:

-JSON Contracts for Dash Wallet apps
+JSON Contracts for Dash Wallet apps, providing secure storage for encrypted transaction metadata and username request information to support masternode voting processes.
📝 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
JSON Contracts for Dash Wallet apps
JSON Contracts for Dash Wallet apps, providing secure storage for encrypted transaction metadata and username request information to support masternode voting processes.

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