AI agent documentation index: llms.txt. Raw markdown for any page is available by appending .md to the URL. Full content snapshot: llms-full.txt.
llms.txt — complete Cartesi documentation index. Append .md to any page URL for raw Markdown (e.g. /cartesi-rollups/2.0/development/building-an-application.md).
Skip to main content

Vouchers and withdrawals

Users deposit assets into your application, but only your application can send them back. It does this by emitting a voucher, a message that executes a call on the base layer once the epoch settles. CMA builds these vouchers for you with the correct destination and payload for each asset type.

The withdrawal flow

A complete withdrawal has three steps, and you have already seen the first two in the previous guides:

  1. Decode the request. The user sends an ABI encoded withdrawal input. The parser identifies it and returns the typed fields. See Parsing inputs.
  2. Debit the ledger. Call withdraw so the user's balance drops inside your application. If the user lacks funds, this call fails and you stop here. See Managing balances.
  3. Emit the voucher. Build and emit the voucher that releases the asset on the base layer.

Running the ledger debit before emitting the voucher matters. It guarantees a user can never withdraw more than they own.

Emitting vouchers

RollupCma has one emit method per asset type. Each builds the voucher and sends it to the machine in a single call. The application address needed for the voucher is captured automatically when you call read_advance_state():

# Ether
rollup.emit_ether_voucher(receiver, amount)

# ERC20
rollup.emit_erc20_voucher(token, receiver, amount)

# ERC721
rollup.emit_erc721_voucher(token, receiver, token_id)

# ERC1155
rollup.emit_erc1155_single_voucher(token, receiver, token_id, amount)
rollup.emit_erc1155_batch_voucher(token, receiver, token_ids, amounts)

A full withdrawal handler, from the wallet sample:

decoded = decode_advance(advance)

if decoded["type"] == "ERC20_WITHDRAWAL":
asset = ledger.retrieve_asset(token=decoded["token"])
account = ledger.retrieve_account(account=msg_sender)

ledger.withdraw(asset["asset_id"], account["account_id"], decoded["amount"])

rollup.emit_erc20_voucher(asset["token"], msg_sender, decoded["amount"])

What each voucher does on the base layer

AssetVoucher destinationEffect when executed
EtherThe receiver addressSends the Ether amount to the receiver
ERC20The token contractCalls the token's transfer function to pay the receiver
ERC721The token contractTransfers the token ID from the application to the receiver
ERC1155The token contractTransfers the token ID and amount, or batches of them, to the receiver

After the epoch that contains the input settles, anyone can execute the voucher on the base layer through the application contract. See Asset handling for the full lifecycle.

Voucher field structs

The exact fields each voucher type needs are listed in Types and selectors.

We use cookies to ensure that we give you the best experience on our website. By using the website, you agree to the use of cookies.