Chialisp Lesson 19: Best Practices Checklist for Secure and Efficient Smart Coins

13 min read

Chialisp best practices for code optimization and cost reduction in smart coin development

Key Takeaways

  • Security First: Always use AGG_SIG_ME over AGG_SIG_UNSAFE to bind signatures to specific coins and prevent replay attacks1
  • Announcement Protection: Include coin IDs in CREATE_COIN_ANNOUNCEMENT to prevent different coins from satisfying the same assertion2
  • Cost Optimization: Minimize CREATE_COIN and signature conditions while aggregating spends to reduce blockchain fees significantly3
  • Validation Always: Treat all solution arguments as hostile and implement comprehensive range-checking and type validation
  • Test Thoroughly: Use the Chia Simulator for integration testing and include regression tests for every bug fix to prevent future vulnerabilities

Article Summary

This chialisp best practices checklist provides a comprehensive framework for writing secure, efficient, and maintainable smart coins on Chia Network, covering critical security patterns, cost optimization techniques, proper testing methodologies, and deployment considerations that every Chialisp developer must implement before mainnet deployment.

Why a Chialisp Best Practices Checklist Matters

If you’ve worked through Lessons 1-18 of this Chialisp tutorial series, you’ve built a solid foundation in environment setup, basic syntax, puzzle creation, signatures, announcements, and advanced patterns like payments and asset bridging. But knowing how to write Chialisp code and knowing how to write secure, production-ready Chialisp code are two very different things.4

The coin-set model that makes Chia unique also introduces security considerations that don’t exist in account-based blockchains. A single mistake in your announcement structure can allow replay attacks. An unvalidated solution parameter can let anyone drain your smart coin. Missing cost optimizations can make your application prohibitively expensive to use. This is why having a chialisp best practices checklist isn’t optional—it’s essential for any developer serious about building on Chia Network.

Chialisp is designed to be a pure and functional language with a focus on security and auditability, making it ideal for locking funds in smart coins until spent and released by their owner.5 This lesson provides a systematic validation framework through a comprehensive checklist you can reference throughout your development lifecycle.

Understanding the Chialisp Security Landscape

Before diving into specific checklist items, you need to understand the unique security challenges in Chialisp development. Unlike Solidity or other smart contract languages where state lives in contract storage, Chialisp operates on individual coins in a stateless environment. This fundamental architectural difference means your security model must account for coin-level validation rather than global state protection.

Every coin you create is a potential attack vector. Farmers can see your solution before including it in a block. Other users can attempt to spend your coins if your puzzle logic contains flaws. Malicious actors can try to replay signatures, substitute announcements, or manipulate the order of spends in a bundle. Your chialisp best practices checklist must address all these threat vectors systematically.

The Coin-Centric Threat Model

When building any Chialisp application, start by defining your explicit threat model. Ask yourself who can cheat, who can grief or censor transactions, and where the incentive structures lie between users, protocol participants, and farmers. This isn’t just theoretical exercise—your threat model directly determines which security patterns you must implement. For example, if you’re building a decentralized exchange, you need to consider how a farmer might modify solution parameters to redirect liquidity to their own address. If you’re creating a custody solution, you must account for how old signatures might be replayed after a key rotation.

State Reconstruction and Invariants

Decide explicitly where your application state lives. Does it exist in the coin graph itself, in singleton structures, in CAT tokens, in NFTs, or in an off-chain database that you reconstruct from coin history? Each approach has different security implications and requires different validation patterns in your checklist. Once you know where state lives, specify your invariants in plain language first. For instance, “total pool shares always equal total liquidity” or “only the admin public key can update oracle prices.” Then map these human-readable invariants to specific puzzle conditions or spend-bundle-level assertions that enforce them.

Security Patterns and Signature Handling

Security PatternImplementationWhy It Matters
AGG_SIG_ME vs AGG_SIG_UNSAFEAlways prefer AGG_SIG_MEAutomatically appends coin ID and genesis challenge to the signed message, making the signature valid only for that exact coin spend1
Announcement ProtectionInclude coin ID in CREATE_COIN_ANNOUNCEMENTPrevents different coins from satisfying same assertion2
Solution ValidationValidate all parameters before executionStops anyone from spending your coin with malicious inputs6
Explicit FailuresUse (x) in impossible branchesFails loudly instead of silently succeeding6

Never Use Password Coins or Bare Secrets

One of the most common mistakes beginners make is creating “password coins” where knowledge of a secret value allows spending. This pattern is fundamentally insecure in Chialisp because solutions are visible on-chain. Instead, always require signatures keyed to specific coins and spends. If you reviewed Lesson 7 on signature aggregation, you learned the mechanics of how signatures work—now we’re applying that knowledge to security.7

When choosing between AGG_SIG_ME and AGG_SIG_UNSAFE, the chialisp best practices checklist clearly states: prefer AGG_SIG_ME. This condition automatically binds the signature to the specific coin ID, puzzle hash, amount, and genesis challenge, making it impossible for an attacker to reuse that signature on a different coin. AGG_SIG_UNSAFE requires you to manually include these bindings in the signed message, which is error-prone and easy to get wrong.1

Announcement-Based Coordination

Back in Lesson 11 when we covered announcements, you learned the basic CREATE_COIN_ANNOUNCEMENT and ASSERT_COIN_ANNOUNCEMENT pattern. These conditions still work and are still supported, but as of CHIP-0025 (activated at block height 5,716,000) they are no longer the recommended approach.

The current best practice is to use the newer SEND_MESSAGE and RECEIVE_MESSAGE conditions instead, which were designed specifically to make atomic multi-coin spends harder to get wrong. If you are spending coins that were created before SEND_MESSAGE and RECEIVE_MESSAGE existed, you will still need the old announcement pattern — and in that case, always include the coin ID of the announcing coin in the announcement message. Without it, a completely different coin could create the same announcement and satisfy your assertion, potentially draining funds or bypassing access controls.2

Use announcements to tie related spends together and prevent farmers from modifying solutions or creating piggyback bundles. If your application requires multiple coins to be spent atomically—like in a decentralized exchange where both sides of a trade must execute together—announcements provide that coordination mechanism. But only if you implement them correctly according to the checklist.

Farmer-Resistant Solution Design

Remember that farmers see your solution before including it in a block. If a farmer can alter any meaningful argument or condition and still produce a valid spend, you have a critical vulnerability. Your puzzle must recompute and check expected conditions rather than simply emitting whatever the solution provides. For example, if your puzzle creates an output coin, don’t let the solution directly specify the amount—calculate it from validated inputs and verify the math yourself.

Arguments, Encoding, and Validation Best Practices

The golden rule of Chialisp security is simple: treat all arguments as hostile. Every parameter that comes through the solution is potentially malicious, crafted by an attacker trying to exploit your puzzle logic. This means comprehensive validation is not optional—it’s the foundation of secure Chialisp development.

Range Checking and Type Validation

Range-check and type-check anything that affects amounts, coin IDs, or control flow. If your puzzle accepts an amount parameter, verify it’s non-negative. If it accepts a coin ID, verify it has the correct format and length. If it accepts a public key, verify it’s a valid curve point. These validations might seem tedious, but they prevent entire classes of attacks.

The CAT1 vulnerability demonstrated how insufficient validation of concatenated data structures can lead to token inflation attacks affecting millions of dollars in assets.8 That bug occurred because the hashing mechanism didn’t include clear length delimiters, allowing attackers to craft ambiguous inputs. Your chialisp best practices checklist must include proper encoding validation to prevent similar issues.

Structured Data Hashing

When hashing structured data for coin IDs, announcements, or other identifiers, include clear length or tag delimiters to prevent ambiguity and concatenation attacks. The lesson from CAT1 is that simple concatenation without boundaries creates security vulnerabilities. Instead, use dedicated helpers like the coinid function rather than manually hashing concatenated fields, or include explicit length prefixes before each field.8

For domain separation, include protocol-specific tags or prefixes in your hashes and announcements. Instead of a generic announcement message like “mint” or “burn”, use something like “my_protocol:pool:mint:” followed by relevant IDs, amounts, and direction fields. This prevents cross-protocol replay attacks where an announcement from one application might accidentally satisfy a condition in another.

Conservation Rules and Amount Validation

Validate that created amounts are non-negative and that conservation rules hold where appropriate. In many Chialisp applications, the sum of input amounts must equal the sum of output amounts. Your puzzle should explicitly verify this rather than trusting the solution to provide correct values. Calculate expected outputs from validated inputs, then assert that the actual created coins match your calculations.

Singletons, CATs, and Stateful Object Patterns

If you’ve built singletons or worked with CAT tokens (covered in Lessons 14 and 15), you know these patterns require special care. Singletons maintain uniqueness through lineage tracking, while CATs maintain supply guarantees through tail validation. Both require rigorous adherence to best practices to prevent duplication, inflation, or state corruption.9

Singleton Lineage Enforcement

For singletons, enforce the singleton lineage conditions on every single spend without exception. Verify that exactly one new singleton coin is created with the updated state and that the lineage proof correctly chains from the previous state. Missing this validation even once creates the possibility of singleton duplication, which breaks the fundamental uniqueness guarantee that makes singletons useful.

When designing liquidity pools, vaults, or other stateful applications using singletons, ensure that each state update is unique and cannot be replayed. Include sequence numbers, nonces, or announcements that bind each state transition to its specific context. This prevents attackers from replaying old state transitions to reset your application to a vulnerable previous state.

CAT Supply Integrity

For CAT tokens, follow the current CAT standard and Tail patterns exactly. Make any supply-changing logic extremely small and auditable—this is not the place for complex conditionals or multiple code paths. The simpler your minting and burning logic, the easier it is to verify that supply rules are maintained correctly.9 Every CAT spend must prove that the total supply remains constant (for non-mintable tokens) or changes only according to explicitly authorized mint/burn operations (for mintable tokens). This verification happens through the tail puzzle validation that occurs on every CAT transaction.

Cost Optimization and Performance

Optimization TechniqueCost ImpactBest Practice
Minimize CREATE_COIN conditionsHigh – significant cost per condition3Aggregate outputs into fewer coins when possible
Minimize AGG_SIG conditionsHigh – significant cost per condition3Combine signatures where security permits
Use cheaper operatorsMedium – can save 20-30% on complex logicConsult operator cost tables when choosing approaches3
Avoid deep environment treesMedium – access costs increase with depthKeep parameter lists compact and well-organized

Understanding Chialisp Cost Model

Every operation in Chialisp has a cost, and the total cost of your puzzle determines how expensive it is to spend coins using that puzzle. Every byte of data your puzzle adds to the blockchain costs 12,000 CLVM cost units. On top of that, the two most expensive conditions are CREATE_COIN at 1,800,000 cost units each and AGG_SIG_ME at 1,200,000 cost units each. If your application creates many small output coins or requires multiple independent signatures, these costs stack up fast and can make your application too expensive for real users.

The chialisp best practices checklist says to aggregate output creation where possible. Instead of creating one coin per logical bucket when you could combine them, look for opportunities to create fewer, larger coins. For example, if your decentralized exchange creates separate fee coins for each trade, consider batching multiple trades and creating a single fee coin for the batch.

Operator Selection and Code Structure

Consult operator cost tables when choosing between arithmetic approaches and bitwise operations. Sometimes a seemingly elegant solution using complex list manipulation costs significantly more than a straightforward arithmetic alternative. The cost difference might not matter for a puzzle that runs once, but for high-frequency operations like DEX swaps or payment routing, every cost unit matters.3

Use non-inline functions where parameters are reused multiple times. If you reference the same curried value or calculated result in several places, extract it into a named binding to avoid duplicated expressions. Each time you recalculate the same value, you pay the computation cost again. Following the patterns from Lesson 9 on modular puzzle design, keeping your code well-organized also keeps costs down.

Currying for Reusability

For parameters that are fixed at coin creation time, use currying. This allows you to reuse the same base puzzle logic while generating unique puzzle hashes for different instances. For example, if you’re creating custody coins with different owner public keys, curry the public key into the puzzle rather than passing it through the solution on every spend. This reduces solution size and makes your code more efficient.6

Implementation Hygiene and Code Organization

Clean, well-organized code isn’t just about aesthetics—it directly impacts security and maintainability. The chialisp best practices checklist emphasizes keeping puzzles small and composable. Wrap your core logic in inner puzzles and add outer policy wrappers for things like singleton tracking, timelock enforcement, or authorization checks.

Avoid Copy-Paste Programming

Never copy-paste standard logic like signature checks or announcement validation. Instead, reuse proven patterns from official documentation and reference puzzles. Every time you reimplement a standard pattern, you risk introducing subtle bugs. Every copy-paste operation creates a maintenance burden where bugs must be fixed in multiple locations. Use the modular design principles from Lesson 9 to build reusable components.

Comment the Why, Not the What

Your comments should explain security rationale and invariants, not describe obvious CLVM forms. A comment like “creates a coin announcement” adds no value—the code already shows that. Instead, explain why: “creates coin announcement to atomically link this spend with the pool reward distribution, preventing farmer from separating them.” Keep your comments aligned with the threat model you defined at the start of development.

Clear Naming and Magic Number Elimination

Use clear, descriptive names for curried parameters. Names like admin_pk, oracle_ph, and fee_bps immediately communicate purpose. Avoid names like param1, arg2, or single letters unless following established mathematical conventions. Similarly, eliminate magic constants—if you have a hardcoded number like 100 representing basis points, define it as a named constant so future maintainers understand its meaning.6

Testing and Review Best Practices

Testing Chialisp is fundamentally different from testing account-based smart contracts. You’re not testing state transitions in a global contract—you’re testing spend validity for individual coins and bundles. Your testing strategy must cover unit tests at the CLVM level, integration tests in a simulator, and comprehensive regression testing.4

Unit Testing All Branches

Unit-test your puzzles at the CLVM level for every branch, especially failure paths and malformed inputs. Most developers test the happy path where everything works correctly, but attackers target the edge cases where validation might fail. Test what happens when amounts are negative, when coin IDs are the wrong length, when signatures are missing, when announcements don’t match. Every conditional branch in your code needs test coverage.

If you followed Lesson 13 on testing methodologies, you learned how to set up basic unit tests. Now apply that knowledge systematically to every puzzle you write. Use the brun command to execute your compiled code with various parameter combinations and verify that it fails gracefully in error cases rather than producing undefined behavior.4

Simulator Integration Testing

Run integration tests in the Chia Simulator for realistic coin graphs, simultaneous spends, offer flows, and conflict scenarios. The simulator lets you test complex multi-coin interactions without spending real XCH. Create test scenarios where multiple users interact with your application simultaneously, where coins are spent in different orders, where bundles conflict with each other.

Test farmer-manipulation scenarios explicitly. What happens if a farmer sees your solution and tries to modify parameters before including it? What happens if they try to insert additional spends into your bundle? What happens if they delay your transaction to change timing-dependent conditions? These aren’t theoretical attacks—they’re real threat vectors that your testing must cover.

Regression Testing

Add regression tests whenever you fix a bug, particularly around announcements, coin ID derivation, and boundary conditions. If you discovered a vulnerability once, create a test that would have caught it, then verify that your fix actually prevents it. Regression tests ensure that future changes don’t reintroduce old bugs.

Adversarial Code Review

Have at least one reviewer walk through your coin graph and spend scenarios from an attacker’s perspective, not just a happy-path user. Ask your reviewer to actively try to break your assumptions. Can they spend coins they shouldn’t control? Can they extract value they shouldn’t receive? Can they manipulate state in unexpected ways? This adversarial mindset catches vulnerabilities that benevolent testing misses.

Deployment and Operations Checklist

Before deploying any Chialisp code to mainnet, work through a formal pre-deployment checklist. This isn’t just good practice—it’s the difference between a successful launch and a costly exploit that drains user funds.

Versioning and Upgrade Paths

Version your puzzles explicitly using constants like PROTO_V1, PROTO_V2. Even if you don’t plan to upgrade immediately, design a well-defined migration path from the beginning. Retrofitting upgrade logic after deployment is much harder than building it in from the start. Document how users will migrate from version 1 to version 2, what happens to existing coins, and whether migration is automatic or requires user action.

Key Role Documentation

Document all required key roles in your system—admin keys, oracle keys, relayer keys, liquidity provider keys. For each role, specify what actions they can and cannot take. Explain how keys can be rotated if they’re compromised. Define the security assumptions around each key role. If your admin key is compromised, what’s the blast radius? Can you implement timelocks or multisig to limit damage?

Farmer-Safe User Flows

For user-facing flows, ensure that offers and spend bundles are farmer-safe. There should be no way for a farmer to tweak solutions to change payouts or drain funds. Every value that affects where money goes must be either cryptographically committed (through signatures or announcements) or calculated deterministically from validated inputs.

Public Checklist Maintenance

Keep a minimal, public checklist in your repository and mark each item off before mainnet deployment. Link to relevant Chialisp documentation sections for each checklist item. This serves multiple purposes: it creates accountability, it helps auditors understand your security posture, and it provides a template for other developers to follow.

Case Studies: Best Practices in Action

The CAT1 token standard was retired after a vulnerability in its announcement structure allowed token inflation attacks, demonstrating why proper length delimiters in hashed data structures are non-negotiable in the chialisp best practices checklist.8 The Chia development team’s response included not just a fix, but a comprehensive review of all standard puzzles to ensure similar patterns didn’t exist elsewhere, showing how one vulnerability drives systematic improvement.

Dexie, a decentralized exchange on Chia Network, implements announcement-based atomic swaps that prevent farmers from separating trade sides or redirecting liquidity, demonstrating the practical application of CREATE_COIN_ANNOUNCEMENT patterns for securing multi-coin transactions.10 Their open-source puzzle code serves as a reference implementation of many items on this checklist, particularly around cost optimization and farmer-resistant design.

Conclusion: Making the Checklist Your Development Habit

The chialisp best practices checklist isn’t something you review once and forget. It’s a living document that should guide every commit, every code review, and every deployment decision. Start by going through the checklist on your current project right now—you’ll likely find items you’ve overlooked. That’s not failure; that’s the checklist working as intended.

As you build more Chialisp applications, these practices will become second nature. You’ll instinctively reach for AGG_SIG_ME instead of AGG_SIG_UNSAFE. You’ll automatically include coin IDs in announcements. You’ll validate inputs before you even write the core logic. That transformation from conscious checklist-following to unconscious best practice is the mark of a mature Chialisp developer.

Take action today: bookmark this checklist, add it to your development workflow, and commit to reviewing it before every mainnet deployment. The security of your users’ funds depends on it.

Chialisp Best Practices Checklist FAQs

What is the most important item on the chialisp best practices checklist?

The most important item on the chialisp best practices checklist is using AGG_SIG_ME instead of AGG_SIG_UNSAFE for signature validation, because it automatically binds signatures to specific coin IDs, puzzle hashes, and amounts, preventing signature replay attacks that could drain funds across multiple coins.1

How does the chialisp best practices checklist prevent announcement-based attacks?

The chialisp best practices checklist prevents announcement-based attacks by requiring developers to include the specific coin ID in every CREATE_COIN_ANNOUNCEMENT, which ensures that only that exact coin can create the announcement and prevents different coins from satisfying the same ASSERT_COIN_ANNOUNCEMENT condition.2

Why does the chialisp best practices checklist emphasize cost optimization?

The chialisp best practices checklist emphasizes cost optimization because expensive puzzles create prohibitive transaction fees that make applications unusable, and minimizing CREATE_COIN and AGG_SIG conditions while aggregating spends can reduce costs significantly in complex applications.3

What testing approaches does the chialisp best practices checklist recommend?

The chialisp best practices checklist recommends three layers of testing: unit tests at the CLVM level for all code branches including failure cases, integration tests in the Chia Simulator for realistic multi-coin scenarios, and regression tests for every fixed bug to prevent reintroduction of vulnerabilities.4

How should developers handle solution parameters according to the chialisp best practices checklist?

According to the chialisp best practices checklist, developers must treat all solution parameters as hostile input and implement comprehensive validation including range checks for amounts, type checks for coin IDs, and verification that conservation rules hold before allowing any spend to succeed.6

Chialisp Best Practices Checklist Citations

  1. Chia Network, “Signatures,” Chia Documentation, https://docs.chia.net/chialisp-signatures/
  2. Chialisp, “Conditions,” Chialisp Documentation, https://chialisp.com/conditions/
  3. Chialisp, “Costs,” Chialisp Documentation, https://chialisp.com/costs/
  4. Chia Network, “Intro to Chialisp,” Chia Documentation, https://docs.chia.net/chialisp-intro/
  5. Chialisp, “About Chialisp,” Chialisp Documentation, https://chialisp.com
  6. Chia Network, “Smart Coins,” Chia Documentation, https://docs.chia.net/chialisp-smart-coin/
  7. Chia Network, “Chialisp and TypeScript,” Chia Documentation, https://docs.chia.net/guides/crash-course/chialisp-and-typescript/
  8. Chia Network, “CAT1 Vulnerability Explained – CVE and CWE,” Chia Network Blog, July 29, 2022, https://www.chia.net/2022/07/29/cat1-vulnerability-explained-cve-and-cwe/
  9. Chialisp, “CATs,” Chialisp Documentation, https://chialisp.com/cats/
  10. Dexie, “Decentralized Exchange for Chia Offers,” https://dexie.space/