Uncategorized · November 21, 2025

Catana

Description

CATANA (Contract Assessment Through trAnsactioN replAy) is a testing framework that addresses one of the key challenges in the evolution of blockchain-based applications: how to safely upgrade smart contracts after deployment. While smart contracts are designed to be immutable, modern decentralized applications often rely on upgradeable architectures (e.g., proxy patterns) to enable evolution, bug fixes, or feature extensions without redeploying a new address. However, new contract versions should be released without introducing regressions or incompatibilites with dependent systems. 

CATANA tackles this issue through a capture-replay testing strategy specifically designed for Proxy-based Upgradeable Smart Contracts (USCs). The tool captures real transactions and execution traces from an existing deployed USC and then replays them against an upgraded version. By comparing the outcomes of the original and replayed executions, CATANA detects behavioral divergences, which can be a clear symptom of future issues.

Resources

Catana Repository : link

The main CATANA repository hosts the full source code and documentation describing how to capture blockchain traces, replay them against upgraded contracts, and interpret comparison results. 

Related Publications 

  • CATANA: Replay Testing for the Ethereum Blockchain M Barboni, GD Angelis, A Morichetta, A Polini IFIP International Conference on Testing Software and Systems, 257-265
  • Wielding Blockchain Transactions for Capture-Replay Testing of Upgradeable Smart Contracts M Barboni, G De Angelis, A Morichetta, A Polini ACM Transactions on Internet Technology

Getting Started

  1. Install the dependencies: with npm install.
  2. Add your Infura and Etherscan API keys in catana-config.js.
  3. Add your project configuration in catana-config.js.
  4. If needed, add the correct compiler version in hardhat-config.js.

Commands

CommandDescriptionUsageExample
capture <nTx> [startBlock]Extract a window of max nTx transactions executed on the Proxy, from an optional startBlock$ npm start buildWindow$ npm start buildWindow 10000
replay <strategy>Replay transactions on the local USC (single txHash, all)$ npm start replay <strategy>$ npm start replay 0x078abc...
cleanClean the testing environment$ npm start clean$ npm start clean

Project Structure

  • contracts/: source codes of the Proxy contract, and of the Local Logic contract under test (V2);
  • contracts/deployed: source codes of the Proxy contract, and of the old Logic contract deployed on Mainnet (V1);
  • hardhat.config.js: Hardhat configuration file;
  • catana-config.js: Replay testing configuration file;

Configuration

The Catana configuration is specified in a catana-config.js file.

FieldDescriptionDefault Value
catanaDirname of the directory where the catana logs are saved./catana
transactionsPathpath to the file containing the transactions to be replayed./catana/transactions/transactions.json
DeployedSourcesDirpath to the folder where the sources of the deployed contracts will be stored./contracts/deployed
UpgradedSourcesDirpath to the folder where the sources of the upgraded contracts (SUT) are stored./contracts
ProxyPathLocal path to the source code of the Proxy contract
UpgradedLogicPathLocal path to the source code of the upgraded Logic contract under test
DeployedProxyAddrAddress of the Proxy contract deployed on the Mainnet
DeployedLogicAddrAddress of the Logic contract (V1) deployed on the Mainnet
stateVarsBlacklistBlacklist for state variables to be ignored during Capture-Replay testing["__gap", "_gap"]
INFURA_KEYInfura api key
ETHERSCAN_KEEtherscan api key

Here’s a simple example of catana-config.js.

module.exports = {
    catanaDir: "./catana",
    transactionsPath: "./catana/transactions/transactions.json",
    DeployedSourcesDir: "./contracts/deployed",
    UpgradedSourcesDir: "./contracts",
    ProxyPath: "./contracts/CErc20Delegator.sol",
    UpgradedLogicPath: "./contracts/CErc20Delegate.sol",
    DeployedProxyAddr: "0x5d3a536e4d6dbd6114cc1ead35777bab948e3643",
    DeployedLogicAddr: "0xa035b9e130F2B1AedC733eEFb1C67Ba4c503491F",
    stateVarsBlacklist: ["__gap", "_gap", "myVar"],
    INFURA_KEY: "your-infura-key",
    ETHERSCAN_KEY: "your-etherscan-key"
}