Tokenization Precompile

Address: 0x0000000000000000000000000000000000001001

The Tokenization Precompile provides full access to the BitBadges tokenization module from Solidity contracts. All methods use a JSON-based interface for maximum flexibility and compatibility with the underlying Cosmos SDK protobuf messages.

Quick Start

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./interfaces/ITokenizationPrecompile.sol";
import "./libraries/TokenizationJSONHelpers.sol";

contract MyTokenContract {
    ITokenizationPrecompile constant TOKENIZATION = 
        ITokenizationPrecompile(0x0000000000000000000000000000000000001001);
    
    // Transfer tokens using JSON helper
    function transfer(
        uint256 collectionId,
        address to,
        uint256 amount,
        uint256 tokenId
    ) external returns (bool) {
        address[] memory recipients = new address[](1);
        recipients[0] = to;
        
        // Build JSON using helpers
        string memory tokenIdsJson = TokenizationJSONHelpers.uintRangeToJson(tokenId, tokenId);
        string memory ownershipTimesJson = TokenizationJSONHelpers.uintRangeToJson(1, TokenizationJSONHelpers.FOREVER);
        
        string memory transferJson = TokenizationJSONHelpers.transferTokensJSON(
            collectionId,
            recipients,
            amount,
            tokenIdsJson,
            ownershipTimesJson
        );
        
        return TOKENIZATION.transferTokens(transferJson);
    }
    
    // Query balance using JSON helper
    function balanceOf(
        uint256 collectionId,
        address user
    ) external view returns (uint256) {
        string memory tokenIdsJson = TokenizationJSONHelpers.uintRangeToJson(1, TokenizationJSONHelpers.FOREVER);
        string memory ownershipTimesJson = TokenizationJSONHelpers.uintRangeToJson(1, TokenizationJSONHelpers.FOREVER);
        
        string memory balanceJson = TokenizationJSONHelpers.getBalanceAmountJSON(
            collectionId,
            user,
            tokenIdsJson,
            ownershipTimesJson
        );
        
        return TOKENIZATION.getBalanceAmount(balanceJson);
    }
}

Why JSON?

The precompile uses JSON strings instead of Solidity structs because:

  1. Protobuf Compatibility: Direct mapping to Cosmos SDK protobuf messages

  2. Flexibility: Easy to extend without breaking changes

  3. Type Safety: JSON helpers provide compile-time safety

  4. Simplicity: Single parameter per method, easy to understand

Core Concepts

1. All Methods Accept JSON Strings

Every precompile method accepts a single string calldata msgJson parameter that matches the protobuf JSON format:

2. Use Helper Libraries

The TokenizationJSONHelpers library provides type-safe functions to construct JSON strings:

3. UintRange Arrays

Token IDs and ownership times use UintRange arrays. Convert them to JSON using helpers:

Common Patterns

Pattern 1: Simple Token Transfer

Pattern 2: Time-Bound Transfer

Pattern 3: Create Dynamic Store (KYC Registry)

Pattern 4: Create Collection

Pattern 5: Multi-Message Execution (Create Collection + Transfer Tokens)

Execute multiple operations atomically in a single transaction:

Available Methods

Transaction Methods

All transaction methods return bool (success) or uint256 (for creation methods):

  • transferTokens(string calldata msgJson) β†’ bool

  • createCollection(string calldata msgJson) β†’ uint256

  • updateCollection(string calldata msgJson) β†’ uint256

  • deleteCollection(string calldata msgJson) β†’ bool

  • createDynamicStore(string calldata msgJson) β†’ uint256

  • setDynamicStoreValue(string calldata msgJson) β†’ bool

  • setIncomingApproval(string calldata msgJson) β†’ bool

  • setOutgoingApproval(string calldata msgJson) β†’ bool

  • deleteIncomingApproval(string calldata msgJson) β†’ bool

  • deleteOutgoingApproval(string calldata msgJson) β†’ bool

  • createAddressLists(string calldata msgJson) β†’ bool

  • castVote(string calldata msgJson) β†’ bool

  • executeMultiple(MessageInput[] calldata messages) β†’ (bool success, bytes[] memory results) - Execute multiple messages atomically

Multi-Message Execution

The executeMultiple method allows executing multiple tokenization messages in a single atomic transaction. This is particularly useful for workflows like "Create Collection + Transfer Tokens":

Key Features:

  • Atomic Execution: All messages succeed or all fail (no partial execution)

  • Sequential Order: Messages execute in the order provided

  • Dynamic Routing: Message type string determines which handler to use

  • Result Decoding: Results are returned as bytes[] - decode based on message type

See API Reference for complete executeMultiple documentation.

Query Methods

Query methods return structs (ABI-encoded; define matching struct types in your contract) or uint256 for amount/supply queries:

  • getCollection(string calldata msgJson) β†’ TokenCollection

  • getBalance(string calldata msgJson) β†’ UserBalanceStore

  • getBalanceAmount(string calldata msgJson) β†’ uint256

  • getTotalSupply(string calldata msgJson) β†’ uint256

  • getCollectionStats(string calldata msgJson) β†’ CollectionStats - Get holder count and circulating supply

  • getDynamicStore(string calldata msgJson) β†’ DynamicStore

  • getDynamicStoreValue(string calldata msgJson) β†’ DynamicStoreValueResult

  • getAddressList(string calldata msgJson) β†’ AddressList

See API Reference for complete method documentation.

Struct Return Types

Query methods (except getBalanceAmount and getTotalSupply) return ABI-encoded structs. Define struct types in your contract that match the precompile’s response layout:

See API Reference - Struct Return Types for supported struct types and layout.

Helper Library Functions

The TokenizationJSONHelpers library provides functions for all common operations:

Transfer Helpers

  • transferTokensJSON(...) - Build transfer JSON

  • uintRangeToJson(start, end) - Single range

  • uintRangeArrayToJson(starts[], ends[]) - Multiple ranges

Collection Helpers

  • createCollectionJSON(...) - Build collection creation JSON

  • collectionMetadataToJson(uri, customData) - Build metadata JSON

  • simpleUserBalanceStoreToJson(...) - Build default balances JSON

  • stringArrayToJson(strings[]) - Convert string array to JSON

Dynamic Store Helpers

  • createDynamicStoreJSON(defaultValue, uri, customData) - Build store creation JSON

  • setDynamicStoreValueJSON(storeId, address, value) - Build set value JSON

  • getDynamicStoreValueJSON(storeId, address) - Build get value JSON

Query Helpers

  • getCollectionJSON(collectionId) - Build collection query JSON

  • getBalanceJSON(collectionId, userAddress) - Build balance query JSON

  • getBalanceAmountJSON(...) - Build balance amount query JSON

  • getTotalSupplyJSON(...) - Build supply query JSON

Utility Helpers

  • uintToString(value) - Convert uint256 to string

  • deleteCollectionJSON(collectionId) - Build delete JSON

  • deleteIncomingApprovalJSON(collectionId, approvalId) - Build delete approval JSON

  • deleteOutgoingApprovalJSON(collectionId, approvalId) - Build delete approval JSON

Precompile Utility Methods

The precompile also provides pure utility methods for common operations:

See API Reference - Utility Helper Methods for complete documentation.

Multi-Message Helpers

When using executeMultiple, build individual message JSONs using the helpers above, then construct the MessageInput array in Solidity.

Return Value Handling

Direct Returns (uint256)

Some methods return uint256 directly:

Struct Returns (Query Methods)

Query methods (e.g. getCollection, getBalance, getCollectionStats, getDynamicStore, getDynamicStoreValue, getAddressList) return ABI-encoded structs. Define matching struct types in your contract and use an interface that declares those return types; then use the returned struct fields directly in your logic. See Struct Return Types for supported types and examples.

Security Considerations

  1. Automatic Creator Field: The creator field is automatically set from msg.sender and cannot be spoofed

  2. JSON Validation: Invalid JSON will revert with clear error messages

  3. Type Safety: Use helper functions to ensure correct JSON structure

  4. Gas Optimization: JSON construction is efficient, but cache complex JSON strings when possible

Best Practices

1. Always Use Helper Functions

2. Cache Complex JSON

3. Validate Inputs Before Building JSON

4. Handle Errors Gracefully

5. Multi-Message Execution Best Practices

When using executeMultiple, follow these guidelines:

Key Points:

  • Validate all inputs before building messages

  • Use auto-prev (collectionId: "0") to reference previous message results

  • Always check result count matches message count

  • Decode and validate each result

  • Handle errors with clear messages

Examples

See the example contracts for complete implementations:

Next Steps

Resources

Last updated