Documentation Index
Fetch the complete documentation index at: https://docs.cultura.xyz/llms.txt
Use this file to discover all available pages before exploring further.
Product Update - Cultura SDK v0.2.0 Released
This release implements a new streamlined royalty claiming process for off-chain payments and UX improvements to make implementation and sponsorship easier. The parent asset structure has been refactored to use Rights Bound Account addresses, simplifying derivative asset creation. Enhanced query capabilities provide richer data, and new utility functions improve developer experience.
This release represents a major update to the Cultura SDK with significant architectural improvements, new features, and some breaking changes. This guide will help you migrate from v0.1.10 to v0.2.0.
Major Changes & New Features
1. BREAKING CHANGE: Parent Asset Structure Refactor
The most significant change in v0.2.0 is the restructuring of parent asset handling for derivative works.
What Changed
- v0.1.10: Used
ParentDigitalAsset type with parentCollection, parentDigitalAssetId, owner, royaltySplit
- v0.2.0: Uses
ParentInfo type with rightsBoundAccount, royaltySplit
Migration Required
Old v0.1.10 Structure:
// v0.1.10 - Parent asset info included collection, tokenId, and owner
const parentAssets: ParentDigitalAsset[] = [
{
parentCollection: "0x123...",
parentDigitalAssetId: 42n,
owner: "0xabc...",
royaltySplit: 75n,
},
];
await sdk.culturaDigitalAsset.mintDigitalAsset(
to,
name,
description,
parentAssets, // Old structure
termsData,
tokenURI
);
New v0.2.0 Structure:
// v0.2.0 - Parent asset info uses Rights Bound Account address
const parentInfo: ParentInfo[] = [
{
rightsBoundAccount: "0xdef...", // RBA address of parent asset
royaltySplit: 75n,
},
];
await sdk.culturaDigitalAsset.mintDigitalAsset(
to,
name,
description,
parentInfo, // New structure
termsData,
tokenURI
);
How to Get Rights Bound Account Address
You can obtain the Rights Bound Account address for a parent asset in several ways:
// Method 1: Query from subgraph data
const parentAsset = await sdk.query.digitalAsset.getByContractAndTokenId(
parentContractAddress,
parentTokenId
);
const rightsBoundAccount = parentAsset?.rightsBoundAccount;
// Method 2: Query from verified rights data
const verifiedRights = await sdk.query.verifiedRights.getByDigitalAsset(
parentContractAddress,
parentTokenId.toString()
);
const rightsBoundAccount = verifiedRights?.rightsBoundAccount;
// Method 3: If you have attestation receipt from parent creation
const rightsBoundAccount =
sdk.attestationService.getRightsBoundAccountFromReceipt(receipt);
2. Enhanced Query System with Richer Data
New Query Features
- Enhanced Verification Data:
verifiedRights queries now include detailed verifications array with individual verifier information
- Owner Token Counts:
digitalAsset.owner now includes tokenCount field
- Nested Asset Information: Better cross-referencing between digital assets and verified rights
Example of Enhanced Data Usage
// v0.2.0 - Access richer verification data
const verifiedRights = await sdk.query.verifiedRights.getAll(10, 0);
verifiedRights.forEach((right) => {
console.log(`Asset: ${right.digitalAsset?.assetName}`);
console.log(`Owner Token Count: ${right.digitalAsset?.owner.tokenCount}`);
// New: Detailed verification information
right.verifications.forEach((verification) => {
console.log(`Verifier: ${verification.verifier.address}`);
console.log(`Bond Amount: ${verification.bondAmount}`);
console.log(`Timestamp: ${verification.timestamp}`);
console.log(`Is Whitelisted: ${verification.verifier.isWhitelisted}`);
});
});
3. New Utility Functions
Digital Asset and Verified Rights ID Generation
import { getDigitalAssetUID, getVerifiedRightsId } from "@cultura/sdk/utils";
// Generate unique identifiers for assets and rights
const digitalAssetUID = getDigitalAssetUID(contractAddress, tokenId);
const verifiedRightsId = getVerifiedRightsId(contractAddress, tokenId);
// Use these IDs for queries
const asset = await sdk.query.digitalAsset.getByUID(digitalAssetUID);
const rights = await sdk.query.verifiedRights.getById(verifiedRightsId);
4. Royalty System UX Improvements
New Off-Chain Payment Methods (Continued from v0.1.10)
The off-chain payment workflow introduced in v0.1.10 has been refined with improved UX:
// Report off-chain payment
await sdk.royalty.reportOffChainPayment(tokenId, periodIndex, amount, metadata);
// Accept off-chain payment by parent
await sdk.royalty.acceptOffChainPaymentByParent(
tokenId,
periodIndex,
parentBoundAccount,
signature,
signerAddress,
sponsorAddress
);
// Deny off-chain payment by parent
await sdk.royalty.denyOffChainPaymentByParent(
tokenId,
periodIndex,
parentBoundAccount,
signature,
signerAddress
);
New Signature Helper Methods
// Generate signatures for off-chain payment acceptance
const acceptanceSignature =
await sdk.royalty.signForAcceptOffChainPaymentByParent(
rightsBoundAccount,
totalAmount,
period,
sponsor
);
// Generate signatures for off-chain payment denial
const denialSignature = await sdk.royalty.signForDenyOffChainPaymentByParent(
tokenId,
periodIndex,
parentBoundAccount
);
v0.2.0 introduces extensive sponsorship capabilities across the entire royalty and attestation system, enabling third parties to cover transaction costs and execute operations on behalf of others.
Delegated Royalty Operations
// Delegated royalty registration - sponsor registers royalty on behalf of asset owner
const registrationSignature =
await sdk.royalty.signForDelegatedRegisterRoyaltyDue(
tokenId,
amountDue,
startDate,
endDate,
royaltyInfoIndex
);
await sponsorSDK.royalty.delegatedRegisterRoyaltyDue(
tokenId,
amountDue,
startDate,
endDate,
royaltyInfoIndex,
registrationSignature
);
// Delegated royalty payment - sponsor pays royalty on behalf of licensee
const paymentSignature = await sdk.royalty.signForDelegatedPayRoyalty(
tokenId,
amountDue,
royaltyInfoIndex
);
await sponsorSDK.royalty.delegatedPayRoyalty(
tokenId,
amountPaid,
periodIndex,
culturaBoundAccount,
signature,
paymentSignature
);
Delegated Off-Chain Payment Flow
// Sponsor reports off-chain payment on behalf of licensee
const reportSignature = await sdk.royalty.signForDelegatedOffchainReportRoyalty(
tokenId,
royaltyInfoIndex,
amount
);
await sponsorSDK.royalty.delegatedReportOffChainPayment(
tokenId,
periodIndex,
amount,
metadata,
reportSignature
);
// Example from licensing flow - sponsor handles all off-chain payment operations
const offchainSignature =
await licenseeSDK.royalty.signForDelegatedRegisterRoyaltyDue(
licensedAssetId,
offchainRoyaltyDue,
offchainPeriodStartDate,
offchainPeriodEndDate,
offchainPeriodIndex
);
await sponsorSDK.royalty.delegatedRegisterRoyaltyDue(
licensedAssetId,
offchainRoyaltyDue,
offchainPeriodStartDate,
offchainPeriodEndDate,
offchainPeriodIndex,
offchainSignature
);
// Sponsor sets payment info on behalf of asset owner
const paymentSignature = await sdk.rightsBoundAccount.signForSetPaymentInfo(
period,
totalAmount,
sponsorAddress
);
// Sponsor SDK executes the transaction
sponsorSDK.setRightsBoundAccount(rightsBoundAccountAddress);
await sponsorSDK.rightsBoundAccount.setPaymentInfo({
totalAmount,
sponsor: sponsorAddress,
signature: paymentSignature,
signer: assetOwnerAddress, // Original signer but sponsor executes
});
// Sponsored attestation creation
const { attestationUid, rightsBoundAccount } =
await sdk.attestationService.sponsoredAttest(
attestationRequest,
digitalAssetAddress,
digitalAssetId,
classId,
bondAmount,
sponsorAddress
);
// Delegated attestation with sponsor
const delegatedSignature =
await sdk.attestationService.signForDelegatedAttestation(recipientAddress);
const { attestationUid, rightsBoundAccount } =
await sponsorSDK.attestationService.sponsoredDelegatedAttest(
attestationRequest,
digitalAssetAddress,
digitalAssetId,
classId,
bondAmount,
delegatedSignature,
recipientAddress,
sponsorAddress
);
- Gas-Free User Experience: Users can interact without owning native tokens
- Platform Integration: Marketplaces can sponsor user interactions seamlessly
- Enterprise Workflows: Complex multi-party operations with clear cost attribution
- Accessibility: Removes technical barriers for non-crypto native users
- Flexible Business Models: Enables subscription, freemium, and sponsored content models
- Scalable Operations: Third parties can batch and optimize transaction execution
6. Enhanced Rights Bound Account Management
New Methods
// Get asset information associated with a Rights Bound Account
const assetInfo = await sdk.rightsBoundAccount.getRightsBoundAccountAsset();
console.log(`Asset Address: ${assetInfo.assetAddress}`);
console.log(`Token ID: ${assetInfo.tokenId}`);
// Improved payment info signing with sponsor support
const signature = await sdk.rightsBoundAccount.signForSetPaymentInfo(
period,
totalAmount,
sponsor
);
7. Improved UX with Attestation
Better Developer Experience for Attestation Functions
v0.2.0 improves the developer experience by having attestation functions return the attestationUid and rightsBoundAccount directly instead of just transaction hashes. This eliminates the need for developers to manually wait for transactions and parse receipts.
// v0.2.0 - Direct returns for better UX
const { attestationUid, rightsBoundAccount } =
await sdk.attestationService.attest(
attestationRequest,
digitalAssetAddress,
digitalAssetId,
assetClass,
bondAmount
);
// No need to wait for transaction or parse receipts manually
console.log(`Attestation UID: ${attestationUid}`);
console.log(`Rights Bound Account: ${rightsBoundAccount}`);
// Same improvement applies to other attestation methods:
// - sponsoredAttest()
// - delegatedAttest()
// - sponsoredDelegatedAttest()
Migration Checklist
Critical - Required Changes
1. Update Parent Asset Structure
2. Update Import Statements
// Add new utility imports if needed
import { getDigitalAssetUID, getVerifiedRightsId } from "@cultura/sdk/utils";
Recommended - Optional Enhancements
3. Leverage Enhanced Query Data
4. Implement New Utility Functions
5. Enhanced Error Handling
Example Migration
Before (v0.1.10)
// v0.1.10 minting with parent assets
const parentAssets: ParentDigitalAsset[] = [
{
parentCollection: "0x123...",
parentDigitalAssetId: 42n,
owner: "0xabc...",
royaltySplit: 75n,
},
];
const tokenId = await sdk.culturaDigitalAsset.mintDigitalAsset(
recipientAddress,
"Derivative Work",
"Based on parent asset",
parentAssets,
termsData,
tokenURI
);
After (v0.2.0)
// v0.2.0 minting with parent info
// First, get the Rights Bound Account address for the parent
const parentAsset = await sdk.query.digitalAsset.getByContractAndTokenId(
"0x123...", // parent collection
42n // parent token ID
);
if (!parentAsset?.rightsBoundAccount) {
throw new Error("Parent asset Rights Bound Account not found");
}
const parentInfo: ParentInfo[] = [
{
rightsBoundAccount: parentAsset.rightsBoundAccount,
royaltySplit: 75n,
},
];
const tokenId = await sdk.culturaDigitalAsset.mintDigitalAsset(
recipientAddress,
"Derivative Work",
"Based on parent asset",
parentInfo, // Updated structure
termsData,
tokenURI
);
Common Migration Issues
Issue 1: Rights Bound Account Not Found
Problem: Parent asset doesn’t have a Rights Bound Account address
Solution: Ensure the parent asset has been properly attested and verified
// Check if parent asset has been attested
const verifiedRights = await sdk.query.verifiedRights.getByDigitalAsset(
parentCollection,
parentTokenId.toString()
);
if (!verifiedRights) {
throw new Error("Parent asset must be attested before use in derivatives");
}
Issue 2: Type Errors with Parent Info
Problem: TypeScript errors when switching from ParentDigitalAsset to ParentInfo
Solution: Update type imports and structure
// Update imports
import type { ParentInfo } from "@cultura/sdk";
// Use correct type
const parentInfo: ParentInfo[] = [
/* ... */
];
Testing Your Migration
- Test Parent Asset Queries: Ensure you can successfully retrieve Rights Bound Account addresses
- Test Minting: Verify derivative asset minting works with new parent info structure
- Test Enhanced Queries: Confirm enhanced query data is accessible
- Test Royalty Flows: Verify royalty distribution still works correctly
Getting Help
If you encounter issues during migration:
The v0.2.0 update provides a more robust and feature-rich SDK while maintaining backward compatibility where possible. The main breaking change around parent asset structure enables better royalty distribution and cleaner architecture going forward.