# Solidity Quickstart

This page gets a Solidity developer to a working contract on the tokenization precompile in a few minutes. Read it before the full [API reference](https://docs.bitbadges.io/chain/evm/tokenization-precompile/api).

## The Essentials

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

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

contract MyToken {
    // Precompile address (same on all BitBadges networks)
    ITokenizationPrecompile constant PRECOMPILE =
        ITokenizationPrecompile(0x0000000000000000000000000000000000001001);

    function transfer(uint256 collectionId, address to, uint256 amount) external {
        address[] memory recipients = new address[](1);
        recipients[0] = to;

        // Use FOREVER, not type(uint256).max
        string memory tokenIds = TokenizationJSONHelpers.uintRangeToJson(1, 1);
        string memory times = TokenizationJSONHelpers.uintRangeToJson(
            1,
            TokenizationJSONHelpers.FOREVER
        );

        string memory json = TokenizationJSONHelpers.transferTokensJSON(
            collectionId, recipients, amount, tokenIds, times
        );

        require(PRECOMPILE.transferTokens(json), "Transfer failed");
    }
}
```

## Constants

BitBadges stores IDs and timestamps as `uint64`. `type(uint256).max` fails with a range overflow error.

```solidity
// Wrong: fails with "range overflow"
TokenizationJSONHelpers.uintRangeToJson(1, type(uint256).max);

// Correct: use the FOREVER constant
TokenizationJSONHelpers.uintRangeToJson(1, TokenizationJSONHelpers.FOREVER);
```

| Constant | Value | Use |
| --- | --- | --- |
| `FOREVER` | `18446744073709551615` | Ownership that never expires |
| `MAX_TIME` | `18446744073709551615` | Maximum timestamp |
| `MAX_ID` | `18446744073709551615` | Maximum token ID |
| `MIN_ID` | `1` | Minimum ID (ranges start at 1, not 0) |
| `FOREVER_STR` | `"18446744073709551615"` | The same value as a string, for hand-built JSON |

All four numeric constants equal `type(uint64).max` except `MIN_ID`. They are defined in both `TokenizationJSONHelpers` and `TokenizationHelpers`.

## Precompile Addresses

| Precompile | Address | Purpose |
| --- | --- | --- |
| Tokenization | `0x0000000000000000000000000000000000001001` | Collections, transfers, balances |
| GAMM | `0x0000000000000000000000000000000000001002` | Liquidity pools, swaps |
| Send manager | `0x0000000000000000000000000000000000001003` | Native coin sends, alias denoms |

## Why JSON

BitBadges precompiles take JSON strings, not Solidity structs.

```solidity
// This is how BitBadges precompiles work:
precompile.transferTokens(
    '{"collectionId":"1","transfers":[{"from":"bb1p0rrel3365scadq5k9pv0x0zp9j22js6dnw70d","toAddresses":["bb1py4mfpg6uf59qkyzg0nmau322c5873eeysp5ue"],"balances":[{"amount":"1","tokenIds":[{"start":"1","end":"1"}],"ownershipTimes":[{"start":"1","end":"18446744073709551615"}]}]}]}'
);

// Not like ERC20:
token.transfer(to, amount);  // BitBadges does not use this pattern
```

The JSON maps directly to the Cosmos SDK protobuf messages, so the same shape works from the EVM, the CLI, and the SDK, and new fields do not break the interface. The helper libraries build the JSON for you; hand-written JSON is rare.

## Import the Libraries

```solidity
// Interface for calling the precompile
import "./interfaces/ITokenizationPrecompile.sol";

// Helpers for constructing JSON (always use these)
import "./libraries/TokenizationJSONHelpers.sol";

// Helpers for constructing structs
import "./libraries/TokenizationHelpers.sol";

// Type definitions
import "./types/TokenizationTypes.sol";

// Error handling
import "./libraries/TokenizationErrors.sol";
```

The files live under [`contracts/`](https://github.com/BitBadges/bitbadgeschain/tree/master/contracts) in the chain repo.

## Common Patterns

### Transfer Tokens

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

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

contract TransferExample {
    ITokenizationPrecompile constant PRECOMPILE =
        ITokenizationPrecompile(0x0000000000000000000000000000000000001001);

    function transfer(
        uint256 collectionId,
        address to,
        uint256 amount,
        uint256 tokenId
    ) external returns (bool) {
        address[] memory recipients = new address[](1);
        recipients[0] = to;

        string memory tokenIds = TokenizationJSONHelpers.uintRangeToJson(tokenId, tokenId);
        string memory times = TokenizationJSONHelpers.uintRangeToJson(
            1, TokenizationJSONHelpers.FOREVER
        );

        string memory json = TokenizationJSONHelpers.transferTokensJSON(
            collectionId, recipients, amount, tokenIds, times
        );

        return PRECOMPILE.transferTokens(json);
    }
}
```

### Check a Balance

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

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

contract BalanceExample {
    ITokenizationPrecompile constant PRECOMPILE =
        ITokenizationPrecompile(0x0000000000000000000000000000000000001001);

    function balanceOf(uint256 collectionId, address user) external view returns (uint256) {
        string memory json = TokenizationJSONHelpers.getBalanceAmountJSON(
            collectionId,
            user,
            1,  // tokenId
            block.timestamp * 1000  // ownershipTime in milliseconds
        );

        return PRECOMPILE.getBalanceAmount(json);
    }
}
```

`ownershipTime` is a single point in time. Pass the same unit your collection uses for ownership times (the chain convention is milliseconds, so `block.timestamp * 1000` for wall-clock times).

### Create a Collection

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

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

contract CreateCollectionExample {
    ITokenizationPrecompile constant PRECOMPILE =
        ITokenizationPrecompile(0x0000000000000000000000000000000000001001);

    function createCollection() external returns (uint256) {
        string memory validTokenIds = TokenizationJSONHelpers.uintRangeToJson(
            1, 1000  // Token IDs 1-1000
        );

        string memory metadata = TokenizationJSONHelpers.collectionMetadataToJson(
            "ipfs://bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi/collection.json", ""
        );

        string memory balances = TokenizationJSONHelpers.simpleUserBalanceStoreToJson(
            true, true, false  // auto-approve settings
        );

        string[] memory standards = new string[](0);
        string memory standardsJson = TokenizationJSONHelpers.stringArrayToJson(standards);

        string memory json = TokenizationJSONHelpers.createCollectionJSON(
            validTokenIds,
            TokenizationJSONHelpers.addressToString(address(this)),  // manager
            metadata,
            balances,
            "{}",  // permissions (empty = default)
            standardsJson,
            "",    // customData
            false  // isArchived
        );

        return PRECOMPILE.createCollection(json);
    }
}
```

### KYC Registry (Dynamic Store)

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

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

contract KycRegistryExample {
    ITokenizationPrecompile constant PRECOMPILE =
        ITokenizationPrecompile(0x0000000000000000000000000000000000001001);

    address public immutable owner = msg.sender;
    uint256 public kycStoreId;

    function initKYC() external {
        require(msg.sender == owner, "Only owner");
        require(kycStoreId == 0, "Already initialized");
        string memory json = TokenizationJSONHelpers.createDynamicStoreJSON(
            false,  // default: not KYC'd
            "", ""  // metadata
        );
        kycStoreId = PRECOMPILE.createDynamicStore(json);
    }

    function setKYC(address user, bool status) external {
        require(msg.sender == owner, "Only owner");
        require(kycStoreId != 0, "Not initialized");
        string memory json = TokenizationJSONHelpers.setDynamicStoreValueJSON(
            kycStoreId, user, status
        );
        PRECOMPILE.setDynamicStoreValue(json);
    }
}
```

## Error Handling

```solidity
import "./interfaces/ITokenizationPrecompile.sol";
import "./libraries/TokenizationErrors.sol";

contract MyContract {
    ITokenizationPrecompile constant PRECOMPILE =
        ITokenizationPrecompile(0x0000000000000000000000000000000000001001);

    function safeTransfer(uint256 collectionId, string memory json) external {
        // Validate before calling precompile
        TokenizationErrors.requireValidCollectionId(collectionId);

        try PRECOMPILE.transferTokens(json) returns (bool success) {
            require(success, "Transfer failed");
        } catch Error(string memory reason) {
            revert(reason);
        }
    }
}
```

Common errors:

- `"range overflow"`: use `FOREVER` instead of `type(uint256).max`.
- `"address cannot be empty"`: check the JSON field names.
- `"failed to unmarshal"`: invalid JSON format.

See [Errors](https://docs.bitbadges.io/chain/evm/tokenization-precompile/errors) for the full list.

## UintRange

Token IDs and ownership times are arrays of inclusive ranges.

```solidity
// Single value: token ID 5
TokenizationJSONHelpers.uintRangeToJson(5, 5);
// Produces: [{"start":"5","end":"5"}]

// Range: token IDs 1-100
TokenizationJSONHelpers.uintRangeToJson(1, 100);
// Produces: [{"start":"1","end":"100"}]

// Forever ownership (never expires)
TokenizationJSONHelpers.uintRangeToJson(1, TokenizationJSONHelpers.FOREVER);
// Produces: [{"start":"1","end":"18446744073709551615"}]

// Multiple ranges
uint256[] memory starts = new uint256[](2);
uint256[] memory ends = new uint256[](2);
starts[0] = 1; ends[0] = 100;
starts[1] = 200; ends[1] = 300;
TokenizationJSONHelpers.uintRangeArrayToJson(starts, ends);
// Produces: [{"start":"1","end":"100"},{"start":"200","end":"300"}]
```

Concept page: [UintRanges](https://docs.bitbadges.io/token-standard/concepts/uint-ranges).

## Address Formats

```solidity
// In Solidity, use EVM addresses (0x hex)
address user = 0x0bc63cfe31d5218eb414b142c799e20964a54a1a;

// Convert to Cosmos bech32 format if needed
string memory bech32 = PRECOMPILE.convertEvmAddressToBech32(user);
// Returns: "bb1p0rrel3365scadq5k9pv0x0zp9j22js6dnw70d"

// Convert back
address evm = PRECOMPILE.convertBech32ToEvmAddress("bb1p0rrel3365scadq5k9pv0x0zp9j22js6dnw70d");
// Returns: 0x0bc63cfe31d5218eb414b142c799e20964a54a1a
```

Both forms name the same account. Precompiles accept either form in JSON address fields and convert to bech32 internally.

## Utility Methods

```solidity
// Address conversion
string memory bech32 = PRECOMPILE.convertEvmAddressToBech32(evmAddress);
address evm = PRECOMPILE.convertBech32ToEvmAddress(bech32Address);

// Range checks
bool inRange = PRECOMPILE.rangeContains(10, 20, 15);  // true
bool overlap = PRECOMPILE.rangesOverlap(10, 20, 15, 25);  // true

// Search in range array
bool found = PRECOMPILE.searchInRanges('[{"start":"1","end":"100"}]', 50);

// Get balance for specific token/time
uint256 amount = PRECOMPILE.getBalanceForIdAndTime(balancesJson, tokenId, timestamp);

// Get reserved list ID for address
string memory listId = PRECOMPILE.getReservedListId(userAddress);
```

## Quick Reference

| Library | Purpose |
| --- | --- |
| `TokenizationJSONHelpers` | Build JSON strings for precompile calls |
| `TokenizationHelpers` | Build structs, constants, utilities |
| `TokenizationErrors` | Input validation, custom errors |
| `TokenizationTypes` | Type definitions |

| Method | Returns | Purpose |
| --- | --- | --- |
| `transferTokens(json)` | `bool` | Transfer tokens |
| `createCollection(json)` | `uint256` | Create collection, returns ID |
| `getBalanceAmount(json)` | `uint256` | Get balance amount |
| `createDynamicStore(json)` | `uint256` | Create store, returns ID |

## Related

- [Tokenization Precompile API](https://docs.bitbadges.io/chain/evm/tokenization-precompile/api)
- [Errors](https://docs.bitbadges.io/chain/evm/tokenization-precompile/errors)
- [Example contracts](https://github.com/BitBadges/bitbadgeschain/tree/master/contracts/examples)
- [GAMM Precompile](https://docs.bitbadges.io/chain/evm/gamm-precompile)
