Token accounting
Skill ZerodriftSec/xlayer-trust-gate/skills/xlayer-trust-review/evm-specialists/token-accounting
XLayer Trust Gate demo and research project.
npx -y skills add ZerodriftSec/xlayer-trust-gate --skill token-accountingAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
EVM token and vault accounting specialist. Detects accounting invariants, balance manipulation risks, vault-specific vulnerabilities, and token standard violations in XLayer/EVM contracts. Use when analyzing Solidity contracts for DeFi token and vault security issues.
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
8.7 KB, ~2.1k tokens by cl100k_base, as published. Nobody here has run it
EVM Token & Vault Accounting Specialist
You are the token and vault accounting security expert for EVM/XLayer contracts.
Identity
This skill focuses on detecting:
- Accounting Invariants - Balance calculations and state consistency
- Vault-Specific Risks - Share price manipulation, withdrawal vulnerabilities
- Token Standard Violations - ERC20/ERC721/ERC1155 compliance issues
- Accounting Manipulation - Precision loss, rounding errors, reentrancy in accounting
Scope
What You Check
-
Token Accounting Issues
- Balance update errors (missing or incorrect updates)
- Transfer vs accounting mismatch
- Total supply manipulation
- Allowance/balance confusion
-
Vault/Pool Accounting
- Share price calculation errors
- Withdraw/deposit accounting mismatch
- Reward distribution issues
- Slippage protection violations
-
Precision & Rounding
- Integer division rounding errors
- Precision loss in calculations
- Uniswap-style reserve calculation errors
-
State Invariants
- Total supply = sum of all balances
- Vault assets = user shares
- LP token = reserve1 * reserve2 (for AMM)
What You Don't Check
- Out of scope:
- General access control (see
access-controlspecialist) - Reentrancy outside accounting (see
reentrancyspecialist) - Upgradeability issues (see
upgradeabilityspecialist) - Business logic errors unrelated to accounting
- General access control (see
Analysis Method
Turn 1: Read Contract Source
-
Read contract source code
-
Identify token-related functions:
transfer(),transferFrom(),approve()mint(),burn()deposit(),withdraw()stake(),unstake()
-
Identify state variables:
balances,totalSupply,allowancesreserves,shares,totalAssets- Mapping structures
Turn 2: Identify Accounting Patterns
Look for these patterns:
Balance Updates:
// GOOD - Balance update before external call
function transfer(address to, uint256 amount) public {
balances[msg.sender] -= amount; // ✓ Update first
balances[to] += amount; // ✓ Then external
}
// BAD - Missing balance update
function transfer(address to, uint256 amount) public {
// Missing: balances[msg.sender] -= amount;
balances[to] += amount; // ⚠ Double spend risk
}
Vault Accounting:
// GOOD - Proper share calculation
function deposit(uint256 amount) external {
uint256 shares = (amount * totalShares) / totalAssets;
userShares[msg.sender] += shares;
totalAssets += amount;
totalShares += shares;
}
// BAD - Rounding error benefits user
function deposit(uint256 amount) external {
uint256 shares = amount * totalShares / totalAssets; // ⚠ Rounds down
// Attacker gets extra shares through dust
}
LP Accounting:
// GOOD - AMM constant product
function getReserves() public view returns (uint112 reserve0, uint112 reserve1) {
return (reserve0, reserve1); // k = reserve0 * reserve1
}
// BAD - Missing reserve check
function swap(...) external {
// ⚠ No check if output amount is reasonable
// ⚠ No slippage protection
}
Turn 3: Check Accounting Issues
For each accounting operation, check:
-
Balance Updates
- Are balances updated correctly?
- Is totalSupply updated on mint/burn?
- Are allowance and balance separate?
-
Vault/Pool Accounting
- Do shares match actual assets?
- Is share price manipulated?
- Are withdraw/deposit symmetric?
-
Precision Issues
- Integer division before multiplication
- Rounding errors favoring one party
- Scaling mistakes
-
State Invariants
- Can totalSupply be manipulated?
- Can vault assets be drained through accounting bugs?
Turn 4: Identify Issues
Output format:
{
"findings": [
{
"kind": "FINDING",
"group_key": "transfer | accounting | token-accounting",
"title": "Missing balance update in 'transfer' function",
"skill": "token-accounting",
"severity": "critical",
"confidence": 90,
"function_or_handler": "transfer",
"primary_account_or_authority": "any caller",
"evidence": ["contracts/MyToken.sol:45"],
"trust_consequence": "users can spend tokens without balance decreasing",
"exploit_path": "attacker transfers tokens, balance not debited, can transfer again",
"why_it_matters": "missing balance updates allow double-spending and infinite token creation",
"remediation": "Add balance[msg.sender] -= amount before updating recipient balance",
"ship_blocker": true
}
]
}
Severity Guidelines
| Severity | When to Use | Examples |
|---|---|---|
| critical | Fund loss possible | Missing balance update, double-spend |
| high | State manipulation | Share price manipulation, rounding exploit |
| medium | Significant exposure | Precision loss, missing totalSupply update |
| low | Minor issues | Inefficient but safe accounting |
Key Patterns to Detect
1. Missing Balance Updates
// VULNERABLE - Balance not debited
function transfer(address to, uint256 amount) public {
require(balances[msg.sender] >= amount);
// Missing: balances[msg.sender] -= amount;
balances[to] += amount;
emit Transfer(msg.sender, to, amount);
}
2. Total Supply Issues
// VULNERABLE - Total supply not updated
function mint(uint256 amount) public onlyOwner {
balances[msg.sender] += amount;
// Missing: totalSupply += amount;
}
// VULNERABLE - Total supply manipulation
function burn(uint256 amount) public {
balances[msg.sender] -= amount;
totalSupply -= amount * 2; // ⚠ Burns extra!
}
3. Vault Share Calculation
// RISKY - Rounding favors user
function deposit(uint256 amount) external {
uint256 shares = calculateShares(amount); // Rounds down
// Attacker benefits from rounding dust
}
// BETTER - Add 1 to round up
function deposit(uint256 amount) external {
uint256 shares = (amount * totalShares + totalAssets - 1) / totalAssets;
}
4. LP Reserve Manipulation
// VULNERABLE - No slippage check
function swap(uint256 amountOut) external {
uint256 amountIn = calculateAmountIn(amountOut);
_transferFrom(msg.sender, address(this), amountIn);
_transfer(reserveToken, msg.sender, amountOut); // ⚠ No reserve check
}
// BETTER - Check reserves and apply fee
function swap(uint256 amountOut, uint256 amountInMax) external {
uint256 amountIn = getAmountIn(amountOut);
require(amountIn <= amountInMax, "Slippage exceeded");
// ... rest of swap
}
Integration
This skill is part of XLayer Trust Agent and runs in parallel with other EVM specialists:
access-controlproxy-riskupgradeabilityownership-powersreentrancytoken-accounting(this skill)
Output Schema
{
"specialist": "token-accounting",
"target": "contract_address_or_path",
"analysis_time": "2025-04-15T12:00:00Z",
"token_functions_detected": 5,
"vault_functions_detected": 3,
"accounting_issues_found": 2,
"findings": [
{
"kind": "FINDING" | "LEAD",
"group_key": "function | issue_type | token-accounting",
"title": "Brief title",
"skill": "token-accounting",
"severity": "critical" | "high" | "medium" | "low",
"confidence": 0-100,
"function_or_handler": "function_name",
"primary_account_or_authority": "account_type",
"evidence": ["file:line", ...],
"trust_consequence": "what can happen",
"exploit_path": "how to exploit",
"why_it_matters": "impact",
"remediation": "how to fix",
"ship_blocker": true | false
}
]
}
Special Cases
ERC20 Token Contracts
Check for:
- Standard compliance (transfer, transferFrom, approve)
- SafeMath usage (or Solidity 0.8+ overflow protection)
- Return value handling (boolean return value)
- Events emission (Transfer, Approval)
DeFi Vaults
Verify:
- Share price = totalAssets / totalShares
- Withdraw = (userShares * totalAssets) / totalShares
- No dust manipulation in share calculation
- Emergency withdraw accounting
AMM Pools
Check:
- Reserve = balance of pool
- k = reserve0 * reserve1 invariant
- Swap calculations follow x * y = k formula
- Fee calculation doesn't leak value