-
Notifications
You must be signed in to change notification settings - Fork 39
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(sdk): add NFT actions in the JS Dash SDK #2444
base: v2.0-dev
Are you sure you want to change the base?
Conversation
…/document-transfer
…/document-transfer
Warning Rate limit exceeded@pshenmic has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 27 minutes and 52 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (7)
WalkthroughThe pull request introduces new document-related methods for transferring, updating prices, and purchasing documents across two key files: Changes
Sequence DiagramsequenceDiagram
participant User
participant Platform
participant Document
participant StateTransition
User->>Platform: transfer/updatePrice/purchase document
Platform->>Document: create state transition
Document->>StateTransition: generate transition with updated metadata
StateTransition-->>Platform: return transition
Platform-->>User: confirm document operation
Possibly related PRs
Suggested reviewers
Poem
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? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
# Conflicts: # packages/js-dash-sdk/src/SDK/Client/Platform/Platform.ts # packages/wasm-dpp/src/document/extended_document.rs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
packages/js-dash-sdk/src/SDK/Client/Platform/Platform.ts
(3 hunks)packages/wasm-dpp/src/document/extended_document.rs
(3 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
packages/js-dash-sdk/src/SDK/Client/Platform/Platform.ts
[error] 64-64: Don't use 'Function' as a type.
Prefer explicitly define the function shape. This type accepts any function-like value, which can be a common source of bugs.
(lint/complexity/noBannedTypes)
[error] 65-65: Don't use 'Function' as a type.
Prefer explicitly define the function shape. This type accepts any function-like value, which can be a common source of bugs.
(lint/complexity/noBannedTypes)
[error] 66-66: Don't use 'Function' as a type.
Prefer explicitly define the function shape. This type accepts any function-like value, which can be a common source of bugs.
(lint/complexity/noBannedTypes)
⏰ Context from checks skipped due to timeout of 90000ms (7)
- GitHub Check: Rust packages (wasm-dpp) / Tests
- GitHub Check: Rust packages (wasm-dpp) / Linting
- GitHub Check: Rust packages (wasm-dpp) / Formatting
- GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
- 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
🔇 Additional comments (2)
packages/js-dash-sdk/src/SDK/Client/Platform/Platform.ts (2)
12-14
: LGTM! New document method imports are properly organized.The imports for NFT-related document methods are correctly added and follow the existing import pattern.
174-176
: LGTM! Method bindings are correctly implemented.The new NFT-related methods are properly bound to the Platform instance in the constructor.
transfer: Function, | ||
updatePrice: Function, | ||
purchase: Function, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Define explicit function signatures instead of using 'Function' type.
Using the generic 'Function' type reduces type safety. Consider defining explicit function signatures for better type checking and IDE support.
- transfer: Function,
- updatePrice: Function,
- purchase: Function,
+ transfer: (document: Document, recipient: Identifier) => Promise<StateTransitionResult>,
+ updatePrice: (document: Document, price: number) => Promise<StateTransitionResult>,
+ purchase: (document: Document, amount: number) => Promise<StateTransitionResult>,
📝 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.
transfer: Function, | |
updatePrice: Function, | |
purchase: Function, | |
transfer: (document: Document, recipient: Identifier) => Promise<StateTransitionResult>, | |
updatePrice: (document: Document, price: number) => Promise<StateTransitionResult>, | |
purchase: (document: Document, amount: number) => Promise<StateTransitionResult>, |
🧰 Tools
🪛 Biome (1.9.4)
[error] 64-64: Don't use 'Function' as a type.
Prefer explicitly define the function shape. This type accepts any function-like value, which can be a common source of bugs.
(lint/complexity/noBannedTypes)
[error] 65-65: Don't use 'Function' as a type.
Prefer explicitly define the function shape. This type accepts any function-like value, which can be a common source of bugs.
(lint/complexity/noBannedTypes)
[error] 66-66: Don't use 'Function' as a type.
Prefer explicitly define the function shape. This type accepts any function-like value, which can be a common source of bugs.
(lint/complexity/noBannedTypes)
#[wasm_bindgen(js_name=createPurchaseStateTransition)] | ||
pub fn create_update_purchase_transition(&mut self, buyer: IdentifierWrapper, amount: u32, identity_contract_nonce: IdentityNonce) -> DocumentsBatchTransitionWasm { | ||
let mut cloned_document = self.0.document().clone(); | ||
|
||
cloned_document.set_revision(Some(cloned_document.revision().unwrap() + 1)); | ||
|
||
let purchase_transition = DocumentPurchaseTransition::from_document( | ||
cloned_document, | ||
self.0.document_type().unwrap(), | ||
amount as u64, | ||
identity_contract_nonce, | ||
PlatformVersion::latest(), | ||
None, | ||
None, | ||
).unwrap(); | ||
|
||
let documents_batch_transition: DocumentsBatchTransition = DocumentsBatchTransitionV0 { | ||
owner_id: buyer.into(), | ||
transitions: vec![purchase_transition.into()], | ||
user_fee_increase: Default::default(), | ||
signature_public_key_id: Default::default(), | ||
signature: Default::default(), | ||
}.into(); | ||
|
||
documents_batch_transition.into() | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Inconsistent method naming pattern.
The method name create_update_purchase_transition
doesn't follow the pattern of other methods. It should be create_purchase_state_transition
for consistency.
- pub fn create_update_purchase_transition(
+ pub fn create_purchase_state_transition(
📝 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.
#[wasm_bindgen(js_name=createPurchaseStateTransition)] | |
pub fn create_update_purchase_transition(&mut self, buyer: IdentifierWrapper, amount: u32, identity_contract_nonce: IdentityNonce) -> DocumentsBatchTransitionWasm { | |
let mut cloned_document = self.0.document().clone(); | |
cloned_document.set_revision(Some(cloned_document.revision().unwrap() + 1)); | |
let purchase_transition = DocumentPurchaseTransition::from_document( | |
cloned_document, | |
self.0.document_type().unwrap(), | |
amount as u64, | |
identity_contract_nonce, | |
PlatformVersion::latest(), | |
None, | |
None, | |
).unwrap(); | |
let documents_batch_transition: DocumentsBatchTransition = DocumentsBatchTransitionV0 { | |
owner_id: buyer.into(), | |
transitions: vec![purchase_transition.into()], | |
user_fee_increase: Default::default(), | |
signature_public_key_id: Default::default(), | |
signature: Default::default(), | |
}.into(); | |
documents_batch_transition.into() | |
} | |
#[wasm_bindgen(js_name=createPurchaseStateTransition)] | |
pub fn create_purchase_state_transition(&mut self, buyer: IdentifierWrapper, amount: u32, identity_contract_nonce: IdentityNonce) -> DocumentsBatchTransitionWasm { | |
let mut cloned_document = self.0.document().clone(); | |
cloned_document.set_revision(Some(cloned_document.revision().unwrap() + 1)); | |
let purchase_transition = DocumentPurchaseTransition::from_document( | |
cloned_document, | |
self.0.document_type().unwrap(), | |
amount as u64, | |
identity_contract_nonce, | |
PlatformVersion::latest(), | |
None, | |
None, | |
).unwrap(); | |
let documents_batch_transition: DocumentsBatchTransition = DocumentsBatchTransitionV0 { | |
owner_id: buyer.into(), | |
transitions: vec![purchase_transition.into()], | |
user_fee_increase: Default::default(), | |
signature_public_key_id: Default::default(), | |
signature: Default::default(), | |
}.into(); | |
documents_batch_transition.into() | |
} |
#[wasm_bindgen(js_name=createUpdatePriceStateTransition)] | ||
pub fn create_update_price_state_transition(&mut self, amount: u32, identity_contract_nonce: IdentityNonce) -> DocumentsBatchTransitionWasm { | ||
let mut cloned_document = self.0.document().clone(); | ||
|
||
cloned_document.set_revision(Some(cloned_document.revision().unwrap() + 1)); | ||
|
||
let update_price_transition = DocumentUpdatePriceTransition::from_document( | ||
cloned_document, | ||
self.0.document_type().unwrap(), | ||
amount as u64, | ||
identity_contract_nonce, | ||
PlatformVersion::latest(), | ||
None, | ||
None, | ||
).unwrap(); | ||
|
||
let documents_batch_transition: DocumentsBatchTransition = DocumentsBatchTransitionV0 { | ||
owner_id: self.0.owner_id(), | ||
transitions: vec![update_price_transition.into()], | ||
user_fee_increase: Default::default(), | ||
signature_public_key_id: Default::default(), | ||
signature: Default::default(), | ||
}.into(); | ||
|
||
documents_batch_transition.into() | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Handle potential overflow in price amount conversion.
The method performs an unchecked conversion from u32 to u64 for the amount parameter. Consider validating the conversion.
- amount as u64,
+ u64::from(amount),
📝 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.
#[wasm_bindgen(js_name=createUpdatePriceStateTransition)] | |
pub fn create_update_price_state_transition(&mut self, amount: u32, identity_contract_nonce: IdentityNonce) -> DocumentsBatchTransitionWasm { | |
let mut cloned_document = self.0.document().clone(); | |
cloned_document.set_revision(Some(cloned_document.revision().unwrap() + 1)); | |
let update_price_transition = DocumentUpdatePriceTransition::from_document( | |
cloned_document, | |
self.0.document_type().unwrap(), | |
amount as u64, | |
identity_contract_nonce, | |
PlatformVersion::latest(), | |
None, | |
None, | |
).unwrap(); | |
let documents_batch_transition: DocumentsBatchTransition = DocumentsBatchTransitionV0 { | |
owner_id: self.0.owner_id(), | |
transitions: vec![update_price_transition.into()], | |
user_fee_increase: Default::default(), | |
signature_public_key_id: Default::default(), | |
signature: Default::default(), | |
}.into(); | |
documents_batch_transition.into() | |
} | |
#[wasm_bindgen(js_name=createUpdatePriceStateTransition)] | |
pub fn create_update_price_state_transition(&mut self, amount: u32, identity_contract_nonce: IdentityNonce) -> DocumentsBatchTransitionWasm { | |
let mut cloned_document = self.0.document().clone(); | |
cloned_document.set_revision(Some(cloned_document.revision().unwrap() + 1)); | |
let update_price_transition = DocumentUpdatePriceTransition::from_document( | |
cloned_document, | |
self.0.document_type().unwrap(), | |
u64::from(amount), | |
identity_contract_nonce, | |
PlatformVersion::latest(), | |
None, | |
None, | |
).unwrap(); | |
let documents_batch_transition: DocumentsBatchTransition = DocumentsBatchTransitionV0 { | |
owner_id: self.0.owner_id(), | |
transitions: vec![update_price_transition.into()], | |
user_fee_increase: Default::default(), | |
signature_public_key_id: Default::default(), | |
signature: Default::default(), | |
}.into(); | |
documents_batch_transition.into() | |
} |
#[wasm_bindgen(js_name=createTransferStateTransition)] | ||
pub fn create_transfer_state_transition(&mut self, recipient: IdentifierWrapper, identity_contract_nonce: IdentityNonce) -> DocumentsBatchTransitionWasm { | ||
let mut cloned_document = self.0.document().clone(); | ||
|
||
cloned_document.set_revision(Some(cloned_document.revision().unwrap() + 1)); | ||
|
||
let transfer_transition = DocumentTransferTransition::from_document( | ||
cloned_document, | ||
self.0.document_type().unwrap(), | ||
identity_contract_nonce, | ||
recipient.into(), | ||
PlatformVersion::latest(), | ||
None, | ||
None, | ||
).unwrap(); | ||
|
||
let documents_batch_transition: DocumentsBatchTransition = DocumentsBatchTransitionV0 { | ||
owner_id: self.0.owner_id(), | ||
transitions: vec![transfer_transition.into()], | ||
user_fee_increase: Default::default(), | ||
signature_public_key_id: Default::default(), | ||
signature: Default::default(), | ||
}.into(); | ||
|
||
documents_batch_transition.into() | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Handle potential panics in transfer state transition.
The method uses unwrap()
which could panic if the document revision is None. Consider adding proper error handling.
- cloned_document.set_revision(Some(cloned_document.revision().unwrap() + 1));
+ let current_revision = cloned_document.revision().ok_or_else(|| {
+ ProtocolError::ValueError("Document revision is required".into())
+ })?;
+ cloned_document.set_revision(Some(current_revision + 1));
📝 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.
#[wasm_bindgen(js_name=createTransferStateTransition)] | |
pub fn create_transfer_state_transition(&mut self, recipient: IdentifierWrapper, identity_contract_nonce: IdentityNonce) -> DocumentsBatchTransitionWasm { | |
let mut cloned_document = self.0.document().clone(); | |
cloned_document.set_revision(Some(cloned_document.revision().unwrap() + 1)); | |
let transfer_transition = DocumentTransferTransition::from_document( | |
cloned_document, | |
self.0.document_type().unwrap(), | |
identity_contract_nonce, | |
recipient.into(), | |
PlatformVersion::latest(), | |
None, | |
None, | |
).unwrap(); | |
let documents_batch_transition: DocumentsBatchTransition = DocumentsBatchTransitionV0 { | |
owner_id: self.0.owner_id(), | |
transitions: vec![transfer_transition.into()], | |
user_fee_increase: Default::default(), | |
signature_public_key_id: Default::default(), | |
signature: Default::default(), | |
}.into(); | |
documents_batch_transition.into() | |
} | |
#[wasm_bindgen(js_name=createTransferStateTransition)] | |
pub fn create_transfer_state_transition(&mut self, recipient: IdentifierWrapper, identity_contract_nonce: IdentityNonce) -> DocumentsBatchTransitionWasm { | |
let mut cloned_document = self.0.document().clone(); | |
let current_revision = cloned_document.revision().ok_or_else(|| { | |
ProtocolError::ValueError("Document revision is required".into()) | |
})?; | |
cloned_document.set_revision(Some(current_revision + 1)); | |
let transfer_transition = DocumentTransferTransition::from_document( | |
cloned_document, | |
self.0.document_type().unwrap(), | |
identity_contract_nonce, | |
recipient.into(), | |
PlatformVersion::latest(), | |
None, | |
None, | |
).unwrap(); | |
let documents_batch_transition: DocumentsBatchTransition = DocumentsBatchTransitionV0 { | |
owner_id: self.0.owner_id(), | |
transitions: vec![transfer_transition.into()], | |
user_fee_increase: Default::default(), | |
signature_public_key_id: Default::default(), | |
signature: Default::default(), | |
}.into(); | |
documents_batch_transition.into() | |
} |
#[wasm_bindgen(js_name=createTransferStateTransition)] | ||
pub fn create_transfer_state_transition(&mut self, recipient: IdentifierWrapper, identity_contract_nonce: IdentityNonce) -> DocumentsBatchTransitionWasm { | ||
let mut cloned_document = self.0.document().clone(); | ||
|
||
cloned_document.set_revision(Some(cloned_document.revision().unwrap() + 1)); | ||
|
||
let transfer_transition = DocumentTransferTransition::from_document( | ||
cloned_document, | ||
self.0.document_type().unwrap(), | ||
identity_contract_nonce, | ||
recipient.into(), | ||
PlatformVersion::latest(), | ||
None, | ||
None, | ||
).unwrap(); | ||
|
||
let documents_batch_transition: DocumentsBatchTransition = DocumentsBatchTransitionV0 { | ||
owner_id: self.0.owner_id(), | ||
transitions: vec![transfer_transition.into()], | ||
user_fee_increase: Default::default(), | ||
signature_public_key_id: Default::default(), | ||
signature: Default::default(), | ||
}.into(); | ||
|
||
documents_batch_transition.into() | ||
} | ||
|
||
#[wasm_bindgen(js_name=createUpdatePriceStateTransition)] | ||
pub fn create_update_price_state_transition(&mut self, amount: u32, identity_contract_nonce: IdentityNonce) -> DocumentsBatchTransitionWasm { | ||
let mut cloned_document = self.0.document().clone(); | ||
|
||
cloned_document.set_revision(Some(cloned_document.revision().unwrap() + 1)); | ||
|
||
let update_price_transition = DocumentUpdatePriceTransition::from_document( | ||
cloned_document, | ||
self.0.document_type().unwrap(), | ||
amount as u64, | ||
identity_contract_nonce, | ||
PlatformVersion::latest(), | ||
None, | ||
None, | ||
).unwrap(); | ||
|
||
let documents_batch_transition: DocumentsBatchTransition = DocumentsBatchTransitionV0 { | ||
owner_id: self.0.owner_id(), | ||
transitions: vec![update_price_transition.into()], | ||
user_fee_increase: Default::default(), | ||
signature_public_key_id: Default::default(), | ||
signature: Default::default(), | ||
}.into(); | ||
|
||
documents_batch_transition.into() | ||
} | ||
|
||
#[wasm_bindgen(js_name=createPurchaseStateTransition)] | ||
pub fn create_update_purchase_transition(&mut self, buyer: IdentifierWrapper, amount: u32, identity_contract_nonce: IdentityNonce) -> DocumentsBatchTransitionWasm { | ||
let mut cloned_document = self.0.document().clone(); | ||
|
||
cloned_document.set_revision(Some(cloned_document.revision().unwrap() + 1)); | ||
|
||
let purchase_transition = DocumentPurchaseTransition::from_document( | ||
cloned_document, | ||
self.0.document_type().unwrap(), | ||
amount as u64, | ||
identity_contract_nonce, | ||
PlatformVersion::latest(), | ||
None, | ||
None, | ||
).unwrap(); | ||
|
||
let documents_batch_transition: DocumentsBatchTransition = DocumentsBatchTransitionV0 { | ||
owner_id: buyer.into(), | ||
transitions: vec![purchase_transition.into()], | ||
user_fee_increase: Default::default(), | ||
signature_public_key_id: Default::default(), | ||
signature: Default::default(), | ||
}.into(); | ||
|
||
documents_batch_transition.into() | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codebase verification
Unit tests needed for NFT state transition operations
These critical NFT operations require comprehensive test coverage to ensure reliability:
create_transfer_state_transition
: Test ownership transfer, revision increments, and transition object creationcreate_update_price_state_transition
: Verify price updates, revision handling, and transition formattingcreate_update_purchase_transition
: Test buyer assignment, amount validation, and transition object structure
🔗 Analysis chain
Add unit tests for new NFT operations.
The new NFT-related state transition methods require comprehensive test coverage to ensure correct behavior, especially around error handling and edge cases.
Would you like me to help generate comprehensive unit tests for these new methods?
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check for existing tests of the new NFT methods
rg -l "test.*(?:transfer|update_price|purchase).*transition" --type rust
Length of output: 240
Script:
#!/bin/bash
# Check for test modules in the extended_document.rs file
echo "=== Checking for test modules in extended_document.rs ==="
rg "#\[cfg\(test\)\]" packages/wasm-dpp/src/document/extended_document.rs
echo -e "\n=== Checking for NFT-related test files in wasm-dpp ==="
fd -t f ".*test.*" packages/wasm-dpp/src
echo -e "\n=== Checking for NFT-related tests with different patterns ==="
rg -l "test.*(?:nft|document.*transition)" packages/wasm-dpp/
Length of output: 644
Issue being fixed or feature implemented
WASM DPP and JS Dash SDK is missing functions for creating NFT document transactions, there are 3 of them:
This PR implements all three missing functions making it able to perform such operations from the browsers (Web).
What was done?
tbd.
How Has This Been Tested?
In the testnet, with JS Dash SDK
https://testnet.platform-explorer.com/transaction/42175A63E25A316B5E0666317A3FF36A407EDDBA01D844982F68A6D10CBBFAF7
https://testnet.platform-explorer.com/transaction/36F3002686CA5ED23ED1FEFAD58803493055EFE55FC07517779AB267C8151747
https://testnet.platform-explorer.com/transaction/5CA156E676FA503CA4A520831484BE73B16EBE15599BB307605DE520B623AC1A
Breaking Changes
No
Checklist:
For repository code-owners and collaborators only
Summary by CodeRabbit