|
| 1 | +--- |
| 2 | +id: Integrating-the-CMA-ledger-library |
| 3 | +title: Integrating the CMA ledger library |
| 4 | +--- |
| 5 | + |
| 6 | +# Integrating the CMA Ledger Library |
| 7 | + |
| 8 | +The **Cartesi Machine Asset (CMA) Ledger** is a core library for managing assets, accounts, balances, and transfers inside Cartesi applications. |
| 9 | + |
| 10 | +You can think of the Ledger as a **plug-and-play wallet engine**. Once integrated, it allows your application to safely track and modify asset state without re-implementing common accounting logic such as deposits, withdrawals, and transfers. |
| 11 | +The CMA tools are split into **two complementary libraries**: |
| 12 | + |
| 13 | +- **Ledger**: Manages assets, accounts, balances, and state changes |
| 14 | +- **Parser**: Parses user input and structures data for the ledger to consume |
| 15 | + |
| 16 | +Together, they provide a smooth development experience: |
| 17 | +1. The parser receives raw user input and converts it into structured data. |
| 18 | +2. The ledger consumes this structured input and applies the corresponding asset and account updates. |
| 19 | + |
| 20 | +If you are not yet familiar with the parser, see [Integrating the CMA Parser Library](./Integrating-the-CMA-parser-library.md). |
| 21 | + |
| 22 | +By integrating the ledger, your application gains a secure, deterministic, and type-safe way to manage digital assets such as Ether, ERC20, ERC721, and ERC1155, while remaining fully compatible with Cartesi rollup workflows. |
| 23 | + |
| 24 | +## Why Use the Ledger? |
| 25 | + |
| 26 | +The CMA Ledger solves common asset-management problems in Cartesi applications: |
| 27 | + |
| 28 | +- **Unified Asset Management**: Manage multiple asset standards and account models from a single interface. |
| 29 | + |
| 30 | +- **Deterministic & Auditable**: Ledger behavior is identical across environments (tests, simulations, and production), making state changes predictable and auditable. |
| 31 | + |
| 32 | +- **Strong Safety Guarantees**: All operations return typed errors, eliminating silent failures and ambiguous states. |
| 33 | + |
| 34 | +- **Cartesi-Native Design**: Built specifically for Cartesi rollups, while remaining flexible and non-intrusive to application logic. |
| 35 | + |
| 36 | +## Key Capabilities |
| 37 | + |
| 38 | +- **Asset Models**: Support for Ether, ERC20, ERC721, and ERC1155-style assets. |
| 39 | + |
| 40 | +- **Account Models**: Support for Ethereum wallet addresses mapped to generic identifiers' ID. |
| 41 | + |
| 42 | +- **Asset Lifecycle Operations**: Create, retrieve, deposit, withdraw, and transfer assets. |
| 43 | + |
| 44 | +- **Balance & Supply Queries**: Read per-account balances and total asset supply at any time. |
| 45 | + |
| 46 | +- **Strong Typing**: Prevents asset/account mismatches at compile time. |
| 47 | + |
| 48 | +## Defined Data Types |
| 49 | + |
| 50 | +| Type | Description | |
| 51 | +|-----|------------| |
| 52 | +| `LedgerAssetId` | Internal 64-bit asset identifier | |
| 53 | +| `LedgerAccountId` | Internal 64-bit account identifier | |
| 54 | +| `AssetType` | ID-based, address-based, or address + ID | |
| 55 | +| `AccountType` | Wallet address or generic account ID | |
| 56 | +| `RetrieveOperation` | `Find`, `Create`, or `FindOrCreate` | |
| 57 | + |
| 58 | +## Commonly Used Methods |
| 59 | + |
| 60 | +### Asset and Account Retrieval |
| 61 | + |
| 62 | +- **retrieve_asset()**: Retrieve or create an asset in the ledger. |
| 63 | + |
| 64 | +- **retrieve_erc20_asset_via_address()**: Retrieve or create and return an ERC20 asset ID based on address. |
| 65 | + |
| 66 | +- **retrieve_erc721_assets_via_address()**: Retrieve or create and return an ERC721 asset ID based on address and token ID. |
| 67 | + |
| 68 | +- **retrieve_ether_assets**: Retrieve or create and return an Ether asset ID. |
| 69 | + |
| 70 | +- **retrieve_account()**: Retrieve or create a ledger account. |
| 71 | + |
| 72 | +- **retrieve_account_via_address()**: Retrieve or create and return a ledger account ID, based on a user address. |
| 73 | + |
| 74 | +### State Mutations |
| 75 | + |
| 76 | +- **deposit**: Deposit assets to an account's ledger record. |
| 77 | + |
| 78 | +- **withdraw**: Withdraw assets from an account's ledger record. |
| 79 | + |
| 80 | +- **transfer**: Transfer assets between accounts record. |
| 81 | + |
| 82 | +### Queries |
| 83 | + |
| 84 | +- **get_balance**: Get balance for an account from the ledger. |
| 85 | + |
| 86 | +- **get_total_supply**: Get total supply for an asset. |
| 87 | + |
| 88 | +### Lifecycle |
| 89 | + |
| 90 | +- **Ledger::new**: Creates a new ledger. |
| 91 | + |
| 92 | +- **ledger.reset**: Resets all records in a ledger. |
| 93 | + |
| 94 | +## Error Handling |
| 95 | + |
| 96 | +All ledger operations return a `LedgerError`, including: |
| 97 | + |
| 98 | +- Asset or account not found |
| 99 | +- Insufficient balance |
| 100 | +- Type mismatches |
| 101 | +- Internal ledger failures |
| 102 | + |
| 103 | +This makes error handling explicit and predictable. |
| 104 | + |
| 105 | +## Installation |
| 106 | + |
| 107 | +import Tabs from '@theme/Tabs'; |
| 108 | +import TabItem from '@theme/TabItem'; |
| 109 | + |
| 110 | + |
| 111 | +<Tabs> |
| 112 | +<TabItem value="Rust" label="Rust" default> |
| 113 | +<pre><code> |
| 114 | + |
| 115 | +```bash |
| 116 | +cargo add cma-rust-parser |
| 117 | +``` |
| 118 | +</code></pre> |
| 119 | +</TabItem> |
| 120 | +</Tabs> |
| 121 | + |
| 122 | + |
| 123 | +## Usage Example |
| 124 | + |
| 125 | + |
| 126 | +<Tabs> |
| 127 | +<TabItem value="Rust" label="Rust" default> |
| 128 | +<pre><code> |
| 129 | + |
| 130 | +```rust |
| 131 | +use cma_rust_parser::{ |
| 132 | + Ledger, AssetType, RetrieveOperation, AccountType, U256, Address |
| 133 | +}; |
| 134 | + |
| 135 | +let address_one = "0x0000000000000000000000000000000000000001"; |
| 136 | +let address_two = "0x0000000000000000000000000000000000000002"; |
| 137 | +let erc_20_token = "0x92C6bcA388E99d6B304f1Af3c3Cd749Ff0b591e2"; |
| 138 | +let erc_721_token = "0xc6582A9b48F211Fa8c2B5b16CB615eC39bcA653B"; |
| 139 | + |
| 140 | +// Initialize the ledger |
| 141 | +let mut ledger = Ledger::new()?; |
| 142 | + |
| 143 | +// Retrieve or create an asset |
| 144 | +let token_address = Address::from_str_hex(erc_721_token).unwrap(); |
| 145 | +let token_id = U256::from_u64(1); // Used for NFTs |
| 146 | + |
| 147 | +let asset_id = ledger.retrieve_asset( |
| 148 | + None, |
| 149 | + Some(token_address), |
| 150 | + Some(token_id), |
| 151 | + AssetType::TokenAddressId, |
| 152 | + RetrieveOperation::FindOrCreate, |
| 153 | +)?; |
| 154 | + |
| 155 | +// Retrieve or create an account |
| 156 | +let wallet_address = Address::from_str_hex(address_one).unwrap(); |
| 157 | + |
| 158 | +let account_id = ledger.retrieve_account( |
| 159 | + None, |
| 160 | + AccountType::WalletAddress, |
| 161 | + RetrieveOperation::FindOrCreate, |
| 162 | + Some(wallet_address.as_bytes()) |
| 163 | +)?; |
| 164 | + |
| 165 | +// Deposit tokens |
| 166 | +ledger.deposit(asset_id, account_id, U256::from_u64(1000)).unwrap(); |
| 167 | + |
| 168 | +// Transfer tokens |
| 169 | +let recipient_address = Address::from_str_hex(address_two).unwrap(); |
| 170 | +let receipient_id = ledger.retrieve_account_via_address(recipient_address).unwrap(); |
| 171 | + |
| 172 | +let transfer_result = ledger.transfer(asset_id, account_id, recipient_id, U256::from_u64(1)).unwrap(); |
| 173 | + |
| 174 | +// Query balances and supply |
| 175 | +let balance = ledger.get_balance(asset_id, account_id).unwrap(); |
| 176 | +let supply = ledger.get_total_supply(asset_id).unwrap(); |
| 177 | + |
| 178 | +// Retrieve ERC20 asset ID |
| 179 | +let erc20_address = Address::from_str_hex(erc_20_token).unwrap(); |
| 180 | +let erc20_token_id = ledger.retrieve_erc20_asset_via_address(erc20_address).unwrap(); |
| 181 | + |
| 182 | +// Withdraw Token |
| 183 | +let withdraw_result = ledger.withdraw(erc20_token_id, account_id, U256::from_u64(100000000000000000000)) |
| 184 | + |
| 185 | +// Retrieve Ether ID |
| 186 | +let ether_id = ledger.retrieve_ether_assets(); // Ether has no contract address hence there's no need to pass an address |
| 187 | +``` |
| 188 | +</code></pre> |
| 189 | +</TabItem> |
| 190 | +</Tabs> |
| 191 | + |
| 192 | +## Further Reading |
| 193 | + |
| 194 | +- [C++ API & language bindings](https://github.com/Mugen-Builders/machine-asset-tools) |
| 195 | +- [Integrating the CMA Library – Parser Functions](./Integrating-the-CMA-parser-library.md) |
0 commit comments