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

Schema and Form ADO #591

Open
wants to merge 20 commits into
base: main
Choose a base branch
from
Open

Schema and Form ADO #591

wants to merge 20 commits into from

Conversation

mdjakovic0920
Copy link
Contributor

@mdjakovic0920 mdjakovic0920 commented Oct 29, 2024

Motivation

1. Schema ADO

Schema ADO stores a schema and has a query that can validate a data against the schema

2. Form ADO

Ado that can take submissions against a form. Form will be a schema ado that can validate submission against a valid json schema.

Implementation

1. Schema ADO

#[andr_instantiate]
#[cw_serde]
pub struct InstantiateMsg {
    pub schema_json_string: String,
}

#[andr_exec]
#[cw_serde]
pub enum ExecuteMsg {
    UpdateSchema { new_schema_json_string: String },
}

#[andr_query]
#[cw_serde]
#[derive(QueryResponses)]
pub enum QueryMsg {
    #[returns(ValidateDataResponse)]
    ValidateData { data: String },
    #[returns(GetSchemaResponse)]
    GetSchema {},
}

2. Form ADO

#[andr_instantiate]
#[cw_serde]
pub struct InstantiateMsg {
    pub schema_ado_address: AndrAddr, // Address of the schema ADO
    pub authorized_addresses_for_submission: Option<Vec<AndrAddr>>,
    pub form_config: FormConfig,
    pub custom_key_for_notifications: Option<String>,
}

#[cw_serde]
pub struct FormConfig {
    pub start_time: Option<Expiry>,       // Optional start time for form
    pub end_time: Option<Expiry>,         // Optional end time for form
    pub allow_multiple_submissions: bool, // Whether multiple submissions are allowed
    pub allow_edit_submission: bool,      // Whether users can edit their submission
}

#[andr_exec]
#[cw_serde]
pub enum ExecuteMsg {
    SubmitForm {
        data: String,
    },
    DeleteSubmission {
        submission_id: u64,
        wallet_address: AndrAddr,
    },
    EditSubmission {
        submission_id: u64,
        wallet_address: AndrAddr,
        data: String,
    },
    OpenForm {},
    CloseForm {},
}

#[andr_query]
#[cw_serde]
#[derive(QueryResponses)]
pub enum QueryMsg {
    #[returns(GetSchemaResponse)]
    GetSchema {},
    #[returns(GetAllSubmissionsResponse)]
    GetAllSubmissions {},
    #[returns(GetSubmissionResponse)]
    GetSubmission {
        submission_id: u64,
        wallet_address: AndrAddr,
    },
    #[returns(GetFormStatusResponse)]
    GetFormStatus {},
}

Testing

Unit test case are added.

Version Changes

Schema ADO: 1.0.0
Form ADO: 1.0.0

Notes

https://hackmd.io/@ECR5wF6JRgCIEKiGLzIABQ/SklY1wtHJJl

Future work

Form ADO: Want to attach custom key in response events provided by user in instantiatiate so that he can build his own service/telegram bot that can send push notification on each submission. This will go in response.add_event().

Summary by CodeRabbit

  • New Features

    • Introduced a comprehensive framework for managing forms, including instantiation, execution, and querying capabilities.
    • Added schema management functionalities, allowing for updates and validation of data against defined schemas.
    • Implemented new dependencies to enhance project capabilities.
    • Added command aliases to streamline development processes.
  • Documentation

    • New configuration files and examples to facilitate easier development and testing processes.
  • Tests

    • Comprehensive unit tests for form management and schema validation, ensuring robust error handling and state management.

Copy link
Contributor

coderabbitai bot commented Oct 29, 2024

Walkthrough

The pull request introduces significant changes across multiple files within the Andromeda project. Key modifications include the addition of new dependencies in Cargo.toml, the creation of new modules and files for managing forms and schemas, and enhancements to testing capabilities. New smart contract functionalities are implemented for instantiation, execution, and querying of forms and schemas, supported by robust error handling and validation mechanisms. Additionally, mock implementations and testing utilities are introduced to facilitate the testing of these new features.

Changes

File Path Change Summary
Cargo.toml Added dependencies: jsonschema-valid = { version = "0.5.2" }, serde_json = { version = "1.0.128" }. Commented-out entry for contracts/automation/*.
contracts/data-storage/andromeda-form/.cargo/config Introduced command aliases: wasm, unit-test, schema.
contracts/data-storage/andromeda-form/Cargo.toml New package andromeda-form declared with version 0.1.0-beta. Added dependencies and features.
contracts/data-storage/andromeda-form/examples/schema.rs New file created with API schema definition using write_api!.
contracts/data-storage/andromeda-form/src/contract.rs Introduced contract lifecycle functions: instantiate, execute, query, and migrate.
contracts/data-storage/andromeda-form/src/execute.rs New file with functions to handle execution messages related to form submissions.
contracts/data-storage/andromeda-form/src/lib.rs Added new modules: contract, execute, query, state, testing.
contracts/data-storage/andromeda-form/src/mock.rs Introduced mock implementation for testing the form contract.
contracts/data-storage/andromeda-form/src/query.rs New file with functions for querying form-related data.
contracts/data-storage/andromeda-form/src/state.rs New module for managing submission-related data with indexing.
contracts/data-storage/andromeda-form/src/testing/mock.rs Mock functions for testing the Andromeda form contract.
contracts/data-storage/andromeda-form/src/testing/mod.rs New modules: mock, mock_querier, tests.
contracts/data-storage/andromeda-form/src/testing/tests.rs Comprehensive unit tests for form contract functionality.
contracts/modules/andromeda-schema/.cargo/config New configuration file with command aliases.
contracts/modules/andromeda-schema/Cargo.toml New package andromeda-schema declared with dependencies and features.
contracts/modules/andromeda-schema/examples/schema.rs New file for schema API definition using write_api!.
contracts/modules/andromeda-schema/src/contract.rs Introduced contract lifecycle functions for schema management.
contracts/modules/andromeda-schema/src/execute.rs New file for handling execution messages related to schema operations.
contracts/modules/andromeda-schema/src/lib.rs Added new modules: contract, execute, query, state, testing.
contracts/modules/andromeda-schema/src/mock.rs Mock implementation for testing the schema module.
contracts/modules/andromeda-schema/src/query.rs New file for querying schema-related data.
contracts/modules/andromeda-schema/src/state.rs New constant SCHEMA for storing JSON schema data.
contracts/modules/andromeda-schema/src/testing/mock.rs Mock testing utilities for schema module.
contracts/modules/andromeda-schema/src/testing/mod.rs New modules: mock, tests.
contracts/modules/andromeda-schema/src/testing/tests.rs Test cases for validating schema instantiation and updates.
packages/andromeda-data-storage/src/form.rs New data structures and message types for managing forms.
packages/andromeda-data-storage/src/lib.rs Added new module form.
packages/andromeda-modules/src/lib.rs Added new module schema.
packages/andromeda-modules/src/schema.rs New data structures and message types for handling schema operations.

Possibly related PRs

  • feat: Include ADOBase Version in Schema #574: The changes in this PR involve updating the Cargo.toml file to include the ADOBase version in the schema, which relates to dependency management similar to the updates made in the main PR's Cargo.toml.
  • Version changed to 0.x.0-beta for undeployed contracts #650: This PR focuses on changing the versioning scheme for undeployed contracts, which is relevant to the overall management of package versions in the Cargo.toml files, aligning with the dependency updates in the main PR.
  • Added Discarded state to cf contract #715: The addition of a new "DISCARDED" state in the crowdfund contract may not directly relate to the dependency changes but reflects ongoing modifications in the contract structure that could be influenced by the overall project management and versioning practices highlighted in the main PR.

Suggested reviewers

  • joemonem
  • crnbarr93

🐰 In the garden, new seeds we sow,
With forms and schemas, our project will grow.
Dependencies added, testing in play,
Andromeda's bright future starts today!
Hops and jumps, let the code run free,
A world of data, for you and me! 🌼


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 generate docstrings to generate docstrings for this PR. (Experiment)
  • @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: 36

🧹 Outside diff range and nitpick comments (24)
contracts/data-storage/andromeda-form/src/testing/mod.rs (1)

1-3: LGTM! Consider adding module documentation.

The module organization follows good testing practices by separating mock implementations, custom queriers, and tests into distinct modules. This structure promotes better test isolation and maintainability.

Consider adding module-level documentation comments to describe the purpose of each module:

+//! Testing utilities for the Form ADO contract
+
+/// Mock implementations for testing Form ADO functionality
 mod mock;
+/// Custom mock querier for handling schema-related requests
 mod mock_querier;
+/// Integration and unit tests for the Form ADO contract
 mod tests;
contracts/modules/andromeda-schema/src/state.rs (1)

1-4: Add documentation for schema format and validation rules.

The implementation looks correct, but could benefit from additional documentation:

  • Document the expected JSON schema format
  • Specify validation rules and constraints
  • Consider adding examples of valid schemas

Add documentation above the SCHEMA constant:

+/// Stores the JSON schema used for validating form submissions.
+/// The schema should follow the JSON Schema specification (https://json-schema.org/).
+/// 
+/// # Example
+/// ```json
+/// {
+///   "type": "object",
+///   "properties": {
+///     "name": { "type": "string" },
+///     "age": { "type": "integer", "minimum": 0 }
+///   }
+/// }
+/// ```
pub const SCHEMA: Item<JSON> = Item::new("schema");
contracts/data-storage/andromeda-form/.cargo/config (1)

1-4: LGTM with suggestions for production improvements.

The cargo aliases are well-structured and follow CosmWasm conventions. Consider these production-ready enhancements:

[alias]
-wasm = "build --release --target wasm32-unknown-unknown"
+wasm = "build --release --target wasm32-unknown-unknown --locked"
-unit-test = "test --lib"
+unit-test = "test --lib --no-fail-fast"
schema = "run --example schema"

The changes:

  1. Added --locked to ensure reproducible builds using Cargo.lock
  2. Added --no-fail-fast to run all tests even if some fail, helpful for CI/CD
contracts/modules/andromeda-schema/src/lib.rs (1)

1-4: Consider adding module-level documentation.

The core module structure looks good and follows best practices. However, adding module-level documentation (//! comments) would improve maintainability by explaining the purpose of each module:

  • contract: Entry points for contract instantiation and message handling
  • execute: Implementation of execute messages for schema operations
  • query: Implementation of query messages for schema validation
  • state: State management and storage logic
+//! Schema ADO implementation for storing and validating JSON schemas
+
 pub mod contract;
 pub mod execute;
 pub mod query;
 pub mod state;
packages/andromeda-modules/src/schema.rs (1)

10-14: Consider schema update implications

The UpdateSchema operation needs additional considerations:

  1. How will existing data be validated against the new schema?
  2. Should there be access control for schema updates?
  3. Consider adding version tracking for schema changes
contracts/modules/andromeda-schema/src/query.rs (2)

19-21: Consider using borrowed str for better efficiency.

Instead of using data.as_str(), you can directly use &data since String implements AsRef.

-    let data_instance = from_str(data.as_str()).map_err(|e| ContractError::CustomError {
+    let data_instance = from_str(&data).map_err(|e| ContractError::CustomError {

9-43: Add documentation for public functions.

Both public functions lack documentation. Consider adding doc comments to explain their purpose, parameters, and return values.

Add documentation like this:

/// Retrieves the stored schema from storage.
/// 
/// # Arguments
/// 
/// * `storage` - The storage to read from
/// 
/// # Returns
/// 
/// * `Result<GetSchemaResponse, ContractError>` - The schema or an error
pub fn get_schema(storage: &dyn Storage) -> Result<GetSchemaResponse, ContractError>

/// Validates the provided JSON data against the stored schema.
/// 
/// # Arguments
/// 
/// * `storage` - The storage to read the schema from
/// * `data` - The JSON string to validate
/// 
/// # Returns
/// 
/// * `Result<ValidateDataResponse, ContractError>` - Validation result or an error
pub fn validate_data(storage: &dyn Storage, data: String) -> Result<ValidateDataResponse, ContractError>
Cargo.toml (1)

61-61: Consider updating jsonschema-valid dependency.

The dependency is functional but relatively old. Consider updating to a newer version for potential bug fixes and improvements.

contracts/modules/andromeda-schema/src/testing/mock.rs (1)

18-30: Add input validation and improve documentation.

While the initialization logic is correct, consider these improvements:

  1. Add validation for the schema_json_string format
  2. Document the expected schema format
  3. Make the assertion message more descriptive

Apply this diff:

 pub fn proper_initialization(schema_json_string: String) -> (MockDeps, MessageInfo) {
+    // Validate schema JSON format
+    serde_json::from_str::<serde_json::Value>(&schema_json_string)
+        .expect("Invalid JSON schema format");
+
     let mut deps = mock_dependencies_custom(&[]);
     let info = mock_info("creator", &[]);
     let msg = InstantiateMsg {
         kernel_address: MOCK_KERNEL_CONTRACT.to_string(),
         owner: None,
         schema_json_string,
     };
     let env = mock_env();
     let res = instantiate(deps.as_mut(), env, info.clone(), msg).unwrap();
-    assert_eq!(0, res.messages.len());
+    assert_eq!(
+        0,
+        res.messages.len(),
+        "Expected no messages during initialization"
+    );
     (deps, info)
 }

Also add this documentation above the function:

/// Initializes a mock Schema ADO contract with the provided JSON schema.
///
/// # Arguments
///
/// * `schema_json_string` - A valid JSON string representing the schema structure.
///   Example format:
///   {
///     "type": "object",
///     "properties": {
///       "name": {"type": "string"},
///       "age": {"type": "integer"}
///     }
///   }
contracts/modules/andromeda-schema/src/mock.rs (2)

15-36: Consider using better error handling in instantiate method.

The unwrap() on line 34 could be replaced with proper error handling to make the mock more robust for testing error scenarios.

-            .unwrap();
+            .map_err(|e| format!("Failed to instantiate schema contract: {}", e))?;

66-81: LGTM! Consider documenting test usage patterns.

The helper functions are well-implemented. Consider adding documentation comments with example usage patterns to help other developers write tests effectively.

Add documentation like:

/// Creates a mock schema contract for testing.
/// 
/// # Example
/// ```
/// let contract = mock_andromeda_schema();
/// let code_id = app.store_code(contract);
/// ```
pub fn mock_andromeda_schema() -> Box<dyn Contract<Empty>> {
contracts/data-storage/andromeda-form/src/testing/mock_querier.rs (1)

18-49: Consider enhancing documentation for test configuration.

While the function implementation is correct, consider documenting:

  • The purpose of the hardcoded values in InstantiateMsg
  • The relationship between MOCK_CONTRACT_ADDR and contract_balance
 /// Alternative to `cosmwasm_std::testing::mock_dependencies` that allows us to respond to custom queries.
 ///
 /// Automatically assigns a kernel address as MOCK_KERNEL_CONTRACT.
+/// 
+/// # Arguments
+/// * `contract_balance` - Initial balance for the MOCK_CONTRACT_ADDR
+///
+/// The function initializes an ADO contract with:
+/// * ado_type: "form" - Identifies this as a form contract
+/// * ado_version: "test" - Test version identifier
+/// * kernel_address: MOCK_KERNEL_CONTRACT - Standard test kernel address
contracts/data-storage/andromeda-form/src/mock.rs (1)

156-186: Simplify query methods by removing unnecessary intermediates.

The query methods could be more concise while maintaining readability.

 pub fn query_schema(&self, app: &mut MockApp) -> GetSchemaResponse {
     let msg = QueryMsg::GetSchema {};
-    let res: GetSchemaResponse = self.query(app, msg);
-    res
+    self.query(app, msg)
 }
contracts/modules/andromeda-schema/src/execute.rs (1)

29-33: Ensure consistency in response construction

When combining the res response with action_response, verify that attributes, messages, and events are correctly merged without duplication or conflict. This ensures clear and accurate execution results.

packages/andromeda-data-storage/src/form.rs (3)

9-12: Consider adding comments to all fields in InstantiateMsg for clarity

The field schema_ado_address includes a comment, but the other fields do not. Adding comments to authorized_addresses_for_submission, form_config, and custom_key_for_notifications would enhance code readability and maintain consistency.


17-20: Add comments to fields in FormConfig for consistency

To maintain consistency and improve readability, consider adding comments to each field in FormConfig, similar to those in InstantiateMsg.


74-79: Add comments to fields in SubmissionInfo for clarity

Adding comments to the fields submission_id, wallet_address, and data in SubmissionInfo would improve code understanding and maintain consistency with other structs.

contracts/modules/andromeda-schema/src/testing/tests.rs (1)

303-310: Ensure consistent schema formatting in assertions

In the test_query_schema function, the expected schema string in the assert_eq! macro is a single-line string, which can be hard to read and maintain. Consider formatting the expected schema with proper indentation and line breaks to improve readability.

Refactor the assertion for better readability:

 assert_eq!(
     schema,
-    "{\"$schema\":\"http://json-schema.org/draft-07/schema#\",\"additionalProperties\":false,\"properties\":{\"kernel_address\":{\"type\":\"string\"},\"owner\":{\"type\":[\"string\",\"null\"]},\"schema_json_string\":{\"type\":\"string\"}},\"required\":[\"kernel_address\",\"schema_json_string\"],\"title\":\"InstantiateMsg\",\"type\":\"object\"}".to_string()
+    serde_json::json!({
+        "$schema": "http://json-schema.org/draft-07/schema#",
+        "additionalProperties": false,
+        "properties": {
+            "kernel_address": { "type": "string" },
+            "owner": { "type": ["string", "null"] },
+            "schema_json_string": { "type": "string" }
+        },
+        "required": ["kernel_address", "schema_json_string"],
+        "title": "InstantiateMsg",
+        "type": "object"
+    })
+    .to_string()
 );

This makes the expected value more readable and easier to maintain.

contracts/data-storage/andromeda-form/src/execute.rs (3)

370-376: Enhance error handling in milliseconds_from_expiration

The milliseconds_from_expiration function currently handles only Expiration::AtTime and returns a generic error for other variants. Consider handling other expiration variants or providing a more descriptive error message to improve clarity.

For example:

 pub fn milliseconds_from_expiration(expiration: Expiration) -> Result<Milliseconds, ContractError> {
     match expiration {
         Expiration::AtTime(time) => Ok(Milliseconds::from_nanos(time.nanos())),
+        Expiration::Never {} => Err(ContractError::CustomError {
+            msg: "Expiration is set to never expire.".to_string(),
+        }),
+        Expiration::AtHeight(height) => Err(ContractError::CustomError {
+            msg: format!("Expiration at block height {} is not supported.", height),
+        }),
         _ => Err(ContractError::CustomError {
-            msg: "Not supported expiration enum".to_string(),
+            msg: format!("Unsupported expiration variant: {:?}", expiration),
         }),
     }
 }

93-138: Handle validation errors more gracefully in execute_submit_form

When data validation fails, the error message returned may not provide sufficient information. Consider providing more detailed error messages or handling specific validation errors to improve the user experience.


68-74: Redundant retrieval of current time

The function execute_submit_form retrieves the current time using get_and_validate_start_time, but this function is designed for validating start times, which may not be necessary here. Consider using ctx.env.block.time directly to get the current time in nanoseconds.

contracts/data-storage/andromeda-form/src/testing/tests.rs (3)

282-288: Reduce redundant calls to START_TIME.load()

Between lines 282-288, START_TIME.load(&deps.storage).unwrap() is called multiple times. To improve efficiency, consider storing the result in a variable and reusing it.

Apply this diff to refactor the code:

 let start_time = START_TIME.load(&deps.storage).unwrap();
-let expected_saved_start_time = if START_TIME.load(&deps.storage).unwrap().is_some() {
+let expected_saved_start_time = if start_time.is_some() {
     Some(Milliseconds::from_nanos(execute_timestamp).plus_milliseconds(Milliseconds(1)))
 } else {
     None
 };

290-295: Remove commented-out debug code

The commented-out println! statements between lines 290-295 are unnecessary and can be removed to keep the codebase clean and maintainable.

Apply this diff to remove the commented code:

-// println!(
-//     "//====================     endtime: {:?}     ====================//",
-//     end_time
-// );

510-511: Enhance test assertions for clarity

On lines 510-511, after querying all submissions, you're asserting the length of the submissions vector. For better clarity and to ensure the submissions are as expected, consider asserting the contents of the submissions as well.

Example addition:

assert_eq!(all_submissions, vec![
    // Expected SubmissionInfo entries
]);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 8955669 and dc2f26a.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (30)
  • Cargo.toml (1 hunks)
  • contracts/data-storage/andromeda-form/.cargo/config (1 hunks)
  • contracts/data-storage/andromeda-form/Cargo.toml (1 hunks)
  • contracts/data-storage/andromeda-form/examples/schema.rs (1 hunks)
  • contracts/data-storage/andromeda-form/src/contract.rs (1 hunks)
  • contracts/data-storage/andromeda-form/src/execute.rs (1 hunks)
  • contracts/data-storage/andromeda-form/src/lib.rs (1 hunks)
  • contracts/data-storage/andromeda-form/src/mock.rs (1 hunks)
  • contracts/data-storage/andromeda-form/src/query.rs (1 hunks)
  • contracts/data-storage/andromeda-form/src/state.rs (1 hunks)
  • contracts/data-storage/andromeda-form/src/testing/mock.rs (1 hunks)
  • contracts/data-storage/andromeda-form/src/testing/mock_querier.rs (1 hunks)
  • contracts/data-storage/andromeda-form/src/testing/mod.rs (1 hunks)
  • contracts/data-storage/andromeda-form/src/testing/tests.rs (1 hunks)
  • contracts/modules/andromeda-schema/.cargo/config (1 hunks)
  • contracts/modules/andromeda-schema/Cargo.toml (1 hunks)
  • contracts/modules/andromeda-schema/examples/schema.rs (1 hunks)
  • contracts/modules/andromeda-schema/src/contract.rs (1 hunks)
  • contracts/modules/andromeda-schema/src/execute.rs (1 hunks)
  • contracts/modules/andromeda-schema/src/lib.rs (1 hunks)
  • contracts/modules/andromeda-schema/src/mock.rs (1 hunks)
  • contracts/modules/andromeda-schema/src/query.rs (1 hunks)
  • contracts/modules/andromeda-schema/src/state.rs (1 hunks)
  • contracts/modules/andromeda-schema/src/testing/mock.rs (1 hunks)
  • contracts/modules/andromeda-schema/src/testing/mod.rs (1 hunks)
  • contracts/modules/andromeda-schema/src/testing/tests.rs (1 hunks)
  • packages/andromeda-data-storage/src/form.rs (1 hunks)
  • packages/andromeda-data-storage/src/lib.rs (1 hunks)
  • packages/andromeda-modules/src/lib.rs (1 hunks)
  • packages/andromeda-modules/src/schema.rs (1 hunks)
✅ Files skipped from review due to trivial changes (8)
  • contracts/data-storage/andromeda-form/Cargo.toml
  • contracts/data-storage/andromeda-form/examples/schema.rs
  • contracts/modules/andromeda-schema/.cargo/config
  • contracts/modules/andromeda-schema/Cargo.toml
  • contracts/modules/andromeda-schema/examples/schema.rs
  • contracts/modules/andromeda-schema/src/testing/mod.rs
  • packages/andromeda-data-storage/src/lib.rs
  • packages/andromeda-modules/src/lib.rs
🧰 Additional context used
📓 Learnings (1)
contracts/data-storage/andromeda-form/src/testing/mock_querier.rs (1)
Learnt from: crnbarr93
PR: andromedaprotocol/andromeda-core#576
File: contracts/data-storage/andromeda-graph/src/testing/mock_querier.rs:93-110
Timestamp: 2024-10-11T10:52:10.088Z
Learning: In the Rust file `contracts/data-storage/andromeda-graph/src/testing/mock_querier.rs`, panics caused by `unwrap()` are acceptable because the code is only used for testing.
🔇 Additional comments (37)
contracts/data-storage/andromeda-form/.cargo/config (1)

4-4: Verify schema example configuration.

The schema alias requires a corresponding example file in the examples directory.

✅ Verification successful

Schema example configuration is valid and properly set up

The verification confirms:

  • Examples directory exists at the correct location
  • Schema example file (schema.rs) is present and properly configured with the required API definitions
  • The cargo config alias correctly points to this example
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify schema example configuration

# Test 1: Check if examples directory exists
echo "Checking for examples directory..."
fd -t d "examples" contracts/data-storage/andromeda-form

# Test 2: Look for schema example file
echo "Looking for schema example file..."
fd -t f "schema" contracts/data-storage/andromeda-form/examples

Length of output: 383


Script:

#!/bin/bash
# Let's verify the content of schema.rs to ensure it's properly configured
echo "Checking schema.rs content..."
cat contracts/data-storage/andromeda-form/examples/schema.rs

# Also check if there are any other cargo config references to this example
echo -e "\nChecking for other cargo config references..."
rg "schema.*example" contracts/data-storage/andromeda-form

Length of output: 534

contracts/data-storage/andromeda-form/src/lib.rs (2)

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

The module structure follows a clean separation of concerns and includes all necessary components for a CosmWasm contract (contract, execute, query, state). The testing module is properly gated with the test configuration attribute.


8-9: LGTM! Good practice for test code isolation.

The mock module is correctly configured to be excluded from Wasm builds and only included when the testing feature is enabled. This ensures that test code doesn't bloat the production builds.

contracts/modules/andromeda-schema/src/lib.rs (1)

5-9: LGTM! Well-structured test configuration.

The test modules are properly configured:

  • Test module is correctly gated with #[cfg(test)]
  • Mock module is appropriately configured for non-wasm32 targets with testing feature
packages/andromeda-modules/src/schema.rs (2)

1-2: LGTM: Appropriate imports for contract message types

The imports correctly include the necessary dependencies for contract message attributes and serialization.


4-8: Add validation and documentation for schema_json_string

Consider the following improvements:

  1. Add input validation to ensure the schema_json_string is valid JSON
  2. Consider adding a maximum size limit to prevent excessive storage costs
  3. Add documentation comments explaining the expected JSON schema format and structure
contracts/modules/andromeda-schema/src/query.rs (1)

1-7: LGTM! Dependencies are well-organized.

The imports are appropriate and necessary for the schema validation functionality.

contracts/modules/andromeda-schema/src/testing/mock.rs (2)

1-16: LGTM! Well-organized imports and useful type alias.

The imports are logically grouped and the MockDeps type alias effectively simplifies the test code.


32-42: Verify sender permissions in tests.

The function should include test cases to verify that only authorized addresses (e.g., owner) can update the schema.

Let's verify the permission checks in the contract:

contracts/modules/andromeda-schema/src/mock.rs (3)

1-11: LGTM! Module configuration and imports are well-structured.

The conditional compilation attribute and imports are appropriate for a mock testing module.


38-57: LGTM! Funds handling is well-implemented.

The execute_update_schema method properly handles optional funds and message construction.


12-13: LGTM! Verify mock_ado macro implementation.

The struct design is clean and the mock_ado! macro usage appears correct.

✅ Verification successful

Let me gather more context about the MockContract trait to fully verify the macro implementation.


Mock implementation verified and provides correct trait functionality

The mock_ado! macro correctly implements:

  • MockContract trait with proper generic constraints for Execute and Query messages
  • Address accessor method via the newtype pattern
  • From conversion for convenient instantiation

The implementation aligns with testing requirements by providing contract execution capabilities through the MockApp integration.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Verify the mock_ado macro implementation to ensure it provides necessary trait implementations
rg -A 10 "macro_rules!\s+mock_ado"

Length of output: 860


Script:

#!/bin/bash
# Check the MockContract trait definition
rg -A 10 "trait\s+MockContract"

Length of output: 896

contracts/data-storage/andromeda-form/src/testing/mock_querier.rs (2)

1-16: LGTM! Well-organized imports and constant definition.

The imports are logically grouped and follow Rust best practices. The constant naming convention is appropriate for the testing context.


54-68: LGTM! Well-implemented error handling.

The raw_query implementation properly handles parsing errors and delegates to appropriate handlers. The error messages are clear and informative.

contracts/data-storage/andromeda-form/src/testing/mock.rs (3)

1-18: LGTM! Well-organized imports and mock setup.

The imports are logically grouped and the mock dependencies are properly set up following CosmWasm testing patterns.


1-183: Overall implementation looks solid!

The mock implementation provides comprehensive test coverage for the Form ADO contract operations. While there are opportunities for improvement in code organization and error handling, the core functionality is well-implemented and follows good testing practices.


68-135: Improve timestamp handling consistency across form operations.

Some form operation functions (submit_form, open_form, close_form) include timestamp handling while others (delete_submission, edit_submission) don't. Consider whether all operations should include timestamp validation for consistency.

Let's verify the timestamp requirements in the contract implementation:

Additionally, consider adding error context to improve debugging:

 pub fn submit_form(/* params */) -> Result<Response, ContractError> {
     let msg = ExecuteMsg::SubmitForm { data };
     let info = mock_info(sender, &[]);
     let mut env = mock_env();
     env.block.time = Timestamp::from_nanos(timestamp_nanos);
-    execute(deps, env, info, msg)
+    execute(deps, env, info, msg).map_err(|e| {
+        ContractError::Std(StdError::generic_err(format!(
+            "Failed to submit form: {}", e
+        )))
+    })
 }
contracts/data-storage/andromeda-form/src/mock.rs (2)

1-16: LGTM! Well-structured imports and proper test configuration.

The imports are comprehensive and the cfg attribute correctly ensures this code is only included in test builds.


189-210: LGTM! Well-implemented helper functions.

The helper functions are well-designed with:

  • Proper use of trait bounds (Into<String>) for flexibility
  • Clear parameter handling
  • Good separation of concerns between contract creation and message construction
contracts/modules/andromeda-schema/src/execute.rs (1)

13-33: Verify the handling of action messages and responses

Confirm that call_action is appropriately used and that any side effects from actions are intended. Ensure that action messages are necessary for this contract's functionality.

contracts/modules/andromeda-schema/src/contract.rs (3)

27-58: Instantiation Function Implemented Correctly

The instantiate function properly initializes the contract and stores the provided schema. Error handling and state management are correctly implemented.


61-74: Execute Function Handles Messages Appropriately

The execute function correctly processes incoming messages by matching the ExecuteMsg variants. It delegates AMP messages to execute_amp_receive and others to handle_execute, ensuring appropriate handling.


77-83: Query Function Correctly Processes Queries

The query function effectively handles ValidateData and GetSchema queries, encoding responses properly. It defers unsupported queries to the base ADOContract, ensuring extensibility.

contracts/data-storage/andromeda-form/src/contract.rs (4)

100-114: Permissions for authorized addresses are correctly set

The implementation properly assigns permissions to authorized_addresses_for_submission, ensuring that only specified addresses can submit forms when required.


116-125: Event emission for custom notifications is accurate

The code correctly adds custom events when custom_key_for_notifications is provided, enabling integration with notification services like Telegram.


154-156: Unhandled QueryMsg variants are correctly delegated

The code appropriately delegates unhandled QueryMsg variants to ADOContract::default().query, ensuring that extended queries are managed by the base contract logic.


137-142: Ensure all ExecuteMsg variants are handled

Verify that all variants of ExecuteMsg are properly managed in the execute function to prevent unhandled cases.

#!/bin/bash
# Description: Check if all ExecuteMsg variants are handled in the execute function.

# Extract all variants from the ExecuteMsg enum
rg 'pub enum ExecuteMsg' -A 50 contracts/data-storage/andromeda-form/src/msg.rs | rg '^[ ]+[A-Za-z_]+'

# Ensure each variant is matched in the execute function
rg 'match msg' -A 20 contracts/data-storage/andromeda-form/src/contract.rs
contracts/modules/andromeda-schema/src/testing/tests.rs (1)

1-310: Overall, well-structured tests and thorough schema validation

The test suite effectively covers various scenarios for schema validation, including valid inputs, missing fields, and incorrect data types. The use of the test_case macro improves readability and maintainability of tests.

contracts/data-storage/andromeda-form/src/testing/tests.rs (1)

586-599: Check for proper authorization in edit submission

In the test_submit_form_disallowed_multiple_submission_disallowed_edit test, lines 586-599, you correctly assert that editing a submission when edits are disallowed results in an error. Ensure that the unauthorized access is properly handled and consider adding more detailed assertions to validate the error content.

contracts/data-storage/andromeda-form/src/state.rs (5)

1-4: Imports are appropriate and necessary

All the required modules are imported correctly for state management and indexing functionalities. The use of andromeda_data_storage::form::SubmissionInfo and cw_storage_plus structures is appropriate.


6-13: State items are properly defined

The state items SCHEMA_ADO_ADDRESS, START_TIME, END_TIME, ALLOW_MULTIPLE_SUBMISSIONS, ALLOW_EDIT_SUBMISSION, and SUBMISSION_ID are correctly defined using Item. This ensures efficient storage and retrieval of singleton values in the contract's state.


15-23: Indexes in SubmissionIndexes are correctly set up

The SubmissionIndexes struct accurately defines MultiIndex for both submission_id and wallet_address. This facilitates efficient querying and retrieval of submission records based on these keys.


25-32: Implementation of IndexList for SubmissionIndexes is appropriate

The get_indexes method correctly returns an iterator over the indexes, integrating seamlessly with the storage system. This implementation adheres to the expected trait requirements.


34-48: submissions function correctly defines the indexed map

The submissions function properly creates an IndexedMap with the primary key (u64, Addr) and integrates the defined indexes. This setup ensures efficient storage, indexing, and querying of SubmissionInfo entries.

contracts/data-storage/andromeda-form/src/query.rs (3)

17-25: LGTM!

The get_schema function correctly retrieves the schema from the specified contract address.


27-42: LGTM!

The get_form_status function accurately determines the form status based on the current time and the saved start and end times.


56-65: LGTM!

The get_submission function correctly retrieves a specific submission based on the submission ID and wallet address.

packages/andromeda-modules/src/schema.rs Show resolved Hide resolved
packages/andromeda-modules/src/schema.rs Show resolved Hide resolved
contracts/modules/andromeda-schema/src/query.rs Outdated Show resolved Hide resolved
contracts/modules/andromeda-schema/src/query.rs Outdated Show resolved Hide resolved
Cargo.toml Show resolved Hide resolved
contracts/data-storage/andromeda-form/src/testing/tests.rs Outdated Show resolved Hide resolved
contracts/data-storage/andromeda-form/src/testing/tests.rs Outdated Show resolved Hide resolved
contracts/data-storage/andromeda-form/src/testing/tests.rs Outdated Show resolved Hide resolved
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: 0

🧹 Outside diff range and nitpick comments (1)
CHANGELOG.md (1)

33-33: Expand the changelog entry to better document this significant feature addition.

The current entry "Schema and Form ADO" is too brief for such a significant feature addition. Consider expanding it to highlight key capabilities and version information:

-Schema and Form ADO [(#591)](https://github.com/andromedaprotocol/andromeda-core/pull/591)
+Added Schema ADO (v1.0.0) and Form ADO (v1.0.0) [(#591)](https://github.com/andromedaprotocol/andromeda-core/pull/591)
+  - Schema ADO: JSON schema storage and validation capabilities
+  - Form ADO: Form submission management with schema validation
+  - Features include:
+    - Authorized submissions
+    - Configurable form timing
+    - Submission management (create/edit/delete)
+    - Comprehensive query system
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between dc2f26a and 8f4ce10.

📒 Files selected for processing (1)
  • CHANGELOG.md (1 hunks)

use cw_storage_plus::{Index, IndexList, IndexedMap, Item, MultiIndex};

pub const SCHEMA_ADO_ADDRESS: Item<AndrAddr> = Item::new("schema_ado_address");
pub const START_TIME: Item<Option<MillisecondsExpiration>> = Item::new("start_time");
Copy link
Contributor

Choose a reason for hiding this comment

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

A bunch of these Items could be stored under one Item under the name Config

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Resolved it.

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

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 8f4ce10 and 1ca55c7.

📒 Files selected for processing (1)
  • contracts/data-storage/andromeda-form/src/execute.rs (1 hunks)
🔇 Additional comments (4)
contracts/data-storage/andromeda-form/src/execute.rs (4)

154-157: Consider allowing users to delete their own submissions

Currently, only the owner or operator can delete submissions. Allowing users to delete their own submissions enhances data privacy and user control.


219-222: Fix potential unauthorized editing of submissions

The execute_edit_submission function relies on the wallet_address parameter provided by the caller, which can be manipulated to edit other users' submissions.


257-309: Simplify logic in execute_open_form function

The nested match statements in execute_open_form add unnecessary complexity. Simplifying the logic improves readability.


311-368: Simplify logic in execute_close_form function

Similar to execute_open_form, the execute_close_form function can be refactored to reduce complexity and enhance maintainability.


pub fn get_submission(
deps: Deps,
submission_id: u64,
Copy link
Contributor

Choose a reason for hiding this comment

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

How are people supposed to remember the submission_id?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

They can query all submissions and can see the submission_id with their wallet addresses.

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

🧹 Outside diff range and nitpick comments (11)
contracts/data-storage/andromeda-form/src/testing/mock_querier.rs (2)

18-49: Consider parameterizing the instantiation message.

The function hardcodes values like "form" and "test" in the instantiation message. Consider making these parameters to increase test flexibility.

 pub fn mock_dependencies_custom(
     contract_balance: &[Coin],
+    ado_type: Option<String>,
+    ado_version: Option<String>,
 ) -> OwnedDeps<MockStorage, MockApi, WasmMockQuerier> {
     // ...
             mock_info("sender", &[]),
             InstantiateMsg {
-                ado_type: "form".to_string(),
-                ado_version: "test".to_string(),
+                ado_type: ado_type.unwrap_or_else(|| "form".to_string()),
+                ado_version: ado_version.unwrap_or_else(|| "test".to_string()),
                 kernel_address: MOCK_KERNEL_CONTRACT.to_string(),
                 owner: None,
             },

83-105: Consider adding structured error handling for schema validation.

The current implementation could benefit from more robust error handling and validation responses.

     fn handle_schema_smart_query(&self, msg: &Binary) -> QuerierResult {
-        match from_json(msg).unwrap() {
+        match from_json(msg) {
+            Ok(query_msg) => match query_msg {
                 SchemaQueryMsg::GetSchema {} => {
                     // ... existing code ...
                 }
                 SchemaQueryMsg::ValidateData { data } => {
                     // ... existing code ...
                 }
-                _ => panic!("Unsupported Query"),
+                _ => SystemResult::Ok(ContractResult::Err("Unsupported query type".into())),
+            },
+            Err(e) => SystemResult::Ok(ContractResult::Err(format!("Failed to parse query: {}", e).into())),
         }
     }
contracts/modules/andromeda-schema/src/query.rs (2)

8-11: Consider adding input validation for storage access.

While the function is well-structured, consider adding validation to ensure the storage is properly initialized before attempting to load the schema.

 pub fn get_schema(storage: &dyn Storage) -> Result<GetSchemaResponse, ContractError> {
+    if !SCHEMA.may_load(storage)?.is_some() {
+        return Err(ContractError::CustomError {
+            msg: "Schema not initialized".to_string(),
+        });
+    }
     let schema = SCHEMA.load(storage)?.to_string();
     Ok(GetSchemaResponse { schema })
 }

85-226: Add test cases for edge scenarios.

The test suite is comprehensive but could benefit from additional edge cases:

  • Empty arrays and objects
  • Null values
  • Maximum nesting depth
  • Very large arrays/objects for performance testing
#[test]
fn test_basic_type_matches_edge_cases() {
    // Empty array
    let schema = json!({
        "type": "array",
        "items": { "type": "string" }
    });
    let data = json!([]);
    assert!(basic_type_matches(&schema, &data));

    // Empty object
    let schema = json!({
        "type": "object",
        "properties": {},
        "required": []
    });
    let data = json!({});
    assert!(basic_type_matches(&schema, &data));

    // Null values in non-required fields
    let schema = json!({
        "type": "object",
        "properties": {
            "optional": { "type": "string" }
        }
    });
    let data = json!({ "optional": null });
    assert!(!basic_type_matches(&schema, &data));
}
contracts/data-storage/andromeda-form/src/testing/tests.rs (6)

290-294: Remove commented out debug print statements.

The code contains commented-out debug print statements that should be removed to maintain code cleanliness.

-    // println!(
-    //     "//====================     endtime: {:?}     ====================//",
-    //     end_time
-    // );

425-507: Consider parameterizing the test case with test_case macro.

The test case test_submit_form_allowed_multiple_submission contains multiple submissions with different test data. Consider using the test_case macro to make the test more maintainable and easier to extend with additional test cases.

Example refactor:

#[test_case(
    vec![
        ("user1", "valid_data1", 20000000000_u64),
        ("user1", "valid_data2", 30000000000_u64),
        // ... more test cases
    ];
    "multiple valid submissions"
)]
fn test_submit_form_allowed_multiple_submission(test_cases: Vec<(&str, &str, u64)>) {
    // ... test setup ...
    for (user, data, timestamp) in test_cases {
        submit_form(deps.as_mut(), user, data.to_string(), timestamp).unwrap();
    }
    // ... assertions ...
}

656-662: Consider extracting the schema string to a constant.

The schema JSON string is hardcoded in the test. Consider extracting it to a constant at the top of the file for better maintainability and reusability across tests.

+const TEST_SCHEMA: &str = "{\"properties\":{\"age\":{\"type\":\"number\"},\"name\":{\"type\":\"string\"}},\"required\":[\"name\",\"age\"],\"type\":\"object\"}";

 let schema = query_schema(deps.as_ref()).unwrap();
 assert_eq!(
     schema,
     GetSchemaResponse {
-        schema: "{\"properties\":{\"age\":{\"type\":\"number\"},\"name\":{\"type\":\"string\"}},\"required\":[\"name\",\"age\"],\"type\":\"object\"}".to_string(),
+        schema: TEST_SCHEMA.to_string(),
     }
 );

1-663: Comprehensive test coverage with room for improvements.

The test file provides good coverage of the Form ADO functionality with:

  • Parameterized tests for various form configurations
  • Validation of form state transitions
  • Error handling for invalid operations
  • Multiple submission scenarios

However, consider adding tests for:

  1. Edge cases around timestamp boundaries
  2. Schema validation with invalid data formats
  3. Concurrent submission scenarios
  4. Form closure with pending submissions

508-511: Add descriptive assertion messages.

The assertion for the number of submissions would be clearer with a descriptive message explaining the expected state.

-    assert_eq!(all_submissions.len(), 7_usize);
+    assert_eq!(
+        all_submissions.len(),
+        7_usize,
+        "Expected 7 submissions after successful submissions from multiple users"
+    );

282-289: Simplify start time validation logic.

The start time validation logic can be simplified by using map instead of explicit if-else.

-    let expected_saved_start_time = if START_TIME.load(&deps.storage).unwrap().is_some() {
-        Some(Milliseconds::from_nanos(execute_timestamp).plus_milliseconds(Milliseconds(1)))
-    } else {
-        None
-    };
+    let expected_saved_start_time = START_TIME
+        .load(&deps.storage)
+        .unwrap()
+        .map(|_| Milliseconds::from_nanos(execute_timestamp).plus_milliseconds(Milliseconds(1)));
contracts/modules/andromeda-schema/src/testing/tests.rs (1)

217-219: Consider parsing and comparing JSON structures instead of raw strings

Comparing JSON data as raw strings can lead to brittle tests due to differences in formatting or property ordering. Parsing the JSON strings into serde_json::Value and comparing the resulting structures will make the test more robust and less sensitive to such changes.

Apply this diff to improve the test:

 fn test_query_schema() {
     let (deps, _) = proper_initialization(SCHEMA_INITIAL.to_string());
     let query_res = query_schema(deps.as_ref()).unwrap();
     let schema = query_res.schema;
-    assert_eq!(
-        schema,
-        "{\"properties\":{\"age\":{\"type\":\"number\"},\"name\":{\"type\":\"string\"}},\"required\":[\"name\",\"age\"],\"type\":\"object\"}".to_string()
-    );
+    let expected_schema: serde_json::Value = serde_json::from_str(SCHEMA_INITIAL).unwrap();
+    let actual_schema: serde_json::Value = serde_json::from_str(&schema).unwrap();
+    assert_eq!(actual_schema, expected_schema);
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 1ca55c7 and fa8082b.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • CHANGELOG.md (1 hunks)
  • contracts/data-storage/andromeda-form/src/testing/mock_querier.rs (1 hunks)
  • contracts/data-storage/andromeda-form/src/testing/tests.rs (1 hunks)
  • contracts/modules/andromeda-schema/Cargo.toml (1 hunks)
  • contracts/modules/andromeda-schema/src/contract.rs (1 hunks)
  • contracts/modules/andromeda-schema/src/execute.rs (1 hunks)
  • contracts/modules/andromeda-schema/src/query.rs (1 hunks)
  • contracts/modules/andromeda-schema/src/testing/mock.rs (1 hunks)
  • contracts/modules/andromeda-schema/src/testing/tests.rs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • CHANGELOG.md
  • contracts/modules/andromeda-schema/Cargo.toml
  • contracts/modules/andromeda-schema/src/contract.rs
  • contracts/modules/andromeda-schema/src/execute.rs
  • contracts/modules/andromeda-schema/src/testing/mock.rs
🔇 Additional comments (3)
contracts/data-storage/andromeda-form/src/testing/mock_querier.rs (1)

1-16: LGTM! Imports and constants are well organized.

The imports cover all necessary components for mocking and testing, and the constant follows naming conventions.

contracts/modules/andromeda-schema/src/query.rs (1)

1-7: LGTM! Dependencies are well-organized.

The imports are minimal and appropriate for the module's functionality.

contracts/data-storage/andromeda-form/src/testing/tests.rs (1)

348-348: Fix typo in error messages: 'opend' should be 'opened'.

Also applies to: 390-390

CHANGELOG.md Outdated Show resolved Hide resolved
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: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between fa8082b and ab4dc29.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (4)
  • CHANGELOG.md (1 hunks)
  • Cargo.toml (1 hunks)
  • packages/andromeda-data-storage/src/lib.rs (1 hunks)
  • packages/andromeda-modules/src/lib.rs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/andromeda-modules/src/lib.rs
  • packages/andromeda-data-storage/src/lib.rs
  • Cargo.toml

CHANGELOG.md Show resolved Hide resolved
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: 4

🧹 Outside diff range and nitpick comments (7)
contracts/data-storage/andromeda-form/Cargo.toml (1)

6-6: Consider relaxing the Rust version requirement

The specified Rust version (1.75.0) is very recent. Consider using an older stable version (like 1.70.0) to ensure broader compatibility and easier development environment setup, unless there are specific features from 1.75.0 that are required.

contracts/modules/andromeda-schema/src/interface.rs (1)

1-6: Consider adding interface documentation for Form ADO integration.

Since this Schema ADO will be used by the Form ADO (as mentioned in PR objectives), consider adding documentation comments that explain:

  1. How to properly reference and interact with this contract from other ADOs
  2. Best practices for schema validation integration
  3. Example usage patterns

This will help future developers understand the intended integration patterns.

contracts/data-storage/andromeda-form/src/interface.rs (1)

1-6: Consider event handling preparation for future enhancements.

The PR objectives mention future plans to support custom keys in response events for notification services. While implementing the current interface, consider preparing the event emission structure to accommodate these future enhancements without requiring breaking changes.

Suggested considerations:

  • Define a consistent event structure that can be extended
  • Plan for backward compatibility when adding custom keys
  • Consider implementing an event builder pattern

Would you like assistance in designing an extensible event structure?

contracts/modules/andromeda-schema/src/lib.rs (1)

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

The core module structure follows CosmWasm best practices with clear separation of concerns between contract entry points, execution logic, queries, and state management.

contracts/modules/andromeda-schema/src/contract.rs (1)

77-84: Consider explicit error handling for unsupported queries

The current implementation silently delegates unsupported queries to ADOContract. Consider adding explicit error handling for unsupported queries to improve debugging and maintainability.

 match msg {
     QueryMsg::ValidateData { data } => encode_binary(&validate_data(deps.storage, data)?),
     QueryMsg::GetSchema {} => encode_binary(&get_schema(deps.storage)?),
-    _ => ADOContract::default().query(deps, env, msg),
+    _ => {
+        // Log or handle unsupported query type explicitly
+        ADOContract::default().query(deps, env, msg)
+    }
 }
contracts/data-storage/andromeda-form/src/contract.rs (2)

120-126: Consider making notification_service configurable

Currently, the notification_service is hardcoded as "Telegram". To enhance flexibility and support multiple notification platforms, consider making the notification_service an input parameter or part of the configuration.

Update the InstantiateMsg struct to include notification_service:

pub struct InstantiateMsg {
    // ... existing fields
    pub notification_service: Option<String>,
}

Then, modify the code to use the configurable notification_service:

 if let Some(custom_key) = msg.custom_key_for_notifications {
+    let notification_service = msg.notification_service.unwrap_or_else(|| "Telegram".to_string());
     response = response.add_event(
         cosmwasm_std::Event::new("custom_key")
             .add_attribute("custom_key", custom_key)
-            .add_attribute("notification_service", "Telegram"),
+            .add_attribute("notification_service", notification_service),
     );
 }

35-129: Add documentation comments for public functions

Consider adding Rust documentation comments (///) to the public functions (instantiate, execute, query, migrate, reply) to improve code readability and maintainability. This practice helps other developers understand the purpose and usage of these functions.

Example:

/// Initializes the contract with the given parameters.
pub fn instantiate(
    // function parameters
) -> Result<Response, ContractError> {
    // implementation
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between ab4dc29 and 33c8f7c.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (8)
  • contracts/data-storage/andromeda-form/Cargo.toml (1 hunks)
  • contracts/data-storage/andromeda-form/src/contract.rs (1 hunks)
  • contracts/data-storage/andromeda-form/src/interface.rs (1 hunks)
  • contracts/data-storage/andromeda-form/src/lib.rs (1 hunks)
  • contracts/modules/andromeda-schema/Cargo.toml (1 hunks)
  • contracts/modules/andromeda-schema/src/contract.rs (1 hunks)
  • contracts/modules/andromeda-schema/src/interface.rs (1 hunks)
  • contracts/modules/andromeda-schema/src/lib.rs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • contracts/data-storage/andromeda-form/src/lib.rs
  • contracts/modules/andromeda-schema/Cargo.toml
🔇 Additional comments (17)
contracts/data-storage/andromeda-form/Cargo.toml (1)

26-39: Verify schema validation capabilities

The dependencies seem aligned with the Form ADO requirements, but let's verify the schema validation capabilities of the chosen dependencies.

✅ Verification successful

Let me analyze the schema validation capabilities based on the search results. I'll generate a final response since I have enough information from the codebase search.

Schema validation capabilities are appropriate for Form ADO

The cw-json dependency is well-suited for the Form ADO's schema validation requirements:

  • The codebase shows extensive use of schema validation patterns across different contracts, primarily using schemars for struct validation
  • No other JSON schema validation crates are used in the workspace that would be more suitable
  • The cw-json crate from the specified git repository is appropriate since:
    • It provides JSON schema validation capabilities needed for form data validation
    • It aligns with the CosmWasm ecosystem's patterns of schema validation
    • Other contracts in the codebase use similar external dependencies for specialized validation needs
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if there are any other schema validation crates in use across the workspace
# that might be more suitable than cw-json

# Search for schema validation related dependencies in all Cargo.toml files
echo "Searching for schema validation crates in workspace:"
rg -l 'jsonschema|schema|validation' -g 'Cargo.toml'

# Check the specific implementation details of schema validation
echo -e "\nSearching for schema validation implementations:"
rg -A 5 'validate|schema' --type rust

Length of output: 67403

contracts/modules/andromeda-schema/src/interface.rs (3)

1-2: LGTM! Clean and focused imports.

The imports are well-organized and include all necessary types for the schema contract interface.


4-4: Verify CONTRACT_ID uniqueness across the Andromeda protocol.

While the ID "schema" is appropriate for this contract, we should ensure it doesn't conflict with other contract IDs in the protocol.

✅ Verification successful

CONTRACT_ID "schema" is unique across the Andromeda protocol

The search results confirm that the CONTRACT_ID "schema" is only used once in the codebase, specifically in the schema contract. All other contracts use distinct identifiers that clearly represent their respective purposes.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Search for other occurrences of CONTRACT_ID definitions
# to ensure uniqueness across the protocol

# Search for CONTRACT_ID definitions
rg -g '!target/' 'pub const CONTRACT_ID: &str = ' -A 1

Length of output: 6001


6-6: Verify WASM binary existence and naming.

The contract interface references "andromeda_schema.wasm". Let's verify this binary is properly configured in the build system.

✅ Verification successful

WASM binary configuration is properly set up

The contract interface configuration is correct and consistent with the project setup:

  • The contract ID "schema" is properly defined as a constant
  • The Cargo.toml is configured with cdylib target for WASM compilation
  • The WASM binary name follows the consistent naming pattern used across all Andromeda contracts
  • The contract interface declaration matches other contracts in the ecosystem
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for WASM binary configuration

# Search for WASM binary name in Cargo.toml files
rg -g 'Cargo.toml' 'andromeda[_-]schema' -A 5

# Search for any references to this WASM name in build scripts
fd -g '*.{rs,sh,toml}' -X rg 'andromeda[_-]schema\.wasm'

Length of output: 606


Script:

#!/bin/bash
# Let's verify the build configuration and contract ID

# Check lib.rs for contract ID and wasm binary configuration
rg -g 'lib.rs' 'CONTRACT_ID' contracts/modules/andromeda-schema/ -B 2 -A 2

# Check if there are any other contract interface declarations for this contract
ast-grep --pattern 'contract_interface!($_, $_, $_)'

# Look for any build script configurations
fd -g 'build.rs' -X cat {} 

Length of output: 8751


Script:

#!/bin/bash
# Let's check the contract ID definition and Cargo configuration

# Check for CONTRACT_ID constant in the schema contract
rg -g '*.rs' 'pub const CONTRACT_ID' contracts/modules/andromeda-schema/

# Check the Cargo.toml configuration for wasm target
cat contracts/modules/andromeda-schema/Cargo.toml

Length of output: 1202

contracts/data-storage/andromeda-form/src/interface.rs (3)

1-2: LGTM! Imports are well-organized and properly scoped.

The imports are correctly structured, bringing in the necessary types from both the data storage module and the standard Andromeda library.


4-4: Verify uniqueness of CONTRACT_ID across the Andromeda ecosystem.

While "form" is a descriptive and appropriate ID, we should ensure it doesn't conflict with existing contracts.

✅ Verification successful

Let me search for any other contract IDs to ensure we have a complete picture of existing IDs in the ecosystem.


CONTRACT_ID "form" is unique across the Andromeda ecosystem

After reviewing all CONTRACT_ID declarations in the codebase, I can confirm that the identifier "form" is only used once in the andromeda-form contract and does not conflict with any other contract IDs in the ecosystem. Each contract has its own unique identifier that clearly describes its purpose.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Search for other occurrences of CONTRACT_ID = "form"
# to ensure uniqueness across the codebase

echo "Searching for CONTRACT_ID declarations containing 'form'..."
rg -g '!target/' 'CONTRACT_ID.*=.*"form"' 

Length of output: 271


Script:

#!/bin/bash
# Search for all CONTRACT_ID declarations in the codebase
echo "Searching for all CONTRACT_ID declarations..."
rg -g '!target/' 'CONTRACT_ID.*=.*".*"' -A 1

# Also search specifically in interface.rs files as they commonly define contract IDs
echo -e "\nSearching in interface.rs files..."
fd interface.rs --exec rg -l 'CONTRACT_ID'

Length of output: 8393


6-6: Verify the referenced WASM file path.

The contract interface references "andromeda_form.wasm". We should ensure this file will be generated with the correct name during the build process.

✅ Verification successful

WASM file name is correctly configured

The build configuration is correct and will generate the expected WASM file:

  1. The package name in Cargo.toml is "andromeda-form", which during build gets converted to "andromeda_form" (hyphens to underscores) as seen in the build script's BUILD_TARGET=${CONTRACT//-/_} conversion.
  2. The build script (scripts/build.sh) handles the WASM file generation and correctly converts hyphens to underscores in the target name.
  3. The generated WASM file will be placed in artifacts/andromeda_form.wasm, matching exactly what's referenced in the contract interface.
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the WASM file name configuration

# Check Cargo.toml for the package name
echo "Checking package name in Cargo.toml..."
rg -g 'Cargo.toml' 'name.*=.*"andromeda[_-]form"'

# Check for any other references to this WASM file
echo "Checking references to the WASM file..."
rg 'andromeda_form\.wasm'

Length of output: 452


Script:

#!/bin/bash
# Let's check the build configuration to see how the WASM file name is determined

# Check for any build scripts or configuration files that might handle WASM naming
echo "Checking for build configuration files..."
fd -e toml -e json -e sh -e rs build

# Check for any Cargo workspace configuration that might affect builds
echo "Checking workspace configuration..."
cat Cargo.toml

# Look for any build.rs files that might affect the output name
echo "Checking for build.rs files..."
fd build.rs

# Check for any other Rust files that might contain build configuration
echo "Looking for build-related code..."
rg -g '*.rs' 'wasm|build|artifact'

Length of output: 66182


Script:

#!/bin/bash
# Let's check the build configuration in the contract's directory

# Check Cargo.toml for build configuration
echo "Checking contract's Cargo.toml..."
cat contracts/data-storage/andromeda-form/Cargo.toml

# Check for any build scripts in the contract directory
echo "Checking for build scripts..."
fd -e sh -e rs build contracts/data-storage/andromeda-form/

# Check for any workspace build scripts that might affect WASM naming
echo "Checking workspace build scripts..."
cat scripts/build.sh

Length of output: 4789

contracts/modules/andromeda-schema/src/lib.rs (3)

5-6: LGTM! Proper test module configuration.

The testing module is correctly configured with conditional compilation, ensuring test code doesn't bloat the production binary.


8-9: LGTM! Excellent mock module configuration.

The mock module uses sophisticated conditional compilation to ensure it's only available during native testing while being completely excluded from WASM builds. This is a best practice for CosmWasm contract testing.


11-14: Verify SchemaContract interface implementation.

The module structure looks good with proper encapsulation. However, let's verify that the SchemaContract interface correctly implements all required functionality from the PR objectives.

✅ Verification successful

Interface implementation matches contract requirements

The SchemaContract interface correctly maps to the contract's implementation. The contract provides all required functionality:

  • Schema validation via ValidateData query
  • Schema updates through UpdateSchema execute message
  • Schema queries via GetSchema query message

The interface is properly encapsulated and the contract implementation in contract.rs handles all the required message types defined in schema.rs.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify SchemaContract interface implementation matches requirements

# Check for required schema validation functionality
ast-grep --pattern 'fn validate_data($$$)'

# Check for schema update capabilities
ast-grep --pattern 'fn update_schema($$$)'

# Check for schema query functionality
ast-grep --pattern 'fn query_schema($$$)'

Length of output: 133


Script:

#!/bin/bash
# Let's try a different approach to find the interface implementation

# First, let's see the interface module content
cat contracts/modules/andromeda-schema/src/interface.rs

# As backup, let's also search for trait or struct definitions
ast-grep --pattern 'trait SchemaContract {
  $$$
}'

ast-grep --pattern 'impl SchemaContract for $_ {
  $$$
}'

Length of output: 443


Script:

#!/bin/bash
# Let's check the contract_interface macro and message types

# Check the contract_interface macro definition
rg -A 5 "macro_rules! contract_interface"

# Check the message types used in the interface
cat contracts/modules/andromeda-schema/src/schema.rs

# Also check if there are any direct implementations
rg -g '!target' -g '!*.md' "impl.*SchemaContract"

Length of output: 1852


Script:

#!/bin/bash
# Let's check the message types in the andromeda_modules crate
# since the interface uses them from there

# Find and check the schema module in andromeda_modules
fd -t f schema.rs

# Once found, let's look at its content to verify the message types
cat packages/modules/src/schema.rs

Length of output: 2552


Script:

#!/bin/bash
# Let's try the correct path for modules
cat packages/andromeda-modules/src/schema.rs

# Also check the contract implementation
cat contracts/modules/andromeda-schema/src/contract.rs

# And check if there are any test files that might show usage
fd -t f -e rs . contracts/modules/andromeda-schema/src/

Length of output: 4383

contracts/modules/andromeda-schema/src/contract.rs (3)

61-75: LGTM!

The execute function implementation follows good practices with proper context management and clear message handling separation.


86-89: LGTM!

The migrate function correctly delegates to ADOContract with proper contract information.


51-54: 🛠️ Refactor suggestion

Optimize JSON parsing and conversion

The current implementation performs unnecessary string conversions.

-let schema_json_value: Value =
-    from_str(schema_json_string.as_str()).map_err(|_| ContractError::CustomError {
-        msg: "Invalid JSON Schema".to_string(),
-    })?;
-let schema_json = JSON::try_from(schema_json_value.to_string().as_str()).unwrap();
+let schema_json = JSON::try_from(schema_json_string.as_str())
+    .map_err(|e| ContractError::CustomError {
+        msg: format!("Invalid JSON Schema: {}", e),
+    })?;

Likely invalid or redundant comment.

contracts/data-storage/andromeda-form/src/contract.rs (4)

28-30: 🛠️ Refactor suggestion

Update CONTRACT_NAME to match the package name without the crates.io: prefix

To maintain consistency with the package metadata, the CONTRACT_NAME should align with the package name defined in Cargo.toml, which is "andromeda-form". The prefix "crates.io:" is unnecessary and can be removed.

Apply this diff to update CONTRACT_NAME:

-const CONTRACT_NAME: &str = "crates.io:andromeda-form";
+const CONTRACT_NAME: &str = "andromeda-form";

43-43: 🛠️ Refactor suggestion

Avoid unnecessary cloning of env

The env variable is cloned multiple times, which is redundant and can impact performance. Consider borrowing env or passing references to functions to improve efficiency.

Apply this diff to remove unnecessary clones:

Line 43:

-env.clone(),
+&env,

Line 63:

-get_and_validate_start_time(&env.clone(), Some(start_time))?
+get_and_validate_start_time(&env, Some(start_time))?

Line 69:

-let time_res = get_and_validate_start_time(&env.clone(), Some(end_time));
+let time_res = get_and_validate_start_time(&env, Some(end_time));

Also applies to: 61-61, 63-63, 69-69


68-84: 🛠️ Refactor suggestion

Refactor end_time validation to avoid using unwrap()

Simplify the error handling logic by using pattern matching instead of unwrap(). This enhances code safety and readability by eliminating potential panics from unwrap() usage.

Refactored code:

let end_time = match msg.form_config.end_time {
    Some(end_time) => match get_and_validate_start_time(&env, Some(end_time)) {
        Ok(validated_time) => Some(milliseconds_from_expiration(validated_time.0)?),
        Err(_) => {
            let current_time = Milliseconds::from_nanos(env.block.time.nanos()).milliseconds();
            let current_height = env.block.height;
            return Err(ContractError::CustomError {
                msg: format!(
                    "End time in the past. current_time {:?}, current_block {:?}",
                    current_time, current_height
                ),
            });
        },
    },
    None => None,
};

75-81: 🛠️ Refactor suggestion

Define a specific error variant for EndTimeInPast

Instead of using ContractError::CustomError, create a dedicated error variant ContractError::EndTimeInPast for clearer and more structured error handling.

Add the new error variant in your ContractError enum:

EndTimeInPast {
    current_time: u64,
    current_height: u64,
},

Update the error return statement:

return Err(ContractError::EndTimeInPast {
    current_time,
    current_height,
});

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

🧹 Outside diff range and nitpick comments (1)
contracts/data-storage/andromeda-form/src/testing/tests.rs (1)

345-345: Fix typo in error message: 'opend' should be 'opened'

There's a typo in the error messages on lines 345 and 387 where "opend" should be "opened". Please correct the typo for clarity.

Apply this diff to fix the typo:

-            msg: format!("Not opened yet. Will be opend at {:?}", Milliseconds::from_nanos(2000000000000_u64)),
+            msg: format!("Not opened yet. Will be opened at {:?}", Milliseconds::from_nanos(2000000000000_u64)),

Also applies to: 387-387

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 33c8f7c and d260a5d.

📒 Files selected for processing (5)
  • contracts/data-storage/andromeda-form/src/contract.rs (1 hunks)
  • contracts/data-storage/andromeda-form/src/execute.rs (1 hunks)
  • contracts/data-storage/andromeda-form/src/query.rs (1 hunks)
  • contracts/data-storage/andromeda-form/src/state.rs (1 hunks)
  • contracts/data-storage/andromeda-form/src/testing/tests.rs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • contracts/data-storage/andromeda-form/src/state.rs
🔇 Additional comments (11)
contracts/data-storage/andromeda-form/src/contract.rs (3)

26-26: Update CONTRACT_NAME to match the package name

The CONTRACT_NAME constant is currently set to "crates.io:andromeda-form", but it should match the package name "andromeda-form" as defined in Cargo.toml. Please remove the crates.io: prefix for consistency.


39-41: Avoid unnecessary cloning of env

The env variable is cloned when it's not necessary. Consider borrowing env or passing references to improve performance and reduce unnecessary cloning.


72-78: Define a specific error variant for EndTimeInPast

Instead of using ContractError::CustomError with a message, define a dedicated error variant like ContractError::EndTimeInPast to provide clearer error handling and messaging.

contracts/data-storage/andromeda-form/src/execute.rs (5)

109-133: Optimize submission existence check when multiple submissions are disallowed

When multiple submissions are not allowed, the current implementation retrieves up to MAX_LIMIT submissions to check if the user has already submitted. This could be inefficient and miss submissions beyond the limit. Consider optimizing the check by using may_load to check for the existence of any submission by the user.


148-177: Allow users to delete their own submissions

Currently, only the owner or operator can delete submissions. Consider allowing users to delete their own submissions to give them control over their data and comply with data privacy norms.


217-227: Fix potential unauthorized editing of submissions

The execute_edit_submission function relies on the wallet_address parameter provided by the caller to identify the submission owner, which can be exploited to edit others' submissions. Retrieve the wallet address from the stored submission and compare it to the sender's address to ensure only the submission owner can edit their submission.


261-333: Simplify the logic in execute_open_form

The nested matches in execute_open_form make the code complex. Refactor the function to simplify the logic for better readability and maintenance.


333-382: Simplify the logic in execute_close_form

Similar to execute_open_form, the execute_close_form function contains complex nested matches. Refactor to simplify the logic and improve code clarity.

contracts/data-storage/andromeda-form/src/query.rs (1)

48-55: Avoid using unwrap() on storage iteration results

Using unwrap() on results from storage iterations can cause the contract to panic if an error occurs during iteration. Handle potential errors by propagating them appropriately.

Consider modifying the code as follows:

 let all_submissions: Vec<SubmissionInfo> = submissions()
     .idx
     .submission_id
     .range(storage, None, None, cosmwasm_std::Order::Ascending)
-    .map(|r| r.unwrap().1) // Extract the `SubmissionInfo` from the result
-    .collect();
+    .map(|res| res.map(|(_, submission_info)| submission_info))
+    .collect::<Result<Vec<_>, _>>()?;
contracts/data-storage/andromeda-form/src/testing/tests.rs (2)

110-128: Avoid comparing errors with dynamic messages in tests

Comparing errors that include dynamically formatted messages can make tests brittle. Match on the error type and use assertions to check for specific patterns in the error message.


344-347: Avoid comparing errors with dynamic messages in tests

In test_failed_close_form, avoid comparing errors with dynamic messages. Instead, match on the error type and assert on relevant parts of the message.

}
Ok(())
}
None => Err(ContractError::CustomError {
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't we consider this that the user wants the form to be opened from the start?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The start time will be set at instantiation or only owner and operator can open/close the form.

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

🧹 Outside diff range and nitpick comments (5)
contracts/data-storage/andromeda-form/src/query.rs (2)

13-21: Consider enhancing error handling for schema queries.

The function could benefit from more specific error handling to distinguish between different failure scenarios (e.g., invalid contract address, schema not found, etc.).

Consider applying this diff:

 pub fn get_schema(deps: Deps) -> Result<GetSchemaResponse, ContractError> {
     let schema_ado_address = SCHEMA_ADO_ADDRESS.load(deps.storage)?;
+    let contract_addr = schema_ado_address
+        .get_raw_address(&deps)
+        .map_err(|e| ContractError::InvalidAddress { reason: e.to_string() })?;
     let res: SchemaResponse = deps.querier.query(&QueryRequest::Wasm(WasmQuery::Smart {
-        contract_addr: schema_ado_address.get_raw_address(&deps)?.into_string(),
+        contract_addr: contract_addr.into_string(),
         msg: encode_binary(&SchemaQueryMsg::GetSchema {})?,
-    }))?;
+    })).map_err(|e| ContractError::SchemaQueryError { reason: e.to_string() })?;
     let schema = res.schema;
     Ok(GetSchemaResponse { schema })
 }

49-58: Consider adding specific error for missing submissions.

The function could provide more informative errors when a submission is not found.

Consider applying this diff:

 pub fn get_submission(
     deps: Deps,
     submission_id: u64,
     wallet_address: AndrAddr,
 ) -> Result<GetSubmissionResponse, ContractError> {
     let wallet_address = wallet_address.get_raw_address(&deps)?;
     let submission =
-        submissions().may_load(deps.storage, &(submission_id, wallet_address.clone()))?;
+        submissions()
+            .may_load(deps.storage, &(submission_id, wallet_address.clone()))?
+            .ok_or_else(|| ContractError::SubmissionNotFound {
+                id: submission_id,
+                address: wallet_address,
+            })?;
-    Ok(GetSubmissionResponse { submission })
+    Ok(GetSubmissionResponse {
+        submission: Some(submission),
+    })
 }
contracts/data-storage/andromeda-form/src/testing/tests.rs (2)

164-164: Use More Specific Error Assertions

When asserting errors in tests (line 164), consider using pattern matching to assert on error variants rather than comparing the entire error objects. This enhances test resilience to changes in error messages.


631-632: Use Specific Error Matching

In test_submit_form_disallowed_multiple_submission_allowed_edit, the test asserts equality on the entire error object (line 631). Consider matching on the error type to make tests less fragile.

Example refactor:

match res {
    ContractError::Unauthorized {} => { /* Test passes */ },
    _ => panic!("Unexpected error type"),
}
contracts/data-storage/andromeda-form/src/state.rs (1)

11-17: Add documentation comments to the Config struct fields

Including documentation comments for each field in the Config struct would improve code readability and maintainability.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d260a5d and 9d1c90e.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • CHANGELOG.md (1 hunks)
  • contracts/data-storage/andromeda-form/src/execute.rs (1 hunks)
  • contracts/data-storage/andromeda-form/src/query.rs (1 hunks)
  • contracts/data-storage/andromeda-form/src/state.rs (1 hunks)
  • contracts/data-storage/andromeda-form/src/testing/tests.rs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • CHANGELOG.md
🔇 Additional comments (19)
contracts/data-storage/andromeda-form/src/query.rs (3)

1-12: LGTM! Imports are well-organized and necessary.

The imports are logically grouped and all are being used in the implementation.


23-35: LGTM! Clean implementation with proper validation.

The function correctly determines form status using the validation helper and handles errors appropriately.


37-47: Avoid using unwrap() on storage iteration results to prevent panics.

Using unwrap() on results from storage iterations can cause the contract to panic if an error occurs during iteration.

contracts/data-storage/andromeda-form/src/testing/tests.rs (4)

1-660: Comprehensive and Well-Structured Test Suite

The test suite is comprehensive and covers a wide range of scenarios for form instantiation, opening, closing, and submission. The use of the test_case macro enhances readability and maintainability.


110-128: 🛠️ Refactor suggestion

Avoid Comparing Errors with Dynamic Messages in Tests

In the test_invalid_instantiation function, the tests compare errors that include dynamically formatted messages (lines 110-128). This approach can lead to brittle tests because any change in the message formatting or content can cause the test to fail, even if the error type is correct.

Consider matching on the error type and validating the error messages using pattern matching or assertions that check for substrings. This will make the tests more resilient to changes in error messages.

Example refactor:

let err = invalid_initialization(...).unwrap_err();
match err {
    ContractError::StartTimeInThePast { .. } => { /* Further assertions if needed */ },
    _ => panic!("Unexpected error type"),
}

209-210: 🛠️ Refactor suggestion

Avoid Comparing Errors with Dynamic Messages in Tests

Similarly, in the test_failed_open_form function, the test compares errors with dynamic messages (lines 209-210). To prevent brittle tests, match on the error type and assert on relevant parts of the error message if necessary.

Example refactor:

let err = open_form(...).unwrap_err();
match err {
    ContractError::CustomError { msg } => {
        assert!(msg.contains("Already opened"));
    },
    _ => panic!("Unexpected error type"),
}

419-420: 🛠️ Refactor suggestion

Avoid Comparing Errors with Dynamic Messages in Tests

In test_failed_close_form (lines 419-420), the test compares errors containing dynamic messages. To improve test stability, match on the error variant and use assertions for dynamic content.

contracts/data-storage/andromeda-form/src/state.rs (5)

1-5: Import statements are appropriate and necessary

The imported modules and types are correctly included for the functionality provided.


7-9: Consider consolidating constants into the Config struct

The constants SCHEMA_ADO_ADDRESS and SUBMISSION_ID could be included within the Config struct to reduce the number of storage variables and simplify state management.


19-27: Index definitions are correctly set up

The SubmissionIndexes struct properly defines the multi-indexes for efficient querying of submissions.


29-36: Implementation of IndexList for SubmissionIndexes is correct

The get_indexes function accurately returns an iterator over the indexes, complying with the required trait implementation.


38-52: submissions function correctly initializes IndexedMap with indexes

The submissions function appropriately initializes the IndexedMap with the defined indexes, ensuring efficient data retrieval.

contracts/data-storage/andromeda-form/src/execute.rs (7)

263-316: Simplify logic in execute_open_form

The current implementation contains complex nested match statements, which can be simplified for better readability and maintainability.

Consider refactoring the function to reduce complexity:

pub fn execute_open_form(ctx: ExecuteContext) -> Result<Response, ContractError> {
    nonpayable(&ctx.info)?;
    let sender = ctx.info.sender;
    ensure!(
        ADOContract::default().is_owner_or_operator(ctx.deps.storage, sender.as_ref())?,
        ContractError::Unauthorized {}
    );

    let mut config = CONFIG.load(ctx.deps.storage)?;
    let current_time = Milliseconds::from_nanos(ctx.env.block.time.nanos());
    let start_time = current_time.plus_milliseconds(Milliseconds(1));

    match config.start_time {
        Some(saved_start_time) if saved_start_time > start_time => {
            config.start_time = Some(start_time);
            CONFIG.save(ctx.deps.storage, &config)?;
        }
        Some(saved_start_time) => {
            return Err(ContractError::CustomError {
                msg: format!("Form is already open since {:?}", saved_start_time),
            });
        }
        None => {
            config.start_time = Some(start_time);
            CONFIG.save(ctx.deps.storage, &config)?;
        }
    }

    // Clear end_time if necessary
    if let Some(saved_end_time) = config.end_time {
        if start_time > saved_end_time {
            config.end_time = None;
            CONFIG.save(ctx.deps.storage, &config)?;
        }
    }

    let response = Response::new()
        .add_attribute("method", "open_form")
        .add_attribute("sender", sender);

    Ok(response)
}

339-394: Simplify logic in execute_close_form

Similar to execute_open_form, the execute_close_form function can be simplified to improve readability and reduce complexity.

Consider the following refactored code:

pub fn execute_close_form(ctx: ExecuteContext) -> Result<Response, ContractError> {
    nonpayable(&ctx.info)?;
    let sender = ctx.info.sender;
    ensure!(
        ADOContract::default().is_owner_or_operator(ctx.deps.storage, sender.as_ref())?,
        ContractError::Unauthorized {}
    );

    let mut config = CONFIG.load(ctx.deps.storage)?;
    let current_time = Milliseconds::from_nanos(ctx.env.block.time.nanos());
    let end_time = current_time.plus_milliseconds(Milliseconds(1));

    match config.start_time {
        Some(saved_start_time) if saved_start_time <= end_time => {
            match config.end_time {
                Some(saved_end_time) if saved_end_time > end_time => {
                    config.end_time = Some(end_time);
                    CONFIG.save(ctx.deps.storage, &config)?;
                }
                Some(saved_end_time) => {
                    return Err(ContractError::CustomError {
                        msg: format!("Form is already closed since {:?}", saved_end_time),
                    });
                }
                None => {
                    config.end_time = Some(end_time);
                    CONFIG.save(ctx.deps.storage, &config)?;
                }
            }
        }
        Some(saved_start_time) => {
            return Err(ContractError::CustomError {
                msg: format!("Form has not been opened yet. Scheduled to open at {:?}", saved_start_time),
            });
        }
        None => {
            return Err(ContractError::CustomError {
                msg: "Form has not been opened yet".to_string(),
            });
        }
    }

    let response = Response::new()
        .add_attribute("method", "close_form")
        .add_attribute("sender", sender);

    Ok(response)
}

188-189: Reconsider requiring the form to be open for editing submissions

The execute_edit_submission function checks if the form is currently open before allowing edits. This might prevent users from correcting their submissions after the form has closed.

Ensure that restricting edits to open forms aligns with the intended functionality and user experience.


100-124: 🛠️ Refactor suggestion

Optimize submission existence check when multiple submissions are disallowed

When allow_multiple_submissions is false, the current implementation retrieves up to MAX_LIMIT submissions to check if the user has already submitted. This approach is inefficient and may not cover submissions beyond the limit.

Apply this diff to optimize the check by retrieving only a single submission:

- let submissions_by_address: Vec<SubmissionInfo> = submissions()
-     .idx
-     .wallet_address
-     .prefix(sender.clone())
-     .range(ctx.deps.storage, None, None, cosmwasm_std::Order::Ascending)
-     .take(MAX_LIMIT as usize)
-     .map(|r| r.unwrap().1)
-     .collect();

- if submissions_by_address.is_empty() {
+ if submissions()
+     .idx
+     .wallet_address
+     .prefix(sender.clone())
+     .range(ctx.deps.storage, None, None, cosmwasm_std::Order::Ascending)
+     .next()
+     .is_none()
+ {
     submissions().save(
         ctx.deps.storage,
         &(new_id.u64(), sender.clone()),
         &SubmissionInfo {
             submission_id: new_id.u64(),
             wallet_address: sender.clone(),
             data,
         },
     )?;
     SUBMISSION_ID.save(ctx.deps.storage, &new_id)?;
 } else {
     return Err(ContractError::CustomError {
         msg: "Multiple submissions are not allowed".to_string(),
     });
 }

146-149: 🛠️ Refactor suggestion

Allow users to delete their own submissions

Currently, only the owner or operator can delete submissions. Consider allowing users to delete their own submissions to give them more control over their data and comply with data privacy regulations.

Modify the authorization logic to permit submission owners to delete their own submissions:

ensure!(
-    ADOContract::default().is_owner_or_operator(ctx.deps.storage, sender.as_ref())?,
+    ADOContract::default().is_owner_or_operator(ctx.deps.storage, sender.as_ref())?
+        || sender == wallet_address.get_raw_address(&ctx.deps.as_ref())?,
    ContractError::Unauthorized {}
);

211-213: ⚠️ Potential issue

Fix potential unauthorized editing of submissions

The execute_edit_submission function relies on the wallet_address parameter provided by the caller to identify the submission owner. This can be exploited by malicious users to edit other users' submissions by supplying a different wallet_address.

To prevent unauthorized editing, retrieve the wallet address from the stored submission and compare it to the sender's address:

let wallet_address = wallet_address.get_raw_address(&ctx.deps.as_ref())?;

if submissions()
    .may_load(ctx.deps.storage, &(submission_id, wallet_address.clone()))?
    .is_some()
{
-   ensure!(
-       wallet_address.clone() == sender.clone(),
-       ContractError::Unauthorized {}
-   );
+   ensure!(
+       wallet_address == sender,
+       ContractError::Unauthorized {}
+   );

204-213: ⚠️ Potential issue

Prevent unauthorized access in execute_edit_submission

The function currently allows any user to attempt editing a submission by specifying a wallet_address. This can lead to unauthorized access if the wallet_address does not match the sender.

Modify the code to use the stored wallet_address from the submission and ensure only the owner can edit it:

let submission = submissions()
    .load(ctx.deps.storage, &(submission_id, wallet_address.clone()))
    .map_err(|_| ContractError::CustomError {
        msg: format!(
            "Submission does not exist - Submission_id {:?}, Wallet_address {:?}",
            submission_id, wallet_address
        ),
    })?;

ensure!(
-    wallet_address.clone() == sender.clone(),
+    submission.wallet_address == sender,
    ContractError::Unauthorized {}
);

Likely invalid or redundant comment.

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.

3 participants