You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Corda中使用Cash State?附示例及简易场景可行性咨询

Hey there! Let's dive deep into working with the Cash State in Corda — I'll walk you through key concepts, practical code examples, and whether it's a fit for simple demo scenarios.

1. What is Cash State in Corda?

The Cash State is a built-in, pre-audited state type in Corda's finance module (net.corda.finance.contracts.asset.Cash) designed to represent fungible cash assets. It handles core cash operations like issuance, transfer, and redemption out of the box, so you don't have to build a custom asset contract from scratch.

Key traits of Cash State:

  • Supports multiple currencies (via Amount<Currency> type)
  • Allows splitting/merging of cash amounts (e.g., splitting a $100 state into $50 and $50 for a transfer)
  • Enforces security rules (only the issuer can destroy cash, only the owner can transfer it)
2. Core Concepts to Understand

Before jumping into code, let's clarify the critical components of Cash State:

  • Issuer: The node that creates the cash (e.g., a bank node in production, a test node in demos)
  • Owner: The node currently holding the cash state
  • Amount: A value paired with a currency code (e.g., Amount(10000, Currency.getInstance("USD")) for $100.00)
  • Issue: The process of creating new cash states
  • Move: Transferring cash from one owner to another (splitting/merging states as needed)
  • Exit: Destroying cash states (only allowed by the original issuer)
3. Step-by-Step Usage with Code Examples

Let's walk through the most common Cash State operations with Kotlin code (Corda's primary language).

3.1 Add Dependencies

First, make sure your project includes the Corda finance module in build.gradle:

dependencies {
    cordaCompile "$corda_release_group:corda-finance:$corda_release_version"
}

3.2 Issuing Cash (Creating Cash States)

To create cash, the issuer node runs a flow that generates new Cash States. Here's a simplified example:

@InitiatingFlow
@StartableByRPC
class IssueCashFlow(
    private val amount: Amount<Currency>,
    private val recipient: Party
) : FlowLogic<SignedTransaction>() {

    override fun call(): SignedTransaction {
        // Get the issuer's identity (current node)
        val issuer = ourIdentity

        // Create the Cash State: issuer is us, recipient is the target owner
        val cashState = Cash.State(amount, issuer, recipient)

        // Build the transaction
        val notary = serviceHub.networkMapCache.notaryIdentities.first()
        val txBuilder = TransactionBuilder(notary)
            .addOutputState(cashState, Cash.PROGRAM_ID)
            .addCommand(Cash.Commands.Issue(), issuer.owningKey)

        // Validate the transaction against the Cash contract rules
        txBuilder.verify(serviceHub)

        // Sign the transaction and finalize it with the recipient
        val signedTx = serviceHub.signInitialTransaction(txBuilder)
        val recipientSession = initiateFlow(recipient)
        val fullySignedTx = subFlow(CollectSignaturesFlow(signedTx, listOf(recipientSession)))

        return subFlow(FinalityFlow(fullySignedTx, listOf(recipientSession)))
    }
}

You can trigger this flow via RPC to issue, say, $500 to a customer node in your test network.

3.3 Transferring Cash (Moving Cash States)

Transferring cash involves consuming existing Cash States and creating new ones with the new owner. Corda's Cash.generateMove() helper handles splitting/merging logic automatically:

@InitiatingFlow
@StartableByRPC
class TransferCashFlow(
    private val amount: Amount<Currency>,
    private val recipient: Party
) : FlowLogic<SignedTransaction>() {

    override fun call(): SignedTransaction {
        // Query the vault for Cash States owned by the current node
        val ownedCashStates = serviceHub.vaultService.queryBy(Cash.State::class.java).states
            .filter { it.state.data.owner == ourIdentity }
            .filter { it.state.data.amount.token == amount.token }

        // Ensure we have enough cash to transfer
        val totalBalance = ownedCashStates.sumOf { it.state.data.amount.quantity }
        require(totalBalance >= amount.quantity) { "Insufficient cash balance" }

        // Build the transaction using Corda's built-in move helper
        val notary = serviceHub.networkMapCache.notaryIdentities.first()
        val txBuilder = TransactionBuilder(notary)
        Cash.generateMove(serviceHub, txBuilder, amount, recipient, ownedCashStates)

        // Add the transfer command (requires the current owner's signature)
        txBuilder.addCommand(Cash.Commands.Move(), ourIdentity.owningKey)

        // Validate and sign the transaction
        txBuilder.verify(serviceHub)
        val signedTx = serviceHub.signInitialTransaction(txBuilder)

        // Collect the recipient's signature and finalize the transaction
        val recipientSession = initiateFlow(recipient)
        val fullySignedTx = subFlow(CollectSignaturesFlow(signedTx, listOf(recipientSession)))

        return subFlow(FinalityFlow(fullySignedTx, listOf(recipientSession)))
    }
}

This flow will split your existing cash states as needed — for example, if you have a $100 state and transfer $30, it will create a $30 state for the recipient and a $70 state for you.

3.4 Querying Cash Balances

To check your node's cash holdings, query the vault and aggregate the amounts:

// Run this in a flow or RPC client
val cashBalances = serviceHub.vaultService.queryBy(Cash.State::class.java).states
    .filter { it.state.data.owner == ourIdentity }
    .groupBy { it.state.data.amount.token }
    .mapValues { entry ->
        Amount(entry.value.sumOf { it.state.data.amount.quantity }, entry.key)
    }

// Print the results
cashBalances.forEach { (currency, balance) ->
    println("Current balance for ${currency.code}: $balance")
}
4. Is Cash State Suitable for Simple Demo Scenarios?

Absolutely — Cash State is perfect for simple demos! Here are a few ideal use cases:

  • Peer-to-peer payment demo: Simulate two nodes sending cash to each other to showcase Corda's asset transfer workflow
  • Mini supply chain finance: Have a "core enterprise" node issue cash to "supplier" nodes as payment for goods
  • Test currency simulation: Create a fake test currency (e.g., "COR") and use it to demonstrate issuance, transfers, and balance tracking

Why it works for demos:

  • No need to write custom contract logic — Corda's built-in Cash contract handles all validation rules
  • The splitting/merging logic is abstracted away, so you can focus on core workflow
  • It's easy to set up in a local test network with just a few nodes

The only thing to note is that in demos, your "issuer" node can be any test node (you don't need a real bank) — it's purely for testing purposes.

5. Common Pitfalls to Avoid
  • Notary selection: Always use a notary that exists in your network (use networkMapCache.notaryIdentities.first() for tests)
  • Balance validation: Never skip checking if you have enough cash before a transfer — the Cash contract will reject the transaction if you don't
  • Signature requirements: Issuance flows need the issuer's signature; transfer flows need the current owner's signature — missing these will cause validation failures

内容的提问来源于stack exchange,提问作者user4473151

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 10:05:48