Skip to content

Conversation

shumkov
Copy link
Collaborator

@shumkov shumkov commented Sep 30, 2025

Issue being fixed or feature implemented

We need to create DataContract from JSON definition

What was done?

  • Added the DataContract.fromJSON method and export DataContract

How Has This Been Tested?

Added unit test

Breaking Changes

None

Checklist:

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

For repository code-owners and collaborators only

  • I have assigned this pull request to a milestone

Summary by CodeRabbit

  • New Features

    • DataContract is now available in the JavaScript SDK and can be created from JSON with platform-version validation and JSON round-tripping.
    • SDK re-exports underlying wasm types so consumers can access DataContract and related types directly.
    • Fetch API now returns the exposed DataContract type.
  • Tests

    • Added unit tests and fixtures verifying DataContract creation, ID consistency, JSON round-trips, instance assertions, and cleanup.
  • Chores

    • Updated several runtime dependencies (including logging and docker-related packages).

@shumkov shumkov added this to the v2.1.0 milestone Sep 30, 2025
@shumkov shumkov self-assigned this Sep 30, 2025
Copy link
Contributor

coderabbitai bot commented Sep 30, 2025

Walkthrough

Replaces explicit wasm re-exports with a wildcard export in js-evo-sdk, exposes DataContractWasm as DataContract to JS with a new from_json(json, platform_version) constructor, updates façade typings and tests to use DataContract, adds wasm and JS tests/fixture, and bumps several runtime dependencies.

Changes

Cohort / File(s) Summary of Changes
JS SDK exports & façade
packages/js-evo-sdk/src/sdk.ts, packages/js-evo-sdk/src/contracts/facade.ts
sdk.ts now uses export * from './wasm.js' replacing prior named re-exports; facade.ts changes fetch return type from Promise<wasm.DataContractWasm> to Promise<wasm.DataContract> (type annotation update).
JS SDK tests (functional & unit)
packages/js-evo-sdk/tests/functional/contracts.spec.mjs, packages/js-evo-sdk/tests/unit/facades/contracts.spec.mjs
Tests import DataContract from the SDK and assert fetched objects are instances of DataContract; unit tests add a dataContract fixture (via Object.create(wasmSDKPackage.DataContract.prototype)), adjust stubs to return the fixture, and add extra wasm method stubs in beforeEach.
WASM bindings & constructor
packages/wasm-sdk/src/dpp.rs
DataContractWasm is exposed to JS as DataContract (#[wasm_bindgen(js_name = "DataContract")] / js_class=DataContract); adds from_json(json: &JsValue, platform_version: u32) -> Result<DataContractWasm, WasmSdkError> to parse JSON into a DataContract with platform-version validation and error mapping.
WASM unit tests & fixture
packages/wasm-sdk/tests/unit/data-contract.spec.mjs, packages/wasm-sdk/tests/unit/fixtures/data-contract-crypto-card-game.mjs
Adds test that initializes the compressed SDK, calls DataContract.from_json(...), asserts contract creation and id, round-trips via toJSON, frees the contract; adds the data-contract-crypto-card-game JSON fixture.
Dependency / lockfile updates
.pnp.cjs, packages/dapi/package.json, packages/dashmate/package.json
Lockfile (.pnp.cjs) updated with multiple runtime dependency bumps (pino 8→9, dockerode 4.0.5→4.0.9, thread-stream, sonic-boom, pino-abstract-transport, removal of fast-redact, addition of slow-redact, etc.). packages/dapi/package.json and packages/dashmate/package.json updated to match bumped dependency versions.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant App as JS App
  participant SDK as js-evo-sdk (export *)
  participant WASM as wasm DataContract (DataContract)
  participant PV as PlatformVersion Resolver
  participant DC as Core DataContract

  App->>SDK: import { DataContract } (via export * from './wasm.js')
  App->>WASM: DataContract.from_json(json, platform_version)
  WASM->>PV: resolve(platform_version)
  alt valid version
    PV-->>WASM: PlatformVersion
    WASM->>DC: parse JSON & construct DataContract
    DC-->>WASM: DataContract internal
    WASM-->>App: DataContract instance (WASM wrapper)
    App->>WASM: instance.toJSON()
    WASM-->>App: contract JSON
  else invalid version or parse error
    WASM-->>App: WasmSdkError (invalid version / parse failure)
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • feat: evo sdk #2771 — touches the same WASM export symbols and SDK re-export surface (verifyIdentityResponse, verifyDataContract, verifyDocuments, start) and is directly related to export changes.

Suggested labels

rs-sdk

Suggested reviewers

  • QuantumExplorer

Poem

A hop, a spec, a contract bright,
From JSON tucked into wasm's light.
I nibble tests, IDs align,
Round-trip true — the fields all fine.
Thump-thump! exported now — hooray, delight. 🐇✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title succinctly describes the new SDK feature of creating or exposing a DataContract from JSON, directly reflecting the addition of DataContract.fromJSON and the export of the DataContract class in the changeset.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/data-contract-from-json

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d2d8cb2 and 77c0cc0.

⛔ Files ignored due to path filters (16)
  • .yarn/cache/dockerode-npm-4.0.9-89c765574b-58bb4f3965.zip is excluded by !**/.yarn/**, !**/*.zip
  • .yarn/cache/fast-redact-npm-3.3.0-2f2f249914-a69c5cb523.zip is excluded by !**/.yarn/**, !**/*.zip
  • .yarn/cache/pino-abstract-transport-npm-2.0.0-696dba31d0-e5699ecb06.zip is excluded by !**/.yarn/**, !**/*.zip
  • .yarn/cache/pino-npm-8.16.2-ab350f6df7-d2860167dd.zip is excluded by !**/.yarn/**, !**/*.zip
  • .yarn/cache/pino-npm-9.13.0-1ccb158e52-deaad84f8f.zip is excluded by !**/.yarn/**, !**/*.zip
  • .yarn/cache/pino-std-serializers-npm-6.2.2-0e907a1130-a00cdff4e1.zip is excluded by !**/.yarn/**, !**/*.zip
  • .yarn/cache/pino-std-serializers-npm-7.0.0-94d470ae0c-884e08f65a.zip is excluded by !**/.yarn/**, !**/*.zip
  • .yarn/cache/process-warning-npm-2.3.1-c08c6a464f-1c27241fff.zip is excluded by !**/.yarn/**, !**/*.zip
  • .yarn/cache/process-warning-npm-5.0.0-7999058ecd-10f3e00ac9.zip is excluded by !**/.yarn/**, !**/*.zip
  • .yarn/cache/slow-redact-npm-0.3.0-d3e132569d-01eb265292.zip is excluded by !**/.yarn/**, !**/*.zip
  • .yarn/cache/sonic-boom-npm-4.2.0-b2baf3f5bd-385ef7fb5e.zip is excluded by !**/.yarn/**, !**/*.zip
  • .yarn/cache/tar-fs-npm-3.0.9-3078dff77a-00e194ef36.zip is excluded by !**/.yarn/**, !**/*.zip
  • .yarn/cache/tar-fs-npm-3.1.1-2a32a81dd7-f7f7540b56.zip is excluded by !**/.yarn/**, !**/*.zip
  • .yarn/cache/thread-stream-npm-2.4.1-3f89bca0b7-baac5bf555.zip is excluded by !**/.yarn/**, !**/*.zip
  • .yarn/cache/thread-stream-npm-3.1.0-ac5663dfb7-ea2d816c4f.zip is excluded by !**/.yarn/**, !**/*.zip
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (3)
  • .pnp.cjs (13 hunks)
  • packages/dapi/package.json (1 hunks)
  • packages/dashmate/package.json (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (wasm-sdk) / Unused dependencies
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build JS packages / Build JS
  • GitHub Check: Rust crates security audit
🔇 Additional comments (1)
packages/dapi/package.json (1)

54-55: Confirm Pino v9 breaking-change coverage

This jumps Pino from v8 to v9. That major release brought breaking changes (logger options, transport APIs, ESM/TypeScript tweaks). Please confirm our runtime logger configuration and transports were updated accordingly, or call out any remaining work.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

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

🧹 Nitpick comments (4)
packages/wasm-sdk/src/dpp.rs (1)

312-328: Well-structured constructor with proper error handling.

The from_json method correctly:

  • Resolves platform version with error mapping
  • Deserializes JSON to the internal format
  • Creates a DataContract instance
  • Wraps errors appropriately

Minor note: The json.clone() on line 320 may be unnecessary since serde_wasm_bindgen::from_value likely doesn't need ownership. This is a minor optimization opportunity but not incorrect.

Consider removing the clone if not required:

-        let data_contract = DataContract::from_json(serde_wasm_bindgen::from_value(json.clone()).map_err(|e| {
+        let data_contract = DataContract::from_json(serde_wasm_bindgen::from_value(json).map_err(|e| {
packages/wasm-sdk/tests/unit/data-contract.spec.mjs (2)

11-22: Expand test coverage for the new API.

The test validates basic functionality but could be more comprehensive. Consider adding tests for:

  • Invalid JSON input (malformed, missing required fields)
  • Invalid platform version
  • Error handling and error messages
  • Memory leak verification with multiple allocations/frees
  • Edge cases in the fixture data

14-15: Use more descriptive assertion messages.

The test uses expect(contract).to.be.ok() without a failure message. Consider adding descriptive messages to aid debugging when tests fail.

-    expect(contract).to.be.ok();
-    expect(contract.id()).to.equal(contractFixture.id);
+    expect(contract, 'DataContract should be created from JSON').to.be.ok();
+    expect(contract.id(), 'Contract ID should match fixture').to.equal(contractFixture.id);
packages/wasm-sdk/tests/unit/fixtures/data-contract-crypto-card-game.mjs (1)

1-96: Consider extracting fixture to a JSON file.

The fixture is defined as a JavaScript object. For better maintainability and reusability, consider storing it as a JSON file that can be imported. This would also make it easier to validate against schemas and use in other contexts.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f9d09e7 and 26ee228.

📒 Files selected for processing (4)
  • packages/js-evo-sdk/src/sdk.ts (1 hunks)
  • packages/wasm-sdk/src/dpp.rs (2 hunks)
  • packages/wasm-sdk/tests/unit/data-contract.spec.mjs (1 hunks)
  • packages/wasm-sdk/tests/unit/fixtures/data-contract-crypto-card-game.mjs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
packages/wasm-sdk/**

📄 CodeRabbit inference engine (CLAUDE.md)

Keep WASM SDK docs in sync (run generate_docs.py) when updating the WASM SDK

Files:

  • packages/wasm-sdk/tests/unit/fixtures/data-contract-crypto-card-game.mjs
  • packages/wasm-sdk/src/dpp.rs
  • packages/wasm-sdk/tests/unit/data-contract.spec.mjs
packages/**/tests/**

📄 CodeRabbit inference engine (AGENTS.md)

Place unit and integration tests alongside each package in packages//tests

Files:

  • packages/wasm-sdk/tests/unit/fixtures/data-contract-crypto-card-game.mjs
  • packages/wasm-sdk/tests/unit/data-contract.spec.mjs
packages/**/**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

packages/**/**/*.{js,ts,jsx,tsx}: Adhere to ESLint with Airbnb/TypeScript configs for JS/TS code
Use camelCase for JS/TS variables and functions
Use PascalCase for JS/TS classes
Prefer kebab-case filenames within JS packages

Files:

  • packages/js-evo-sdk/src/sdk.ts
**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.rs: Format Rust code with cargo fmt
Run Clippy linter for Rust code

Files:

  • packages/wasm-sdk/src/dpp.rs
🧬 Code graph analysis (3)
packages/wasm-sdk/tests/unit/fixtures/data-contract-crypto-card-game.mjs (1)
packages/wasm-sdk/tests/unit/data-contract.spec.mjs (1)
  • contract (12-12)
packages/wasm-sdk/src/dpp.rs (1)
packages/wasm-sdk/src/error.rs (2)
  • invalid_argument (73-75)
  • serialization (77-79)
packages/wasm-sdk/tests/unit/data-contract.spec.mjs (1)
packages/wasm-sdk/tests/unit/fixtures/data-contract-crypto-card-game.mjs (1)
  • contract (1-96)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (wasm-sdk) / Unused dependencies
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Formatting
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build JS packages / Build JS
  • GitHub Check: Rust crates security audit
🔇 Additional comments (7)
packages/wasm-sdk/src/dpp.rs (3)

297-298: LGTM! Clean binding structure.

The js_name attribute correctly exposes DataContractWasm as DataContract to JavaScript, and the tuple struct wrapper is a clean pattern for WASM bindings.


306-311: LGTM! Correct JS class binding.

The js_class attribute properly associates the implementation block with the JavaScript DataContract class, and the id() method correctly encodes the identifier as Base58.


330-343: toJSON serialization is correct
The use of PlatformVersion::first() in toJSON across both wasm-dpp and wasm-sdk is intentional—serializations always emit the current first protocol version, while from_json accepts a version to support legacy formats. No changes required.

packages/js-evo-sdk/src/sdk.ts (1)

148-148: LGTM! Clean export addition.

The DataContract export follows the established pattern and properly exposes the new functionality to SDK consumers.

packages/wasm-sdk/tests/unit/fixtures/data-contract-crypto-card-game.mjs (2)

74-93: Ignore incorrect index property fix suggestion

The existing index definitions ({ name: 'asc' } and { rarity: 'asc' }) already map property names to sort order correctly—quoting the keys is optional and doesn’t change behavior.

Likely an incorrect or invalid review comment.


64-72: Verify $createdAt and $updatedAt in required
The required list includes $createdAt and $updatedAt, but neither is defined under properties. Confirm per the Data Contract specification that system‐generated fields may be listed here, or remove them if they’re not intended.

packages/wasm-sdk/tests/unit/data-contract.spec.mjs (1)

4-4: Avoid hardcoded PLATFORM_VERSION in test
Replace the literal 1 with the SDK’s version helper (e.g. call getLatestVersionNumber() or expose a getFirstVersion() method) and verify it matches PlatformVersion::first().protocol_version.

Copy link
Collaborator

@thephez thephez Oct 2, 2025

Choose a reason for hiding this comment

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

What do you think about using a contract that includes tokens and groups also in the tests? Like https://testnet.platform-explorer.com/dataContract/Afk9QSj9UDE14K1y9y3iSx6kUSm5LLmhbdAvPvWL4P2i (schema below). Really tests should include an example of all contract version so any issues are caught, right?

v1 contract with documents, tokens, and groups
{ "$format_version": "1", "id": "Afk9QSj9UDE14K1y9y3iSx6kUSm5LLmhbdAvPvWL4P2i", "config": { "$format_version": "1", "canBeDeleted": false, "readonly": false, "keepsHistory": false, "documentsKeepHistoryContractDefault": false, "documentsMutableContractDefault": true, "documentsCanBeDeletedContractDefault": true, "requiresIdentityEncryptionBoundedKey": null, "requiresIdentityDecryptionBoundedKey": null, "sizedIntegerTypes": true }, "version": 1, "ownerId": "7XcruVSsGQVSgTcmPewaE4tXLutnW1F6PXxwMbo8GYQC", "schemaDefs": null, "documentSchemas": { "card": { "type": "object", "documentsMutable": false, "canBeDeleted": true, "transferable": 1, "tradeMode": 1, "creationRestrictionMode": 1, "properties": { "name": { "type": "string", "description": "Name of the card", "minLength": 0, "maxLength": 63, "position": 0 }, "description": { "type": "string", "description": "Description of the card", "minLength": 0, "maxLength": 256, "position": 1 }, "attack": { "type": "integer", "description": "Attack power of the card", "position": 2 }, "defense": { "type": "integer", "description": "Defense level of the card", "position": 3 } }, "indices": [ { "name": "owner", "properties": [ { "$ownerId": "asc" } ] }, { "name": "attack", "properties": [ { "attack": "asc" } ] }, { "name": "defense", "properties": [ { "defense": "asc" } ] } ], "required": [ "name", "attack", "defense" ], "additionalProperties": false } }, "createdAt": 1756237255149, "updatedAt": null, "createdAtBlockHeight": 174305, "updatedAtBlockHeight": null, "createdAtEpoch": 9690, "updatedAtEpoch": null, "groups": { "0": { "$format_version": "0", "members": { "7XcruVSsGQVSgTcmPewaE4tXLutnW1F6PXxwMbo8GYQC": 1, "HJDxtN6FJF3U3T9TMLWCqudfJ5VRkaUrxTsRp36djXAG": 1 }, "required_power": 2 } }, "tokens": { "0": { "$format_version": "0", "conventions": { "$format_version": "0", "localizations": { "en": { "$format_version": "0", "shouldCapitalize": true, "singularForm": "stt-99", "pluralForm": "stt-99s" } }, "decimals": 0 }, "conventionsChangeRules": { "V0": { "authorized_to_make_change": "ContractOwner", "admin_action_takers": "ContractOwner", "changing_authorized_action_takers_to_no_one_allowed": true, "changing_admin_action_takers_to_no_one_allowed": true, "self_changing_admin_action_takers_allowed": true } }, "baseSupply": 100, "maxSupply": null, "keepsHistory": { "$format_version": "0", "keepsTransferHistory": true, "keepsFreezingHistory": true, "keepsMintingHistory": true, "keepsBurningHistory": true, "keepsDirectPricingHistory": true, "keepsDirectPurchaseHistory": true }, "startAsPaused": false, "allowTransferToFrozenBalance": true, "maxSupplyChangeRules": { "V0": { "authorized_to_make_change": "ContractOwner", "admin_action_takers": "ContractOwner", "changing_authorized_action_takers_to_no_one_allowed": true, "changing_admin_action_takers_to_no_one_allowed": true, "self_changing_admin_action_takers_allowed": true } }, "distributionRules": { "$format_version": "0", "perpetualDistribution": { "$format_version": "0", "distributionType": { "BlockBasedDistribution": { "interval": 100, "function": { "FixedAmount": { "amount": 1 } } } }, "distributionRecipient": "ContractOwner" }, "perpetualDistributionRules": { "V0": { "authorized_to_make_change": "ContractOwner", "admin_action_takers": "ContractOwner", "changing_authorized_action_takers_to_no_one_allowed": true, "changing_admin_action_takers_to_no_one_allowed": true, "self_changing_admin_action_takers_allowed": true } }, "preProgrammedDistribution": null, "newTokensDestinationIdentity": "7XcruVSsGQVSgTcmPewaE4tXLutnW1F6PXxwMbo8GYQC", "newTokensDestinationIdentityRules": { "V0": { "authorized_to_make_change": "ContractOwner", "admin_action_takers": "ContractOwner", "changing_authorized_action_takers_to_no_one_allowed": true, "changing_admin_action_takers_to_no_one_allowed": true, "self_changing_admin_action_takers_allowed": true } }, "mintingAllowChoosingDestination": false, "mintingAllowChoosingDestinationRules": { "V0": { "authorized_to_make_change": "ContractOwner", "admin_action_takers": "ContractOwner", "changing_authorized_action_takers_to_no_one_allowed": true, "changing_admin_action_takers_to_no_one_allowed": true, "self_changing_admin_action_takers_allowed": true } }, "changeDirectPurchasePricingRules": { "V0": { "authorized_to_make_change": "ContractOwner", "admin_action_takers": "ContractOwner", "changing_authorized_action_takers_to_no_one_allowed": true, "changing_admin_action_takers_to_no_one_allowed": true, "self_changing_admin_action_takers_allowed": true } } }, "marketplaceRules": { "$format_version": "0", "tradeMode": "NotTradeable", "tradeModeChangeRules": { "V0": { "authorized_to_make_change": "ContractOwner", "admin_action_takers": "ContractOwner", "changing_authorized_action_takers_to_no_one_allowed": true, "changing_admin_action_takers_to_no_one_allowed": true, "self_changing_admin_action_takers_allowed": true } } }, "manualMintingRules": { "V0": { "authorized_to_make_change": "ContractOwner", "admin_action_takers": "ContractOwner", "changing_authorized_action_takers_to_no_one_allowed": true, "changing_admin_action_takers_to_no_one_allowed": true, "self_changing_admin_action_takers_allowed": true } }, "manualBurningRules": { "V0": { "authorized_to_make_change": "ContractOwner", "admin_action_takers": "ContractOwner", "changing_authorized_action_takers_to_no_one_allowed": true, "changing_admin_action_takers_to_no_one_allowed": true, "self_changing_admin_action_takers_allowed": true } }, "freezeRules": { "V0": { "authorized_to_make_change": "ContractOwner", "admin_action_takers": "ContractOwner", "changing_authorized_action_takers_to_no_one_allowed": true, "changing_admin_action_takers_to_no_one_allowed": true, "self_changing_admin_action_takers_allowed": true } }, "unfreezeRules": { "V0": { "authorized_to_make_change": "ContractOwner", "admin_action_takers": "ContractOwner", "changing_authorized_action_takers_to_no_one_allowed": true, "changing_admin_action_takers_to_no_one_allowed": true, "self_changing_admin_action_takers_allowed": true } }, "destroyFrozenFundsRules": { "V0": { "authorized_to_make_change": "ContractOwner", "admin_action_takers": "ContractOwner", "changing_authorized_action_takers_to_no_one_allowed": true, "changing_admin_action_takers_to_no_one_allowed": true, "self_changing_admin_action_takers_allowed": true } }, "emergencyActionRules": { "V0": { "authorized_to_make_change": "ContractOwner", "admin_action_takers": "ContractOwner", "changing_authorized_action_takers_to_no_one_allowed": true, "changing_admin_action_takers_to_no_one_allowed": true, "self_changing_admin_action_takers_allowed": true } }, "mainControlGroup": 0, "mainControlGroupCanBeModified": "ContractOwner", "description": null } }, "keywords": [ "stt-99" ], "description": null }

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Sounds good. Let's do it in a separate PR though.

@shumkov shumkov merged commit aaea36f into v2.1-dev Oct 3, 2025
35 checks passed
@shumkov shumkov deleted the feat/data-contract-from-json branch October 3, 2025 08:45
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