A fairly useless toolkit for measuring gas costs in CosmWasm smart contracts. The true intent of this project is to provide a guided walkthrough of creating and deploying a non-standard cw contract, complete with automated deployment scripts, testing, and analysis. This goes a little outside the realm of the standard mintable/burnable token, or NFT collection deployment to encourage thinking outside of the box, with some portion of the project being completely off-chain.
The project measures gas consumption across different message sizes, formats, and character types. Results are stored in CSV format locally and on-chain.
Example results are available in this analysis report.
- Rust (beginner)
- JavaScript
- Cosmos SDK basics
graph TD
A[Build Contract] --> B[Deploy Contract]
B --> C[Run Gas Tests]
C --> D[Store Results On-Chain]
D --> E[Analyze Results]
E --> F[Generate Visualizations]
- Gas testing for message sizes, formats, and character types
- On-chain storage of test results
- Statistical regression analysis
- Transaction hash storage as proof
- Automated deployment to testing workflow
- Multi-chain configuration options
- Interactive chart generation
cw-gas-test/
βββ src/ # Rust contract code
β βββ lib.rs # Gas testing contract
βββ artifacts/ # Compiled contract (after build)
βββ scripts/ # JavaScript automation
β βββ config.js # Chain configuration
β βββ deploy.js # Contract deployment
β βββ test-gas.js # Gas testing
β βββ analyze-results.js # Analysis + Report Generation
β βββ package.json # JS dependencies
β βββ deployments.json # Tracks deployment addresses per chain
β βββ .env # Mnemonic ONLY (create from template)
βββ Cargo.toml # Rust dependencies
βββ rust-toolchain.toml # Rust version spec
βββ build.sh # Compilation script (build contract only)
βββ analyze_results.py # [Optional] Python data visualization
βββ cw-gas-test.sh # Complete workflow (build + deploy + test + analyze)- Rust (1.74.0+)
- Node.js (v18.0.0+)
- Yarn (or npm)
- Docker (for contract optimization)
- Fee tokens on the target network
jq(for JSON parsing in scripts)- Python (optional, for extra visualization)
1. Clone & Initial Prep (Click to expand)
git clone https://github.com/Cordtus/cw-gas-test.git
cd cw-gas-test
# Make the scripts executable
chmod +x build.sh cw-gas-test.sh2. Configure Your Chain Settings (Click to expand)
Network settings and other variables must be set in scripts/config.js.
Example:
// =============================
// CHAIN CONFIGURATION
// =============================
// Edit for your target chain
export const config = {
// Network settings
RPC_ENDPOINT: 'http://localhost:26657',
REST_ENDPOINT: 'http://localhost:1317',
CHAIN_ID: 'gaia-1',
ADDRESS_PREFIX: 'gaia',
// Token settings
TOKEN_NAME: 'STAKE', // Display name / ticker / symbol (e.g. 'ATOM', 'EVMOS')
TOKEN_DENOM: 'ustake', // Base denomination with prefix (e.g. 'uatom', 'aevmos')
GAS_PRICE: '0.025ustake',
GAS_ADJUSTMENT: 1.3, // Buffer to avoid tx failure
// Contract settings
CONTRACT_LABEL: 'gas_test_contract',
WASM_PATH: '../artifacts/cw_gas_test.wasm',
// Optional: Existing contract address if you do NOT want to deploy a new one on target chain.
// If your target chain is found in deployments.json, the contract address specified there will be used.
// In any other case, this script will build & deploy a new contract.
CONTRACT_ADDRESS: '', // Optional: reuse existing contract [check ./deployments.json]
// Test configuration
TEST_MESSAGE_LENGTHS: [1, 10, 50, 100, 200, 500, 1000, 2000],
OUTPUT_FILE: 'gas_results.csv',
REQUEST_DELAY: 1000, // Delay between requests in milliseconds
TX_CONFIRMATION_TIMEOUT: 10000, // Max time to wait for tx confirmation (ms)
TX_POLLING_INTERVAL: 3000, // How often to check for tx confirmation (ms)
};Important:
CONTRACT_ADDRESSis optional. Leave it blank to trigger new deployment (unless one is found indeployments.json).- If you already have a contract deployed, you can put its address here (or ideally, add it to
deployments.jsonand make a PR).
3. Provide Your Mnemonic in `.env` (Click to expand)
-
.env(located inscripts/) should contain only your wallet mnemonic. -
Example:
MNEMONIC="word1 word2 word3 ... word24"
key and wallet will be derived using the standard ../118/0/0/0 hdpath
If .env doesn't exist, copy .env.template to .env and fill in your mnemonic:
cd scripts
cp .env.template .env
# then edit .env to include your mnemonicPlease make a NEW wallet to use here. In any case, make sure the file is either in your .gitignore, or that you do not commit the changes to a public repo.
4. Option A: Manually Build & Run Steps (Click to expand)
If you only want to build the contract artifacts:
./build.shThis uses Docker to compile and optimize your CosmWasm contract. An optimized .wasm is placed in artifacts/.
Then you can run the JS scripts separately:
# From inside "scripts/"
yarn install # or npm install
yarn deploy # deploy.js
yarn test # test-gas.js
yarn analyze # analyze-results.jsThis will:
- Deploy (if
CONTRACT_ADDRESSis empty) or reuse an existing contract. - Run gas tests. [varied message sizes, formats, character types.]
- Generate a report in CSV, Markdown, and interactive HTML.
4. Option B: Full Combined Workflow (Click to expand)
A single script, cw-gas-test.sh, merges all setup and execution into one pass:
./cw-gas-test.shThis will:
- Check for a known contract address (either in
config.jsordeployments.json) - Build the contract if needed (via
./build.sh) - Deploy the contract if none is set
- Run the test suite (
test-gas.js) - Generate an analysis report and visualizations
When complete, you'll see:
gas_results.csvβ Raw test datagas_analysis.mdβ High-level summary with regression analysisgas_visualization.htmlβ Interactive visualization of results
Results in gas_results.csv:
| Message Length | Gas Used | Cost (ustake) |
|---|---|---|
| 1 | 129298 | 2585.96 |
| 10 | 129671 | 2593.41 |
| 50 | 131333 | 2626.66 |
| 100 | 133394 | 2667.88 |
| 200 | 141530 | 2830.60 |
| 500 | 149664 | 2993.28 |
| 1000 | 170624 | 3412.48 |
| 2000 | 212585 | 4251.70 |
Regression analysis output:
## Regression Analysis
- Base gas cost: 129256.99 gas units
- Marginal cost per byte: 41.37 gas units
- R-squared: 1.0000
## Formula
Total Gas = 129256.99 + 41.37 Γ Message Size (bytes)
Total Cost = Total Gas Γ 0.02 ustake/gas unit
Key metrics:
- Base Gas Cost: Fixed transaction cost (y-intercept)
- Marginal Gas Cost: Cost per additional byte (slope)
- Format Efficiency: Comparison between data formats
The formula Gas = 129256.99 + 41.37 Γ MessageSize indicates a base cost of ~129,257 gas plus ~41.37 gas per byte.
The smart contract includes:
-
Message Storage:
StoreMessage: Store any message with its actual lengthStoreFixedLength: Store a message padded/truncated to a specific length
-
Test Run Data:
RecordTestRun: Save aggregated test data with transaction proofsClearData: Remove old test data (admin only)
-
Queries:
GetConfig: Contract configurationGetMessage: Retrieve stored message by IDListMessages: List stored messages (paginated)GetTestRuns: Retrieve test run statistics (paginated)GetGasSummary: Get gas usage analysis summary
-
Error Handling:
- Custom error types for better error handling
- Input validation with meaningful error messages
- Proper authorization checks
You can edit parameters in scripts/config.js (like TEST_MESSAGE_LENGTHS, network endpoints) to suit your environment:
// New parameter options
MAX_PARALLEL_REQUESTS: 3, // Control parallel execution
GENERATE_VISUALIZATION: true, // Toggle visualization generation
SMALL_MESSAGE_THRESHOLD: 200, // Threshold for small/large message
RETRY_ATTEMPTS: 2, // Number of retries on failure
MAX_MESSAGE_SIZE: 10000, // Max msg sizeThe test suite examines:
- Message Length: Test how gas scales with increasing message size
- Message Format: Compare JSON, Base64, and Hex encoded data
- Character Type: Test different characters (ASCII, Unicode, Emoji)
To modify test parameters or add new test types:
- Edit
test-gas.jsto add new test functions - Update the corresponding contract message handlers in
lib.rs - Modify
analyze-results.jsto include new metrics in the analysis
If you already have a contract deployed:
-
Put its address into
config.jsunderCONTRACT_ADDRESS, or -
Place the address in
scripts/deployments.jsonfor the target chain: Example Formatting:{"deployments": [{"chainId":"contractAddress"}]} -
Please submit a pull request to include your contribution!
If your target chain exists in deployments.json, the scripts will skip re-deployment and run tests directly.
Potential enhancements:
- Batch transaction benchmarking
- Complex storage pattern testing
- Web-based visualization dashboard
- Cross-chain comparison framework
- CosmWasm memory operation benchmarks
RPC Errors
- Try alternate RPC endpoints in
config.js - Adjust
REQUEST_DELAYandTX_CONFIRMATION_TIMEOUTvalues - Verify endpoint supports required query methods
Out of Gas Errors
- Increase
GAS_ADJUSTMENTorGAS_PRICEinconfig.js - Reduce test message sizes for chains with stricter limits
- Check chain-specific gas configuration
Deployment Failures
- Ensure wallet has sufficient tokens for fees
- Check transaction logs in block explorer
- Verify contract compatibility with chain's CosmWasm version
- Check for chain-specific code size limitations
Permission Issues
- Run
chmod +x <script>for execution permission - Verify Docker daemon permissions
Transaction Timeouts
- Increase
TX_CONFIRMATION_TIMEOUTfor slower chains - Adjust
TX_POLLING_INTERVALfor congested networks
This tool can be adapted for other CosmWasm-enabled chains by updating config.js.
For different CosmWasm versions, update Cargo.toml dependencies to match the target chain and recompile with ./build.sh.
Directory of CosmWasm enabled networks, courtesy of Confio. Refer to the Cosmos Chain Registry for chain parameters and other information.
- CosmWasm: Smart contracting platform for Cosmos ecosystem
- Gas: Computational cost metric in blockchains
- WASM: WebAssembly, compiled format for CosmWasm contracts
- Mnemonic: Seed phrase for cryptographic key generation
- RPC Endpoint: Interface for blockchain node interaction
- Base Gas: Fixed transaction cost component
- Marginal Gas: Variable cost per data unit
- Regression Analysis: Statistical relationship modeling method
MIT License β see LICENSE file