|
| 1 | +# MxOps Development Guide |
| 2 | + |
| 3 | +MxOps is a Python automation tool for MultiversX blockchain. Users write YAML scene files that describe steps (contract deployments, calls, queries, token management) which MxOps executes. |
| 4 | + |
| 5 | +## Quick Reference |
| 6 | + |
| 7 | +### Essential Commands |
| 8 | +```bash |
| 9 | +# Install dev dependencies |
| 10 | +uv sync --group dev |
| 11 | + |
| 12 | +# Run ALL checks before PR (required) |
| 13 | +bash scripts/local_checks.sh |
| 14 | + |
| 15 | +# Run unit tests only |
| 16 | +bash scripts/launch_unit_tests.sh |
| 17 | + |
| 18 | +# Run integration tests (chain-simulator) |
| 19 | +uv run mxops chain-simulator start |
| 20 | +bash integration_tests/scripts/setup.sh chain-simulator |
| 21 | +bash scripts/launch_integration_tests.sh chain-simulator |
| 22 | +uv run mxops chain-simulator stop |
| 23 | +``` |
| 24 | + |
| 25 | +### Testing Development Changes |
| 26 | +```bash |
| 27 | +# Use development version (NOT globally installed mxops) |
| 28 | +uv run mxops <command> |
| 29 | +# or |
| 30 | +python -m mxops <command> |
| 31 | +``` |
| 32 | + |
| 33 | +### Code Quality (all must pass for PR) |
| 34 | +- **Bandit**: `uv run bandit -r mxops` - no security issues |
| 35 | +- **Flake8**: `uv run flake8 mxops tests integration_tests examples` - max-line-length=88 |
| 36 | +- **Ruff**: `uv run ruff format mxops && uv run ruff check mxops` - format + lint |
| 37 | +- **Pylint**: `uv run pylint mxops` - score >= 9.5 |
| 38 | + |
| 39 | +## Architecture |
| 40 | + |
| 41 | +### Core Flow |
| 42 | +```text |
| 43 | +YAML Scene -> Steps -> Transactions/Queries -> MultiversX Network |
| 44 | +``` |
| 45 | + |
| 46 | +### Key Directories |
| 47 | +| Directory | Purpose | |
| 48 | +|-----------|---------| |
| 49 | +| `mxops/execution/steps/` | All step implementations (28 types) | |
| 50 | +| `mxops/smart_values/` | Dynamic value resolution (`%`, `$`, `&`, `=` syntax) | |
| 51 | +| `mxops/data/` | ScenarioData persistence per network+scenario | |
| 52 | +| `mxops/cli/` | CLI commands (execute, data, config, chain-simulator) | |
| 53 | +| `tests/` | Unit tests (pytest) | |
| 54 | +| `integration_tests/` | Chain-simulator/devnet integration tests | |
| 55 | + |
| 56 | +### All Step Types (28) |
| 57 | +**Contracts**: `ContractDeploy`, `ContractUpgrade`, `ContractCall`, `ContractQuery`, `FileFuzzer` |
| 58 | +**Transfers**: `Transfer` |
| 59 | +**Tokens**: `FungibleIssue`, `NonFungibleIssue`, `SemiFungibleIssue`, `MetaIssue`, `FungibleMint`, `NonFungibleMint`, `ManageFungibleTokenRoles`, `ManageNonFungibleTokenRoles`, `ManageSemiFungibleTokenRoles`, `ManageMetaTokenRoles` |
| 60 | +**Setup**: `GenerateWallets`, `ChainSimulatorFaucet`, `R3D4Faucet`, `AccountClone` |
| 61 | +**Control**: `Loop`, `Scene`, `SetVars`, `SetSeed`, `Assert`, `Wait`, `Log`, `Python` |
| 62 | + |
| 63 | +### Smart Values Syntax |
| 64 | +| Symbol | Source | Example | |
| 65 | +|--------|--------|---------| |
| 66 | +| `%` | Scenario data | `%contract_id.address`, `%saved_value` | |
| 67 | +| `$` | Environment var | `$MY_ENV_VAR` | |
| 68 | +| `&` | Config file | `&PROXY` | |
| 69 | +| `=` | Formula | `=10**18`, `=randint(1,5)` | |
| 70 | + |
| 71 | +**Formula functions**: `int`, `str`, `float`, `rand`, `randint`, `choice`, `ceil`, `len` |
| 72 | + |
| 73 | +**Composition**: `%{${OWNER}_token.identifier}`, `={%{amount_1} + %{amount_2}}` |
| 74 | + |
| 75 | +## Adding New Steps |
| 76 | + |
| 77 | +1. Create dataclass in `mxops/execution/steps/<module>.py` |
| 78 | +2. Inherit from `Step` (non-tx) or `TransactionStep` (tx) |
| 79 | +3. Implement `_execute()` or `build_unsigned_transaction()` |
| 80 | +4. Export in `mxops/execution/steps/__init__.py` |
| 81 | +5. Add tests in `tests/` |
| 82 | + |
| 83 | +Pattern: |
| 84 | +```python |
| 85 | +@dataclass(kw_only=True) |
| 86 | +class MyStep(TransactionStep): |
| 87 | + my_param: SmartStr |
| 88 | + optional_param: SmartInt | None = None |
| 89 | + |
| 90 | + def build_unsigned_transaction(self) -> Transaction: |
| 91 | + param = self.my_param.get_evaluated_value() |
| 92 | + ... |
| 93 | +``` |
| 94 | + |
| 95 | +## Branch/Commit Conventions |
| 96 | + |
| 97 | +- **Branches**: `feature/<name>`, `fix/<name>`, `refactor/<name>`, `docs/<name>`, `test/<name>`, `breaking/<name>` |
| 98 | +- **Commits**: Conventional Commits format (automated versioning depends on this) |
| 99 | +- **PRs target**: `develop` branch |
| 100 | + |
| 101 | +## Gotchas |
| 102 | + |
| 103 | +1. **Smart values must be quoted in YAML**: Use `"%var"` not `%var` |
| 104 | +2. **Step type suffix optional**: `ContractCall` and `ContractCallStep` both work |
| 105 | +3. **Formula results are typed**: `=10**18` returns int, use `=str(...)` if string needed |
| 106 | +4. **Scenario isolation**: Each network+scenario combo has separate persisted data |
| 107 | +5. **ABI recommended**: Always provide ABI for automatic argument encoding/decoding |
0 commit comments