---
name: lifinance-analyze-tx
description: "Analyze a failing transaction by hash and network"
license: "LGPL-3.0"
metadata:
  decimalai-skill-id: "62deba95-9c44-4293-a594-cc0a2656bc21"
  decimalai-version-id: "53235f60-e699-418f-823c-9430662a2be9"
  decimalai-version: "1"
  decimalai-body-sha256: "e3afba6f6fa461816be7fcd4a8c0c0340ec62cf3cdf7d24073f373e0172c87b6"
  decimalai-name: "lifinance/analyze-tx"
  decimalai-format: "1"
  decimalai-invocation: "model"
  decimalai-category: "coding"
  decimalai-source: "https://app.decimal.ai/s/lifinance-analyze-tx@1/SKILL.md"
---
# Transaction Trace Analysis Command

> **Usage**: `/analyze-tx <network> <tx_hash>`
>
> Example: `/analyze-tx ethereum 0x1234...abcd`

## ⚠️ CRITICAL: Trace-First Analysis Principle

**THE EXECUTION TRACE AND LOGS ARE THE SOURCE OF TRUTH - THEY SHOW WHAT ACTUALLY HAPPENED.**

### Source of Truth Hierarchy

1. **Execution Trace** (`debug_traceTransaction`) - Shows WHAT ACTUALLY HAPPENED:

   - Every function call that occurred
   - Every contract interaction
   - Value transfers
   - Revert points and error messages

2. **Transaction Receipt Logs** - Shows WHAT EVENTS ACTUALLY EMITTED:

   - Every event that was emitted
   - Event topics and data are facts

3. **Code (Source Files)** - Reference for understanding, NOT facts:
   - Shows what SHOULD happen under normal conditions
   - Helps understand intended behavior
   - Use to understand context, not to claim what happened

### Analysis Rules

✅ **DO:**

- State what trace shows: "The trace shows function X was called"
- State what logs show: "The logs show event Y was emitted"
- Use code to understand context: "Based on the code, function X should..."
- Cross-reference trace with code to understand intent vs. reality

❌ **DON'T:**

- Claim an event was emitted if it's not in the logs
- Claim a function was called if it's not in the trace
- Assume something happened because code shows it should happen
- Hallucinate or infer events/calls that aren't explicitly in trace/logs

**Example:**

- ❌ **WRONG**: "The transaction called `swapAndStartBridgeTokensViaStargate` and emitted `LiFiTransferStarted` events."
- ✅ **CORRECT**: "The trace shows `swapTokensMultipleV3ERC20ToERC20` was called. The receipt logs show `LiFiGenericSwapCompleted` was emitted. No `LiFiTransferStarted` events are present in the logs."

## Quick Checklist

1. ✅ **Fetch Data** - Use premium RPC (via `analyzeFailingTx <NETWORK> <TX_HASH>` or user-provided RPC)
2. ✅ **Identify** - Was LiFiDiamond called? If not, state: "Not one of our transactions"
3. ✅ **Decode** - Extract calldata, `msg.value` (from receipt, NOT trace), map addresses to names
4. ✅ **Facet** - Identify facet, load code, find config file (check deploy script for correct filename)
5. ✅ **Params** - Extract BridgeData, SwapData, FacetData
6. ✅ **Trace** - Analyze step-by-step from ACTUAL trace data (not code assumptions), find ALL revert points
7. ✅ **Events** - Verify events from receipt logs (never assume based on code)
8. ✅ **Root Cause** - Expected vs. provided, why failed, what's needed

## Critical Rules

1. ⚠️ **Premium RPC only** - Use `analyzeFailingTx` or user-provided premium RPC; NEVER silently fall back to public RPCs
2. ⚠️ **LiFiDiamond check first** - Confirm involvement (direct/indirect) or state it's not our transaction
3. ⚠️ **msg.value from receipt** - NOT from trace
4. ⚠️ **TRACE IS SOURCE OF TRUTH** - Never claim something happened if it's not in the trace/logs (see Trace-First Principle above)
5. ⚠️ **VERIFY function selectors** - NEVER assume; ALWAYS cross-check with:
   - Actual function name from trace (preferred)
   - `out/<ContractName>.sol/<ContractName>.json` methodIdentifiers
   - `cast sig "<FUNCTION_SIGNATURE>"` to get expected selector
   - If `cast 4byte` returns different function, use trace function name!
6. ⚠️ **VERIFY events from logs** - NEVER assume events were emitted based on code; check receipt logs
7. ⚠️ **Enrich all addresses** - Use whitelist.json (DEXS/PERIPHERY), deployments, configs
8. ⚠️ **Config file from deploy script** - Don't assume filename matches facet name
9. ⚠️ **DEX names from whitelist.json** - Never use generic terms when specific name available
10. ⚠️ **Check native fees** - Verify FacetData requirements
11. ⚠️ **Find ALL reverts** - There may be multiple failure points
12. ⚠️ **Never assume** - Nested calls may have failed; value may not have come from root tx

## Tron-Specific Analysis

### Tron RPC Limitations

- `debug_traceTransaction` is **NOT available** on TronGrid public endpoints
- `triggerconstantcontract` simulates state-changing functions in read-only mode — **return values are unreliable** for write functions (e.g., `transfer` may return `false` in simulation but succeed on-chain)
- `eth_getTransactionCount` is **NOT supported**, so `cast call` fails; use `curl` with TronGrid native API instead

### Tron Address Encoding

- Tron addresses are 21 bytes: `0x41` prefix + 20-byte EVM address
- **On-chain (Solidity `address` type): always use 20-byte EVM format** (strip `0x41` prefix)
- **In ABI-encoded parameters** for `triggerconstantcontract`: use 20-byte EVM format padded to 32 bytes (no `0x41`)

### Tron Transaction Fetching

Use TronGrid native API instead of EVM RPC:

```bash
# Full transaction data + internal transactions
curl -s -X POST https://api.trongrid.io/wallet/gettransactioninfobyid \
  -H "Content-Type: application/json" \
  -d '{"value": "<TX_HASH>"}' | jq .

# Raw transaction (calldata, signature)
curl -s -X POST https://api.trongrid.io/wallet/gettransactionbyid \
  -H "Content-Type: application/json" \
  -d '{"value": "<TX_HASH>"}' | jq .
```

### Tron `gettransactioninfobyid` Fields

- `contractResult[0]`: **4-byte hex revert selector** (use `cast 4byte` to decode)
- `resMessage`: hex-encoded revert message string (decode with `xxd -r -p`)
- `internal_transactions[].rejected`: **ALL internal txs show `rejected: true` when outer tx reverts** — this does NOT mean each individual call failed; it means all effects were rolled back
- `internal_transactions[].note`: `63616c6c` = "call", `64656c656761746563616c6c` = "delegatecall"
- `receipt.energy_usage_total`: total energy consumed (including sub-calls)
- `receipt.energy_penalty_total`: extra energy charged for calling certain contracts

### Tron Address Conversion

**Preferred — use `troncast` (see `.agents/rules/202-tron-scripts.md` for Tron script conventions):**

```bash
# base58 → EVM hex
bun troncast address to-hex TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t
# Output: 0xa614f803b6fd780986a42c78ec9c7f77e6ded13c

# EVM hex → base58
bun troncast address to-base58 0xa614f803b6fd780986a42c78ec9c7f77e6ded13c
# Output: TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t

# Multiple addresses (comma-separated) supported in both directions
bun troncast address to-hex "TAddr1,TAddr2"
```

### Tron Contract Code

Use `troncast` instead of `cast code` (which does not support Tron). Accepts both base58 and EVM hex addresses:

```bash
# Get contract bytecode (analog of `cast code` for Tron)
bun troncast code TLPh66vQ2QMb64rG3WEBV5qnAhefh2kcdw
# Returns 0x<bytecode> or "0x" if address is not a contract

# Hex address is auto-converted to base58 internally
bun troncast code 0x7252afce04856eaac8f8a8beb5ae29621a1ca49b

# Testnet
bun troncast code <address> --env testnet
```


## Key Files & Tools

### Files

- `deployments/<network>.json` - Contract addresses
- `script/deploy/facets/Deploy<FacetName>.s.sol` - Find config filename
- `config/<configFileName>.json` - Facet external contracts
- `config/whitelist.json` - DEX/router names (DEXS[] and PERIPHERY[] sections)
- `config/networks.json` - Network metadata (wrappedNative, explorerUrl, etc.)
- `src/Facets/<FacetName>.sol` - Facet code
- `src/Libraries/LibSwap.sol` - SwapData structure
- `src/Facets/CalldataVerificationFacet.sol` - Decoding logic
- `out/<ContractName>.sol/<ContractName>.json` - Compiled contract ABIs with methodIdentifiers

### Tools

- `cast 4byte <SELECTOR>` - Get function signature from selector (4byte.directory)
- `cast calldata-decode "<SIGNATURE>" <CALLDATA>` - Decode calldata using function signature
- `cast sig "<FUNCTION_NAME>"` - Get selector from function name
- `cast tx <TX_HASH> --rpc-url <RPC>` - Get transaction details
- `cast receipt <TX_HASH> --rpc-url <RPC>` - Get transaction receipt (contains logs)
- `web_search` - Search for contract information on block explorers

## Analysis Workflow

### 1. Fetch Transaction Data

**Preferred:**

```bash
bash -lc 'source script/helperFunctions.sh && source script/playgroundHelpers.sh && analyzeFailingTx "<NETWORK>" "<TX_HASH>"'
```

**Fallback:** Ask user for premium RPC URL, use for:

- `eth_getTransactionReceipt` - Contains logs (events that ACTUALLY happened)
- `debug_traceTransaction` (callTracer) - Contains execution trace (what ACTUALLY happened)
- Optional: `cast run`

**Extract:**

- Receipt: status, gas, **logs (EVENTS)**, `to`/`from`, `value`
- Trace: Complete execution flow, nested calls, value flow, ALL revert points

### 2. Transaction Identification

- Extract: hash, network, `to` address, `from`, calldata, `msg.value` (from receipt)
- Check: Does `to` match LiFiDiamond? If indirect, trace to find LiFiDiamond call
- Enrich: Map addresses from `deployments/<network>.json`

### 3. Root Transaction Analysis (If NOT Direct LiFiDiamond Call)

When root transaction calls a contract other than LiFiDiamond:

1. **Get block explorer URL:**

   - Read `config/networks.json` → extract `explorerUrl` field

2. **Research contract:**

   - Construct URL: `<explorerUrl>/address/<CONTRACT_ADDRESS>`
   - Use `web_search`: `"<explorerUrl>/address/<CONTRACT_ADDRESS> contract verified"`
   - Navigate to "Contract" tab → "Write Contract" sub-tab
   - Extract: contract name, function signatures, selectors, parameters

3. **Verify function selector (CRITICAL):**

   - Extract selector from trace (first 4 bytes of calldata)
   - Cross-check with actual function name from trace (preferred)
   - Verify using `out/<ContractName>.sol/<ContractName>.json` methodIdentifiers
   - Use `cast sig "<FUNCTION_SIGNATURE>"` to get expected selector
   - **If `cast 4byte` returns different function, use trace function name!**

4. **Decode calldata:**

   - Use verified function signature (from trace preferred, then block explorer, then `cast 4byte` fallback)
   - Decode: `cast calldata-decode "<FUNCTION_SIGNATURE>" <CALLDATA>`

5. **Extract nested calldata:**
   - If router passes data to LiFiDiamond, extract from `bytes` parameter
   - Decode nested LiFiDiamond calldata separately

### 4. Facet & Protocol Identification

1. **Extract function selector from trace:**

   - Get selector from actual call in trace (first 4 bytes of calldata)
   - Example: Trace shows `0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE::swapTokensMultipleV3ERC20ToERC20(...)`

2. **Verify selector matches trace:**

   - Cross-check with actual function name from trace (preferred)
   - Verify using `out/<ContractName>.sol/<ContractName>.json` methodIdentifiers
   - Use `cast sig "<FUNCTION_SIGNATURE>"` to get expected selector
   - **Never assume** - if `cast 4byte` returns different function, use trace function name!

3. **Map selector to facet:**

   - Use `out/<ContractName>.sol/<ContractName>.json` methodIdentifiers
   - Verify function signature matches trace

4. **Load facet code:**
   - Load: `src/Facets/<FacetName>.sol`
   - Find config: Check `script/deploy/facets/Deploy<FacetName>.s.sol` for config filename
   - Load config: `config/<configFileName>.json`

**Common Error:**

- ❌ **WRONG**: Seeing selector `0xab138240` and assuming it's `swapAndStartBridgeTokensViaStargate`
- ✅ **CORRECT**: Check `cast 4byte 0xab138240` → returns `bridge(address,address,...)` → verify with trace → trace shows `swapTokensMultipleV3ERC20ToERC20` → use actual function from trace

### 5. Calldata Decoding

#### For Root Transaction (Non-LiFiDiamond)

1. Identify function selector: `cast 4byte <SELECTOR>`
2. Decode calldata: `cast calldata-decode "<FUNCTION_SIGNATURE>" <CALLDATA>`
3. Extract nested calldata if router passes data to LiFiDiamond

**Fallback for unverified contracts**: if the target is an unverified contract (no matching artifact in `out/`, `cast 4byte` returns nothing, and no signature can be resolved from the trace), run [`/analyze-unverified-contract <ADDRESS> <NETWORK>`](analyze-unverified-contract.md) to disassemble the bytecode, extract selectors, and enrich them against 4byte.directory. Use the resulting selectors file to identify the called function and proceed with `cast calldata-decode`.

#### For LiFiDiamond Calls

Use `CalldataVerificationFacet` patterns:

**BridgeData:**

```solidity
bridgeData = abi.decode(data[4:], (ILiFi.BridgeData));
```

**SwapData (if hasSourceSwaps):**

```solidity
(, swapData) = abi.decode(data[4:], (ILiFi.BridgeData, LibSwap.SwapData[]));
```

**Key functions:**

- `extractBridgeData(bytes calldata data)` → `ILiFi.BridgeData`
- `extractSwapData(bytes calldata data)` → `LibSwap.SwapData[]`
- `extractMainParameters(bytes calldata data)` → Quick overview

### 6. Parameter Extraction

- **BridgeData**: transactionId, bridge, integrator, sendingAssetId, receiver, destinationChainId, minAmount, hasSourceSwaps, hasDestinationCall
- **SwapData** (if applicable): For each swap - callTo (enrich DEX name), approveTo, sendingAssetId, receivingAssetId, fromAmount, callData (decode selector), requiresDeposit
- **FacetData**: Extract facet-specific params, check native fee requirements

### 7. Address Enrichment

**For every address:**

1. Check `config/whitelist.json`:
   - **DEXS section**: `DEXS[]` → `contracts[<network>]` → match address (case-insensitive) → use `name`
   - **PERIPHERY section**: `PERIPHERY[<network>]` → match address → use `name`
2. Fallback: `deployments/<network>.json`
3. Tokens: MAY call ERC20 `name()` via premium RPC (read-only, non-fatal)

**Never use generic terms** ("DexRouter", "Router", "DEX") when specific name available.

### 8. Execution Trace Analysis

**Analyze ONLY what the trace shows - never assume based on code!**

- **Entry point**: Function called (from trace), input params (from trace)
- **Call stack**: Trace each nested call - caller, target, function (from trace), value, params, success/fail
- **Value flow**: Track native value through execution (from trace)
- **Token flow**: Track deposits, approvals, transfers, balances (from trace)
- **Events**: Check receipt logs to see what events were ACTUALLY emitted
- **Failure points**: Identify ALL reverts (from trace), extract error messages

**Rules:**

- ✅ If trace shows function X → state "Function X was called"
- ❌ If code shows function Y should emit event Z → DON'T claim event Z was emitted unless it's in the logs
- ✅ If logs show event A → state "Event A was emitted"
- ✅ Use code to UNDERSTAND what should happen, but trace/logs to report what DID happen

### 9. Root Cause Analysis

- What was expected vs. provided
- Why it failed (specific validation/requirement that wasn't met)
- What's needed to succeed

## Output Format

```markdown
# Transaction Analysis: [TX_HASH]

## Transaction Intent

[One-sentence description]

## Root Transaction Details

- **Network:** [name]
- **From:** [address]
- **To:** [contract name] ([address])
- **Function:** [name] ([selector])
- **Value:** [amount] [symbol] - **CRITICAL: From receipt**
- **Status:** [Success/Fail]

## Parameters Decoded

### Root Transaction Parameters (if not direct LiFiDiamond call)

**Contract:** [Contract name from block explorer] ([address])
**Function:** [function name] ([selector])
**Parameters:**

- [Parameter 1]: [value]
- [data (bytes)]: Contains LiFiDiamond calldata (see below)

### BridgeData

[transactionId, bridge, integrator, sendingAssetId, receiver, destinationChainId, minAmount, hasSourceSwaps, hasDestinationCall]

### SwapData (if applicable)

**Swap 1:**

- DEX: [name from whitelist]
- From: [token] ([amount])
- To: [token]
- Router: [contract name] ([address])
- Function: [name] ([selector])

### Facet-Specific Data

[Native Fee Required: [amount] - **CRITICAL**, other params]

## Execution Flow

1. **[Step]:** [Description]
   - Caller: [name]
   - Target: [name]
   - Action: [what happened]
   - Result: [success/fail]

[N] **[FAILURE POINT]:** [Description]

- Error: [message]
- Reason: [why failed]

## Root Cause Analysis

**Primary Issue:** [One-sentence summary]

**Detailed Explanation:**

1. [What was expected]
2. [What was provided]
3. [Why it failed]
4. [What's needed to succeed]

## Contract Addresses Reference

[LiFiDiamond, FacetName, External Contracts, Tokens]

## Summary for Stakeholders

**Transaction Purpose:** [What user was trying to do]
**Failure Reason:** [Clear, non-technical explanation]
**Required Fix:** [What needs to change]
**Impact:** [Who/what is affected]
```

## Quality Checks

Before finalizing:

- [ ] Premium RPC used (via `analyzeFailingTx` or user-provided)
- [ ] LiFiDiamond involvement confirmed
- [ ] Root tx value verified from receipt
- [ ] **All events verified from receipt logs** (never assume based on code)
- [ ] **All function calls verified from trace** (never assume based on code)
- [ ] Root transaction calldata decoded (if not direct LiFiDiamond call)
- [ ] Block explorer URL obtained and contract researched (if needed)
- [ ] Function selector verified against trace data (never assume!)
- [ ] Selector cross-checked with methodIdentifiers
- [ ] All addresses enriched (whitelist.json → deployments)
- [ ] Correct config file identified from deploy script
- [ ] All DEX names from whitelist.json (no generic terms)
- [ ] All parameters decoded and displayed
- [ ] Execution flow traced completely from trace data
- [ ] ALL failure points identified
- [ ] Root cause clearly explained
- [ ] Summary clear for non-technical readers

## Command Execution Flow

When user invokes `/analyze-tx <network> <tx_hash>`:

1. **Parse arguments**: Extract network and tx_hash from command
2. **Validate inputs**: Ensure network is valid, tx_hash is hex format
3. **Fetch transaction data**: Use premium RPC via `analyzeFailingTx` or prompt for RPC URL
4. **Follow analysis workflow**: Execute all steps from "Analysis Workflow" section
5. **Generate output**: Format results according to "Output Format" section
6. **Quality check**: Verify all items in "Quality Checks" are complete
