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

PoW Cw721 #697

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

PoW Cw721 #697

wants to merge 12 commits into from

Conversation

mdjakovic0920
Copy link
Contributor

@mdjakovic0920 mdjakovic0920 commented Dec 4, 2024

Motivation

The motivation of this ADO is to be able to simulate BTC style PoW mining with NFTs.
It takes very little work to solve the first one, and once it’s solved, the NFT increases its “level”.
Last block hash, nonce = seed for challenge.

Just have it where someone can submit the proof to the ADO and it levels up.
Level 1 -> 2 -> 3 -> 4 (etc)
But each level gets harder to solve.
Just make the difficulty go up by 150% or something, so that it eventually gets really difficult.
Then we can create a little JS that solves it and we can submit it via command line.

Implementation

#[andr_instantiate]
#[cw_serde]
pub struct InstantiateMsg {
    pub linked_cw721_address: AndrAddr,
    pub authorized_origin_minter_addresses: Option<Vec<AndrAddr>>,
}

#[andr_exec]
#[cw_serde]
pub enum ExecuteMsg {
    MintPowNFT {
        owner: AndrAddr,
        token_id: String,
        token_uri: Option<String>,
        extension: TokenExtension,
        base_difficulty: u64,
    },
    SubmitProof {
        token_id: String,
        nonce: u128,
    },
}

#[cw_serde]
pub struct PowNFTInfo {
    pub owner: Addr,
    pub level: u64,
    pub last_hash: Binary,
    pub difficulty: u64,
}

#[andr_query]
#[cw_serde]
#[derive(QueryResponses)]
pub enum QueryMsg {
    #[returns(GetPowNFTResponse)]
    GetPowNFT { token_id: String },
    #[returns(GetLinkedCw721AddressResponse)]
    GetLinkedCw721Address {},
}

#[cw_serde]
pub struct GetPowNFTResponse {
    pub nft_response: PowNFTInfo,
}

#[cw_serde]
pub struct GetLinkedCw721AddressResponse {
    pub linked_cw721_address: AndrAddr,
}

Testing

Unit test cases are added.

Version Changes

Version is set as 0.1.0-beta

Future work

We can set the other methods to solve the challenge to level up.

Summary by CodeRabbit

  • New Features

    • Introduced a new non-fungible token (NFT) system with proof-of-work capabilities.
    • Added functionality for minting NFTs and submitting proofs.
    • Implemented querying capabilities for NFT data and linked addresses.
    • Enhanced developer usability with new command aliases in configuration files.
  • Bug Fixes

    • Enhanced error handling for unauthorized actions and invalid proofs.
  • Tests

    • Added a comprehensive suite of unit tests to validate NFT functionalities, including instantiation, minting, and proof submission.
  • Documentation

    • Updated configuration and metadata files for improved developer usability.
    • Revised the changelog to reflect new ADOs and functionality changes.

Copy link
Contributor

coderabbitai bot commented Dec 4, 2024

Walkthrough

This pull request introduces a new non-fungible token (NFT) implementation within the Andromeda framework. It includes the creation of a new Cargo package with a configuration file that defines command aliases to streamline development tasks. The implementation features a smart contract with functions for instantiation, execution, querying, and migration, alongside a set of mock testing utilities. Additionally, it defines various message structures and response types for handling NFT operations, enhancing the overall functionality and organization of the codebase.

Changes

File Path Change Summary
contracts/non-fungible-tokens/andromeda-pow-cw721/.cargo/config Added command aliases: wasm, unit-test, and schema to streamline development tasks.
contracts/non-fungible-tokens/andromeda-pow-cw721/Cargo.toml Introduced new package andromeda-pow-cw721, version 0.1.0-b.1, with metadata, dependencies, features, and exclusions for certain files.
contracts/non-fungible-tokens/andromeda-pow-cw721/examples/schema.rs Created schema.rs to generate API schema using write_api! macro for contract messages.
contracts/non-fungible-tokens/andromeda-pow-cw721/src/contract.rs Implemented smart contract functions: instantiate, execute, query, reply, and migrate for NFT operations.
contracts/non-fungible-tokens/andromeda-pow-cw721/src/execute.rs Introduced handle_execute function for processing execution messages, including minting and proof submission.
contracts/non-fungible-tokens/andromeda-pow-cw721/src/interface.rs Added PowCw721Contract interface with CONTRACT_ID constant for contract identification.
contracts/non-fungible-tokens/andromeda-pow-cw721/src/lib.rs Added modules: contract, execute, query, state, and conditionally compiled testing and interface modules for better organization.
contracts/non-fungible-tokens/andromeda-pow-cw721/src/query.rs Added query functions: query_pow_nft and query_linked_cw721_address for retrieving NFT and linked address information.
contracts/non-fungible-tokens/andromeda-pow-cw721/src/state.rs Defined constants for NFT state management: LINKED_CW721_ADDRESS and POW_NFT.
contracts/non-fungible-tokens/andromeda-pow-cw721/src/testing/mock.rs Introduced mock functions for testing contract functionality, including initialization and minting operations.
contracts/non-fungible-tokens/andromeda-pow-cw721/src/testing/mock_querier.rs Implemented a custom mock querier for testing, handling specific queries related to the CW721 contract.
contracts/non-fungible-tokens/andromeda-pow-cw721/src/testing/mod.rs Added new modules: mock, mock_querier, and tests for improved testing structure.
contracts/non-fungible-tokens/andromeda-pow-cw721/src/testing/tests.rs Created unit tests for contract functionality, covering instantiation, minting, proof submission, and error handling.
packages/andromeda-non-fungible-tokens/src/lib.rs Added module declaration for pow_cw721 to the existing Andromeda non-fungible tokens package.
packages/andromeda-non-fungible-tokens/src/pow_cw721.rs Defined structures and messages for NFT operations, including InstantiateMsg, ExecuteMsg, PowNFTInfo, and query messages.

Possibly related PRs

  • feat: Set Amount Splitter #507: The changes in this PR involve the introduction of command aliases in the .cargo/config file, similar to the main PR's addition of a configuration file for the Rust Cargo package manager, indicating a focus on enhancing usability for developers.
  • feat: add single boolean storage to andromeda-data-storage #513: This PR also introduces a new configuration file and command aliases, which aligns with the main PR's changes to streamline development processes through configuration enhancements.
  • feat: Restake & Redelegate for Validator Staking #622: The introduction of restake and redelegate functionalities in the validator staking aligns with the main PR's enhancements aimed at improving contract management and usability.
  • Added Discarded state to cf contract #715: The addition of the "DISCARDED" state in the crowdfund contract is relevant to the main PR's updates on campaign management, as both involve changes to contract states and functionalities.
  • feat: added mainnet chain configs #689: The introduction of mainnet chain configurations in this PR complements the main PR's updates, as both aim to enhance the overall functionality and organization of the Andromeda project.
  • Moved Distance ADO to Andromeda-math #714: The movement of the Distance ADO to a more appropriate directory reflects a similar organizational improvement as seen in the main PR's updates to contract functionalities.
  • fix: add cw20 missing receive schema #594: The addition of the CW20 receive schema in this PR is related to the main PR's focus on enhancing contract functionalities, particularly in the context of token management.

Suggested labels

backport/release/3, ci: skip-changelog

Suggested reviewers

  • joemonem
  • crnbarr93

🐇 In the land of code, where tokens play,
A new NFT shines bright today!
With functions and tests, all set to go,
And command aliases to make it flow.
Hop along, dear devs, let’s code away,
For Andromeda's magic is here to stay! ✨


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

🧹 Outside diff range and nitpick comments (21)
contracts/non-fungible-tokens/andromeda-pow-cw721/src/lib.rs (2)

6-7: Consider making the testing module private.

The testing module is marked as pub, but test utilities typically don't need to be publicly exposed unless they're intended to be used by other crates.

 #[cfg(test)]
-pub mod testing;
+mod testing;

1-12: Consider adding module documentation.

While the module structure is clean, adding documentation comments for each module would improve maintainability and help other developers understand the PoW NFT implementation details.

Add documentation like this:

+//! Proof of Work NFT implementation that simulates Bitcoin-style mining.
+//! Allows users to level up NFTs by solving increasingly difficult challenges.
+
 pub mod contract;
contracts/non-fungible-tokens/andromeda-pow-cw721/src/testing/mock_querier.rs (2)

18-20: Enhance function documentation.

Consider adding more details about the return value and parameter requirements in the documentation.

 /// 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
+/// 
+/// # Returns
+/// `OwnedDeps` instance with custom WasmMockQuerier implementation

33-48: Consider improving error handling in ADOContract instantiation.

The unwrap() call on the instantiation result could mask important error details during testing.

-    ADOContract::default()
-        .instantiate(
-            &mut deps.storage,
-            mock_env(),
-            &deps.api,
-            &QuerierWrapper::new(&deps.querier),
-            mock_info("sender", &[]),
-            InstantiateMsg {
-                ado_type: "pow-cw721".to_string(),
-                ado_version: "test".to_string(),
-                kernel_address: MOCK_KERNEL_CONTRACT.to_string(),
-                owner: None,
-            },
-        )
-        .unwrap();
+    ADOContract::default()
+        .instantiate(
+            &mut deps.storage,
+            mock_env(),
+            &deps.api,
+            &QuerierWrapper::new(&deps.querier),
+            mock_info("sender", &[]),
+            InstantiateMsg {
+                ado_type: "pow-cw721".to_string(),
+                ado_version: "test".to_string(),
+                kernel_address: MOCK_KERNEL_CONTRACT.to_string(),
+                owner: None,
+            },
+        )
+        .map_err(|e| panic!("Failed to instantiate ADOContract: {}", e))?;
contracts/non-fungible-tokens/andromeda-pow-cw721/src/testing/tests.rs (4)

16-26: Enhance instantiation test coverage.

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

  • Instantiation with authorized minters
  • Default state validation
  • Error cases with invalid CW721 address
#[test]
fn test_instantiation_with_minters() {
    let minters = vec![
        AndrAddr::from_string(AUTHORIZED_ORIGIN_MINTER1),
        AndrAddr::from_string(AUTHORIZED_ORIGIN_MINTER2),
    ];
    let deps = proper_initialization(AndrAddr::from_string(MOCK_CW721_CONTRACT), Some(minters.clone()));
    
    // Verify minters are stored correctly
    let stored_minters = query_authorized_minters(deps.as_ref()).unwrap();
    assert_eq!(stored_minters, minters);
}

28-51: Add edge cases to minting authorization tests.

Consider adding tests for:

  • Minting with empty authorized minters list
  • Minting with invalid token_id format
  • Minting the same token_id twice
#[test]
fn test_mint_pow_nft_duplicate_token() {
    let mut deps = proper_initialization(AndrAddr::from_string(MOCK_CW721_CONTRACT), None);
    
    // First mint should succeed
    mint_pow_nft(
        deps.as_mut(),
        ORIGIN_MINTER,
        AndrAddr::from_string(ORIGIN_MINTER),
        "test_pow1".to_string(),
        None,
        TokenExtension {
            publisher: "Andromeda".to_string(),
        },
        10_u64,
    )
    .unwrap();
    
    // Second mint with same token_id should fail
    let err = mint_pow_nft(
        deps.as_mut(),
        ORIGIN_MINTER,
        AndrAddr::from_string(ORIGIN_MINTER),
        "test_pow1".to_string(),
        None,
        TokenExtension {
            publisher: "Andromeda".to_string(),
        },
        10_u64,
    )
    .unwrap_err();
    
    assert!(matches!(err, ContractError::TokenIdAlreadyExists { .. }));
}

53-89: Enhance NFT state validation in minting test.

The test should verify the complete NFT state after minting:

  • Initial difficulty value
  • Hash initialization
  • TokenExtension data persistence
  • Other metadata fields

Also, consider documenting why the initial difficulty is set to 10 or making it a named constant for better maintainability.


1-174: Consider enhancing test architecture and documentation.

The test suite would benefit from:

  1. A test helper module to calculate valid nonces and expected difficulties
  2. Documentation explaining the PoW algorithm and difficulty calculation
  3. Property-based testing for proof validation
  4. Integration tests for concurrent operations

Consider using a test helper like this:

mod test_helpers {
    /// Calculates a valid nonce for the given difficulty
    pub fn calculate_valid_nonce(difficulty: u64, previous_hash: &str) -> u128 {
        // Add implementation
    }
    
    /// Calculates expected difficulty for a given level
    pub fn calculate_difficulty(initial_difficulty: u64, level: u32) -> u64 {
        // Add implementation using 150% increase formula
    }
}
packages/andromeda-non-fungible-tokens/src/pow_cw721.rs (3)

32-32: Consider changing owner type to AndrAddr for consistency.

To maintain consistency with the MintPowNFT struct, consider changing the owner field in PowNFTInfo from Addr to AndrAddr.


50-50: Rename nft_response to pow_nft_info for clarity.

In the GetPowNFTResponse struct, renaming the field nft_response to pow_nft_info can improve readability by clearly indicating that it contains PowNFTInfo.

Apply this diff to make the change:

 pub struct GetPowNFTResponse {
-    pub nft_response: PowNFTInfo,
+    pub pow_nft_info: PowNFTInfo,
 }

55-55: Consider renaming linked_cw721_address to linked_cw721_addr for consistency.

Across the codebase, shorter variable names like addr are commonly used. Renaming linked_cw721_address to linked_cw721_addr can enhance consistency.

contracts/non-fungible-tokens/andromeda-pow-cw721/src/contract.rs (1)

95-97: Directly returning error without handling may cause issues.

In the reply function, you are directly returning the error from msg.result.unwrap_err(). Consider mapping the error to a more descriptive ContractError or handling specific error cases for better clarity.

Apply this diff to improve error handling:

 if msg.result.is_err() {
-    return Err(ContractError::Std(StdError::generic_err(
-        msg.result.unwrap_err(),
-    )));
+    let error_msg = format!("Reply failed: {:?}", msg.result.unwrap_err());
+    return Err(ContractError::Std(StdError::generic_err(error_msg)));
 }
contracts/non-fungible-tokens/andromeda-pow-cw721/src/state.rs (1)

5-6: Ensure proper namespacing of storage keys.

To prevent key collisions in storage, consider prefixing the storage keys with a unique namespace or module identifier.

Apply this diff to update the storage keys:

 pub const LINKED_CW721_ADDRESS: Item<AndrAddr> = Item::new("linked_cw721_address");
 pub const POW_NFT: Map<String, PowNFTInfo> = Map::new("pow_nft");
+// For example:
+pub const LINKED_CW721_ADDRESS: Item<AndrAddr> = Item::new("pow_cw721_linked_cw721_address");
+pub const POW_NFT: Map<String, PowNFTInfo> = Map::new("pow_cw721_pow_nft");

This change reduces the risk of key collisions with other modules or contracts.

contracts/non-fungible-tokens/andromeda-pow-cw721/src/query.rs (2)

7-15: Add documentation for the query_pow_nft function.

Consider adding documentation that explains:

  • The purpose of the function
  • The expected format of token_id
  • The error conditions

Example documentation:

/// Queries information about a specific PoW NFT
/// 
/// # Arguments
/// * `deps` - Dependencies for storage access
/// * `token_id` - Unique identifier of the NFT
///
/// # Returns
/// * `GetPowNFTResponse` containing the NFT information
/// * `ContractError::NFTNotFound` if the token doesn't exist

17-25: Add documentation for the query_linked_cw721_address function.

Consider adding documentation that explains:

  • The purpose of the function
  • The relationship with the linked CW721 contract

Example documentation:

/// Retrieves the address of the linked CW721 contract
/// 
/// # Arguments
/// * `deps` - Dependencies for storage access
///
/// # Returns
/// * `GetLinkedCw721AddressResponse` containing the linked contract address
/// * Propagates any storage errors
contracts/non-fungible-tokens/andromeda-pow-cw721/Cargo.toml (2)

34-34: Consider using workspace version for sha2 dependency.

Other dependencies use workspace versions for consistency. Consider moving sha2 to workspace dependencies as well.


36-36: Clean up commented out dependencies.

Remove commented out dependencies if they're not needed:

  • hex = { version = "0.4.3" }
  • cw-orch-daemon = "0.24.2"

Also applies to: 45-45

contracts/non-fungible-tokens/andromeda-pow-cw721/src/testing/mock.rs (4)

1-1: Remove or document the commented import.

The commented import andromeda_data_storage::graph suggests either planned functionality or leftover code. If it's not needed, please remove it. If it's for future use, add a TODO comment explaining the intended usage.


20-35: Consider adding validation and documentation.

While the initialization looks correct, consider:

  1. Adding validation for empty authorized_origin_minter_addresses vector
  2. Documenting why owner: None is acceptable in the test context
 pub fn proper_initialization(
     linked_cw721_address: AndrAddr,
     authorized_origin_minter_addresses: Option<Vec<AndrAddr>>,
 ) -> MockDeps {
+    // Validate that if authorized_origin_minter_addresses is Some, it's not empty
+    if let Some(addresses) = &authorized_origin_minter_addresses {
+        assert!(!addresses.is_empty(), "Minter addresses vector cannot be empty");
+    }
     let mut deps = mock_dependencies_custom(&[]);
     let info = mock_info("creator", &[]);
     let msg = InstantiateMsg {
         kernel_address: MOCK_KERNEL_CONTRACT.to_string(),
+        // Owner is None in test context as it's handled by kernel contract
         owner: None,
         linked_cw721_address,
         authorized_origin_minter_addresses,
     };

57-66: Document the proof verification process.

Since this implements a PoW mechanism where difficulty increases by 150% per level, it would be helpful to document:

  1. How the proof is verified
  2. The difficulty increase mechanism
  3. The expected format/calculation of the nonce
+/// Submits a proof of work for a token to increase its level
+/// The proof is verified by:
+/// 1. Calculating hash(previous_hash + nonce)
+/// 2. Checking if the hash meets the current difficulty requirement
+/// 3. Difficulty increases by 150% for each level
+/// The nonce should be calculated to produce a hash with the required number of leading zeros
 pub fn submit_proof(
     deps: DepsMut<'_>,
     sender: &str,
     token_id: String,
     nonce: u128,
 ) -> Result<Response, ContractError> {

68-84: Simplify error handling and add return type documentation.

The query functions could be improved for better maintainability and clarity.

+/// Returns the linked CW721 contract address
+/// Returns GetLinkedCw721AddressResponse containing the address
 pub fn query_linked_cw721_address(
     deps: Deps,
 ) -> Result<GetLinkedCw721AddressResponse, ContractError> {
-    let res = query(deps, mock_env(), QueryMsg::GetLinkedCw721Address {});
-    match res {
-        Ok(res) => Ok(from_json(res).unwrap()),
-        Err(err) => Err(err),
-    }
+    query(deps, mock_env(), QueryMsg::GetLinkedCw721Address {})
+        .map_err(|e| e)
+        .and_then(|res| Ok(from_json(res)?))
 }

+/// Returns information about a specific PoW NFT
+/// Returns GetPowNFTResponse containing the NFT's level, difficulty, and last hash
 pub fn query_pow_nft(deps: Deps, token_id: String) -> Result<GetPowNFTResponse, ContractError> {
-    let res = query(deps, mock_env(), QueryMsg::GetPowNFT { token_id });
-    match res {
-        Ok(res) => Ok(from_json(res).unwrap()),
-        Err(err) => Err(err),
-    }
+    query(deps, mock_env(), QueryMsg::GetPowNFT { token_id })
+        .map_err(|e| e)
+        .and_then(|res| Ok(from_json(res)?))
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 257309c and c8953e6.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (15)
  • contracts/non-fungible-tokens/andromeda-pow-cw721/.cargo/config (1 hunks)
  • contracts/non-fungible-tokens/andromeda-pow-cw721/Cargo.toml (1 hunks)
  • contracts/non-fungible-tokens/andromeda-pow-cw721/examples/schema.rs (1 hunks)
  • contracts/non-fungible-tokens/andromeda-pow-cw721/src/contract.rs (1 hunks)
  • contracts/non-fungible-tokens/andromeda-pow-cw721/src/execute.rs (1 hunks)
  • contracts/non-fungible-tokens/andromeda-pow-cw721/src/interface.rs (1 hunks)
  • contracts/non-fungible-tokens/andromeda-pow-cw721/src/lib.rs (1 hunks)
  • contracts/non-fungible-tokens/andromeda-pow-cw721/src/query.rs (1 hunks)
  • contracts/non-fungible-tokens/andromeda-pow-cw721/src/state.rs (1 hunks)
  • contracts/non-fungible-tokens/andromeda-pow-cw721/src/testing/mock.rs (1 hunks)
  • contracts/non-fungible-tokens/andromeda-pow-cw721/src/testing/mock_querier.rs (1 hunks)
  • contracts/non-fungible-tokens/andromeda-pow-cw721/src/testing/mod.rs (1 hunks)
  • contracts/non-fungible-tokens/andromeda-pow-cw721/src/testing/tests.rs (1 hunks)
  • packages/andromeda-non-fungible-tokens/src/lib.rs (1 hunks)
  • packages/andromeda-non-fungible-tokens/src/pow_cw721.rs (1 hunks)
✅ Files skipped from review due to trivial changes (3)
  • packages/andromeda-non-fungible-tokens/src/lib.rs
  • contracts/non-fungible-tokens/andromeda-pow-cw721/src/testing/mod.rs
  • contracts/non-fungible-tokens/andromeda-pow-cw721/examples/schema.rs
🔇 Additional comments (9)
contracts/non-fungible-tokens/andromeda-pow-cw721/src/lib.rs (2)

1-4: LGTM! Well-organized module structure.

The modular organization follows best practices for Cosmos SDK contracts, with clear separation of concerns:

  • contract: Entry points and core logic
  • execute: Message execution handlers
  • query: Query handlers
  • state: Contract state management

9-12: Verify WASM target exclusion for interface module.

The interface module and PowCw721Contract are correctly excluded from WASM builds. However, let's verify that this contract is properly integrated with other non-WASM components that might depend on it.

✅ Verification successful

Based on the gathered information, I can now provide a final response:

WASM target exclusion is correctly implemented and safe.

The interface module and PowCw721Contract are properly excluded from WASM builds through the #[cfg(not(target_arch = "wasm32"))] attribute. The code shows:

  1. The interface is only used for testing and local development:
    • It's part of the non-WASM test infrastructure along with cw-multi-test and andromeda-testing
    • All test files and mock implementations are correctly excluded from WASM builds
  2. The Cargo.toml configuration properly handles the separation:
    • Test dependencies are correctly gated behind [target.'cfg(not(target_arch = "wasm32"))'.dependencies]
    • WASM-specific artifacts are properly excluded in the package configuration

No issues were found with the WASM target exclusion implementation.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any direct usage of PowCw721Contract in WASM-targeted code
# which could cause compilation errors

# Search for PowCw721Contract usage
rg "PowCw721Contract" --type rust

# Look for any potential WASM integration tests or examples
fd -e rs -e toml . | xargs rg "target_arch.*wasm32.*PowCw721Contract"

Length of output: 357


Script:

#!/bin/bash
# Let's check the interface module implementation and its usage patterns
# First, let's see the interface.rs content
cat contracts/non-fungible-tokens/andromeda-pow-cw721/src/interface.rs

# Check for any test modules or integration tests
fd -e rs . -t f | grep -i "test" | xargs cat

# Look for any dependencies in Cargo.toml that might use this contract
cat contracts/non-fungible-tokens/andromeda-pow-cw721/Cargo.toml

# Check for any potential cross-contract calls or imports
rg "use.*andromeda.*pow.*cw721" --type rust

Length of output: 109748


Script:

#!/bin/bash
# Let's check for any WASM-specific code or dependencies in the codebase
# First, check for any WASM-specific dependencies in Cargo.toml
cat contracts/non-fungible-tokens/andromeda-pow-cw721/Cargo.toml

# Check for any WASM-specific imports or uses in the codebase
rg "wasm|target_arch" --type rust contracts/non-fungible-tokens/andromeda-pow-cw721/

# Check for any test files that might verify WASM integration
fd -e rs . contracts/non-fungible-tokens/andromeda-pow-cw721/ | grep -i test | xargs cat

Length of output: 15862

contracts/non-fungible-tokens/andromeda-pow-cw721/src/testing/mock_querier.rs (2)

1-17: LGTM! Well-organized imports and constants.

The imports are logically grouped and the constants are appropriately named for mock testing purposes.


50-99: Add test coverage for error cases.

The mock querier implementation would benefit from additional test coverage to verify error handling paths.

Let's check the current test coverage:

Would you like me to help generate comprehensive test cases for the mock querier error paths?

contracts/non-fungible-tokens/andromeda-pow-cw721/src/testing/tests.rs (2)

1-14: LGTM! Well-organized test setup.

The imports and constants provide a clear foundation for testing different minter scenarios.


91-144: 🛠️ Refactor suggestion

Document proof validation logic and enhance test coverage.

The test cases use hardcoded nonce values without explaining how they were calculated or why they are valid/invalid. This makes it difficult to understand the proof validation logic.

  1. Add documentation explaining the proof validation algorithm and how valid nonces are calculated.
  2. Add tests for:
    • Concurrent proof submissions
    • Difficulty increase after successful proof
    • Edge cases near the difficulty threshold
/// Demonstrates how valid nonces are calculated
#[test]
fn test_proof_calculation_explanation() {
    // Add a test that shows step by step how a valid nonce is calculated
    // and why it meets the difficulty requirement
}

/// Tests concurrent proof submissions
#[test]
fn test_concurrent_proof_submissions() {
    // Add a test that simulates multiple users submitting proofs
    // for the same NFT concurrently
}

Let's verify the proof validation implementation:

contracts/non-fungible-tokens/andromeda-pow-cw721/.cargo/config (1)

1-4: LGTM!

The Cargo aliases are correctly defined and will help streamline development tasks.

contracts/non-fungible-tokens/andromeda-pow-cw721/src/interface.rs (1)

1-6: LGTM! Clean and well-structured interface implementation.

The interface follows standard Cosmos-SDK patterns and includes all necessary imports from the Andromeda ecosystem.

contracts/non-fungible-tokens/andromeda-pow-cw721/Cargo.toml (1)

1-48: Verify security of dependencies.

Let's check for any known vulnerabilities in the dependencies.

✅ Verification successful

Dependencies are using secure versions - no known vulnerabilities found

The key dependencies are using recent stable versions:

  • cosmwasm-std v1.5.8 (latest stable)
  • sha2 v0.10.8 (latest stable)

The codebase shows appropriate security awareness through documentation and comments. No security advisories or known vulnerabilities were found for the specified versions.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for security advisories in dependencies

# Check for security advisories in cosmwasm-std
gh api graphql -f query='
{
  securityVulnerabilities(first: 5, ecosystem: CARGO, package: "cosmwasm-std") {
    nodes {
      advisory {
        summary
        severity
        publishedAt
      }
      vulnerableVersionRange
      firstPatchedVersion {
        identifier
      }
    }
  }
}'

# Check for security advisories in sha2
gh api graphql -f query='
{
  securityVulnerabilities(first: 5, ecosystem: CARGO, package: "sha2") {
    nodes {
      advisory {
        summary
        severity
        publishedAt
      }
      vulnerableVersionRange
      firstPatchedVersion {
        identifier
      }
    }
  }
}'

Length of output: 1543


Script:

#!/bin/bash
# Let's try a different approach to check dependencies

# First, let's check if there's a Cargo.lock file to see exact versions
fd -t f "Cargo.lock" --exec cat {}

# Let's also check workspace dependencies in the root Cargo.toml
cat Cargo.toml

# Let's also look for any security-related comments or known issues in the codebase
rg -i "security|vulnerability|advisory" -g "*.{md,toml}"

Length of output: 65678


Script:

#!/bin/bash
# Let's check for specific versions of key dependencies and any security-related comments

# Check workspace dependencies in root Cargo.toml
rg -A 5 '\[workspace\.dependencies\]' Cargo.toml

# Check for any security advisories in README or other docs
rg -i "security|vulnerability|advisory" -g "*.md"

# Check specific versions of security-critical dependencies
rg -A 1 'sha2.*=|cosmwasm-std.*=' Cargo.toml

# Look for any security-related comments in the code
rg -i "security|vulnerability|advisory" -g "*.rs"

Length of output: 2973

#[cw_serde]
pub enum ExecuteMsg {
MintPowNFT {
owner: AndrAddr,
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Inconsistent address types for owner fields.

The owner field in MintPowNFT is of type AndrAddr, whereas in PowNFTInfo, the owner field is of type Addr. For consistency and to prevent potential type conversion errors, consider using the same address type for both fields. If AndrAddr provides additional functionality required elsewhere, you may convert it to Addr when necessary.

Comment on lines +123 to +134
pow_nft.difficulty = if pow_nft.difficulty >= 2 {
let next_difficulty = (pow_nft.difficulty as f64 * 1.5) as u64;
if next_difficulty > 128 {
return Err(ContractError::CustomError {
msg: format!(
"Max difficulty is 128. Next difficulty will be over 128. Current level: {:?}",
pow_nft.level
),
});
}
next_difficulty
} else {
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Avoid using floating-point arithmetic in smart contracts.

The difficulty adjustment uses floating-point arithmetic, which can lead to non-deterministic behavior and precision issues in smart contracts. It's recommended to use integer arithmetic to ensure deterministic and precise calculations.

Apply this diff to adjust the difficulty calculation:

 pow_nft.difficulty = if pow_nft.difficulty >= 2 {
-    let next_difficulty = (pow_nft.difficulty as f64 * 1.5) as u64;
+    let next_difficulty = pow_nft.difficulty * 3 / 2;
     if next_difficulty > 128 {
         return Err(ContractError::CustomError {
             msg: format!(

This change replaces the floating-point multiplication with integer arithmetic, ensuring consistent behavior across different platforms.

📝 Committable suggestion

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

Suggested change
pow_nft.difficulty = if pow_nft.difficulty >= 2 {
let next_difficulty = (pow_nft.difficulty as f64 * 1.5) as u64;
if next_difficulty > 128 {
return Err(ContractError::CustomError {
msg: format!(
"Max difficulty is 128. Next difficulty will be over 128. Current level: {:?}",
pow_nft.level
),
});
}
next_difficulty
} else {
pow_nft.difficulty = if pow_nft.difficulty >= 2 {
let next_difficulty = pow_nft.difficulty * 3 / 2;
if next_difficulty > 128 {
return Err(ContractError::CustomError {
msg: format!(
"Max difficulty is 128. Next difficulty will be over 128. Current level: {:?}",
pow_nft.level
),
});
}
next_difficulty
} else {

Comment on lines +114 to +116
let hash_value = u128::from_be_bytes(hash[0..16].try_into().unwrap());
let threshold = u128::MAX >> (pow_nft.difficulty as u32);

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Handle potential panics when converting hash bytes to u128.

The use of unwrap() in hash[0..16].try_into().unwrap() can cause a panic if the slice does not have the correct length. Consider handling the potential error using ? to propagate it properly.

Apply this diff to handle the error:

 let hash_value = u128::from_be_bytes(hash[0..16].try_into().unwrap());
+// Change to:
+let hash_value = u128::from_be_bytes(hash[0..16].try_into().map_err(|_| ContractError::CustomError {
+    msg: "Failed to convert hash bytes to u128.".to_string(),
+})?);

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

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)

30-30: Consider expanding the changelog entry with implementation details.

While the entry follows the correct format, consider adding more details about the key features, such as:

  • NFT leveling mechanics
  • 150% difficulty increase per level
  • Proof of Work challenge system

This would help users and developers better understand the significant features introduced.

Example expansion:

-Added PoW Cw721 ADO [(#697)](https://github.com/andromedaprotocol/andromeda-core/pull/697)
+Added PoW Cw721 ADO with NFT leveling system, 150% difficulty scaling, and Bitcoin-style PoW challenges [(#697)](https://github.com/andromedaprotocol/andromeda-core/pull/697)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between c8953e6 and 6e9ea18.

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

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

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 6e9ea18 and feb0aa6.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (4)
  • CHANGELOG.md (1 hunks)
  • contracts/non-fungible-tokens/andromeda-pow-cw721/src/execute.rs (1 hunks)
  • contracts/non-fungible-tokens/andromeda-pow-cw721/src/testing/mock.rs (1 hunks)
  • packages/andromeda-non-fungible-tokens/src/pow_cw721.rs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/andromeda-non-fungible-tokens/src/pow_cw721.rs
  • CHANGELOG.md
  • contracts/non-fungible-tokens/andromeda-pow-cw721/src/testing/mock.rs
🔇 Additional comments (3)
contracts/non-fungible-tokens/andromeda-pow-cw721/src/execute.rs (3)

23-23: ⚠️ Potential issue

Remove incorrect usage of as_ref()

The ExecuteMsg enum doesn't implement AsRef, making this call invalid.

-msg.as_ref(),
+&msg,

125-136: ⚠️ Potential issue

Replace floating-point arithmetic with integer operations

Using floating-point arithmetic in smart contracts can lead to non-deterministic behavior.


116-118: ⚠️ Potential issue

Handle potential panics in hash conversion

The unwrap usage can cause panics if the slice conversion fails.

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 feb0aa6 and b3682d1.

📒 Files selected for processing (2)
  • contracts/non-fungible-tokens/andromeda-pow-cw721/src/execute.rs (1 hunks)
  • contracts/non-fungible-tokens/andromeda-pow-cw721/src/testing/tests.rs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • contracts/non-fungible-tokens/andromeda-pow-cw721/src/testing/tests.rs
🔇 Additional comments (6)
contracts/non-fungible-tokens/andromeda-pow-cw721/src/execute.rs (6)

1-16: LGTM! All necessary imports are present and well-organized.

The imports cover all required functionality including Cosmos SDK, Andromeda framework, and cryptographic operations.


54-58: LGTM! Proper validation of base_difficulty parameter.

The implementation correctly validates that base_difficulty is within acceptable bounds (1-128).


23-24: ⚠️ Potential issue

Remove incorrect as_ref() usage

The ExecuteMsg enum doesn't implement AsRef, making this call invalid. This needs to be fixed to ensure proper message handling.

-        msg.as_ref(),
+        &msg,

86-91: 🛠️ Refactor suggestion

Enhance initial hash entropy

Using only block height for the initial hash makes it predictable. Consider adding more entropy sources.

 let block_height = ctx.env.block.height;
+let block_time = ctx.env.block.time.nanos();
+let sender = ctx.info.sender.as_bytes();
 
 let mut hasher = Sha256::new();
 hasher.update(block_height.to_be_bytes());
+hasher.update(block_time.to_be_bytes());
+hasher.update(sender);
 let last_hash = hasher.finalize().to_vec();

131-142: ⚠️ Potential issue

Replace floating-point arithmetic with integer operations

Using floating-point arithmetic in smart contracts can lead to non-deterministic behavior.

-        let next_difficulty = (pow_nft.difficulty as f64 * 1.5) as u64;
+        let next_difficulty = pow_nft.difficulty * 3 / 2;

122-124: ⚠️ Potential issue

Replace unwrap() with proper error handling

Using unwrap() can cause panics. Implement proper error handling for the byte conversion.

-    let hash_value = u128::from_be_bytes(hash[0..16].try_into().unwrap());
+    let hash_value = u128::from_be_bytes(hash[0..16].try_into().map_err(|_| ContractError::CustomError {
+        msg: "Failed to convert hash bytes to u128".to_string(),
+    })?);

Likely invalid or redundant comment.

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 (1)
contracts/non-fungible-tokens/andromeda-pow-cw721/src/execute.rs (1)

131-144: Consider implementing difficulty retargeting mechanism

The current implementation increases difficulty by a fixed percentage. Consider implementing a more sophisticated difficulty adjustment algorithm that takes into account:

  • Time between proof submissions
  • Network hash rate
  • Target block time (like Bitcoin's 10-minute target)

This would help maintain consistent proof-of-work intervals regardless of network computing power.

Would you like me to provide an implementation of a more sophisticated difficulty adjustment algorithm?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between b3682d1 and c053ef6.

📒 Files selected for processing (1)
  • contracts/non-fungible-tokens/andromeda-pow-cw721/src/execute.rs (1 hunks)
🔇 Additional comments (1)
contracts/non-fungible-tokens/andromeda-pow-cw721/src/execute.rs (1)

23-24: ⚠️ Potential issue

Replace msg.as_ref() with proper message serialization

The ExecuteMsg type doesn't implement AsRef, so this will fail to compile.

-msg.as_ref(),
+&msg,

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 (3)
contracts/non-fungible-tokens/andromeda-pow-cw721/src/execute.rs (3)

37-37: Improve error handling for unknown message variants

Instead of delegating unknown variants to ADOContract::default().execute(), consider explicitly handling all possible message variants to make the code more maintainable and prevent potential security issues.

-        _ => ADOContract::default().execute(ctx, msg),
+        ExecuteMsg::Other(msg) => ADOContract::default().execute(ctx, ExecuteMsg::Other(msg)),

110-113: Add event emission for NFT minting

The response should include an event for the minting operation to help indexers track NFT creation.

     Ok(Response::new()
         .add_message(mint_msg)
         .add_attribute("method", "mint_pow_nft")
-        .add_attribute("sender", sender))
+        .add_attribute("sender", sender)
+        .add_attribute("token_id", token_id.clone())
+        .add_attribute("base_difficulty", base_difficulty.to_string())
+        .add_event(
+            Event::new("pow_nft_minted")
+                .add_attribute("token_id", token_id)
+                .add_attribute("owner", owner_addr.to_string())
+                .add_attribute("base_difficulty", base_difficulty.to_string())
+        ))

119-119: Consider using a larger integer type for the solution parameter

Using u128 for the solution might be limiting as the difficulty increases. Consider using a string or byte array to allow for arbitrary-length solutions in future updates.

-    solution: u128,
+    solution: String, // or Vec<u8>

Note: This change would require adjusting the solution processing logic accordingly.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between c053ef6 and 9771873.

📒 Files selected for processing (1)
  • contracts/non-fungible-tokens/andromeda-pow-cw721/src/execute.rs (1 hunks)

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

🧹 Outside diff range and nitpick comments (3)
contracts/non-fungible-tokens/andromeda-pow-cw721/Cargo.toml (3)

34-34: Consider using workspace version for sha2

Other dependencies use workspace versioning, but sha2 has a direct version specification. Consider moving this to the workspace level for consistent dependency management.


36-36: Remove commented out dependencies

There are commented out dependencies that should be either removed or uncommented if needed:

  • Line 36: hex = { version = "0.4.3" }
  • Line 45: cw-orch-daemon = "0.24.2"

Also applies to: 45-45


27-40: Verify dependencies for PoW implementation

The current dependencies cover NFT functionality through cw721 and hashing through sha2. For a PoW implementation, consider if additional dependencies are needed for:

  • Difficulty adjustment calculations
  • Nonce validation
  • Memory-hard hashing (optional, for ASIC resistance)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 9771873 and 309cf93.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (2)
  • CHANGELOG.md (1 hunks)
  • contracts/non-fungible-tokens/andromeda-pow-cw721/Cargo.toml (1 hunks)
🔇 Additional comments (2)
contracts/non-fungible-tokens/andromeda-pow-cw721/Cargo.toml (2)

5-6: Verify Rust version requirement

The specified Rust version 1.75.0 is quite recent. Consider if this strict requirement is necessary or if the contract could work with an earlier stable version to ensure broader compatibility.

✅ Verification successful

Based on the output, I can see that all contracts in the workspace consistently use Rust version 1.75.0, with only one exception (andromeda-kernel using 1.65.0). Since this is a consistent pattern across the codebase and represents an intentional choice for the project, I can generate the final response:

Rust version requirement is consistent with workspace

The specified Rust version 1.75.0 aligns with the version used across most packages in the workspace. This appears to be an intentional standardization across the project.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if other contracts in the workspace use different Rust versions
fd -e toml -x grep -l "rust-version" {} \; | xargs cat

Length of output: 60148


41-44: Verify test coverage with optional testing dependencies

Since cw-multi-test and andromeda-testing are marked as optional dependencies, ensure that the test suite provides adequate coverage when these features are disabled.

✅ Verification successful

Tests are properly implemented without optional dependencies

The contract has a comprehensive test suite that uses Cosmos-SDK's native testing utilities (cosmwasm_std::testing) instead of the optional dependencies. The tests include:

  • Proper initialization tests
  • Minting functionality tests
  • Token-specific operations tests
  • Custom mock querier implementation

The test implementation is robust without relying on cw-multi-test or andromeda-testing, making the optional nature of these dependencies appropriate.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for test files and their coverage
fd -e rs -x grep -l "#[test]" {} \;

Length of output: 91


Script:

#!/bin/bash
# Check test files in the specific contract directory
fd -e rs . contracts/non-fungible-tokens/andromeda-pow-cw721/ -x grep -l "#[test]"

# Check if there are any test modules or test functions
rg -l "mod tests" contracts/non-fungible-tokens/andromeda-pow-cw721/
rg "#\[test\]" contracts/non-fungible-tokens/andromeda-pow-cw721/ -A 1

# Check if there are any cfg test attributes
rg "cfg\(test\)" contracts/non-fungible-tokens/andromeda-pow-cw721/

Length of output: 1166


Script:

#!/bin/bash
# Check if tests use these optional dependencies
rg "use (cw_multi_test|andromeda_testing)" contracts/non-fungible-tokens/andromeda-pow-cw721/src/testing/

# Check for feature flags in test modules
rg "cfg\(feature" contracts/non-fungible-tokens/andromeda-pow-cw721/src/testing/

# Look at the test module setup
head -n 20 contracts/non-fungible-tokens/andromeda-pow-cw721/src/testing/mod.rs

Length of output: 311


Script:

#!/bin/bash
# Check the content of mock files to see testing setup
cat contracts/non-fungible-tokens/andromeda-pow-cw721/src/testing/mock.rs
cat contracts/non-fungible-tokens/andromeda-pow-cw721/src/testing/mock_querier.rs

# Check if cw-orch is used in tests
rg "use cw_orch" contracts/non-fungible-tokens/andromeda-pow-cw721/

Length of output: 6433

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

1 participant