This is a lower bound: only assets with reliable historical USD prices are counted, so the actual loss may be higher.
0x81e9918e248d14d78ff7b697355fd9f456c6d7881486ed14fdfb69db166311540x420725a69e79eeffb000f98ccd78a52369b6c5d4Ethereum0xe38b72d6595fd3885d1d2f770aa23e94757f91a1EthereumOn Ethereum mainnet block 14139082, an unprivileged attacker used a single contract-creation transaction to exploit a bug in TecraCoin's TcrToken contract. The exploit destroyed the TCR balance of a TCR/USDT liquidity pool and swapped that exposure into USDT via Uniswap, delivering 639,222.253258 USDT to the attacker's externally owned account (EOA).
The root cause is a mis-indexed allowance check in TcrToken.burnFrom. Instead of checking the victim's allowance to the spender, the implementation checks and updates _allowances[msg.sender][from]. This allows any caller that self-approves a victim address to burn tokens from that victim without the victim's consent. The attacker packaged this bug into a constructor that approves and then calls the vulnerable burn path against the TCR/USDT pool, followed by swaps to drain USDT.
TecraCoin's TcrToken contract at 0xe38b72d6595fd3885d1d2f770aa23e94757f91a1 is an ERC20-style token with standard _balances and _allowances mappings, owner and pauser roles, blacklist functionality, and burn/burnFrom helpers implemented in Contract.sol. The token uses 8 decimals, a fixed maxSupply, and exposes the typical transfer, transferFrom, and approve interfaces, plus additional bulk transfer and upgrade hooks.
The principal victim of this incident is a TCR/USDT liquidity pool at . This pool holds reserves of TCR and USDT and is serviced by the canonical UniswapV2 router at . The exploit contract uses the router to route swaps through this pool, converting the destroyed TCR exposure into USDT and sending the proceeds to the attacker EOA.
0x420725a69e79eeffb000f98ccd78a52369b6c5d40x7a250d5630b4cf539739df2c5dacb4c659f2488dIn a correct ERC20 design, a burnFrom(from, amount) helper uses the allowance mapping as _allowances[from][msg.sender]. The spender (caller) can only burn tokens from from that from has explicitly allowed. This enforces the invariant that destructive operations on a holder's balance are gated by that holder's approvals.
The vulnerability is an authorization bug in TcrToken.burnFrom(address from, uint256 amount). The function checks allowance by reading _allowances[msg.sender][from] and then calls _approve(msg.sender, from, ...) before burning from's balance. This reverses the indices in the allowance mapping.
As a result, any caller can:
approve(victim, amount) from their own address, which writes to _allowances[msg.sender][victim].burnFrom(victim, amount) (directly or via a contract).Because the function consults _allowances[msg.sender][victim], the call passes the allowance check and burns the victim's tokens even though the victim never consented. The exploit contract deploys with constructor logic that performs large self-approvals and then calls the vulnerable burn path against the TCR/USDT pool address, followed by swaps through UniswapV2Router02 to pull USDT out of the same pool.
This is an ACT (anyone-can-take) opportunity: any unprivileged EOA that can pay gas and deploy an equivalent exploit contract can reproduce the same sequence against the same vulnerable TcrToken deployment and a TCR-funded pool.
The TecraCoin TcrToken contract implements burn and burnFrom as follows (excerpt from the verified source):
function burn(uint256 amount) external {
require(_balances[msg.sender] >= amount, ERROR_BTL);
_burn(msg.sender, amount);
}
function burnFrom(address from, uint256 amount) external {
require(_allowances[msg.sender][from] >= amount, ERROR_ATL);
require(_balances[from] >= amount, ERROR_BTL);
_approve(msg.sender, from, _allowances[msg.sender][from] - amount);
_burn(from, amount);
}
The allowance mapping is declared as:
mapping(address => mapping(address => uint256)) private _allowances;
Everywhere else, allowance-related operations treat the mapping as _allowances[owner][spender]. However, in burnFrom, the check and subsequent _approve call both use _allowances[msg.sender][from], effectively treating msg.sender as the owner and from as the spender. This breaks the standard invariant:
For any holder
Hand spenderS, a destructive burn ofH's balance viaburnFrom(H, amount)must only succeed if_allowances[H][S] >= amountandHhas explicitly granted that allowance toS.
With the indices reversed, an attacker can:
approve(victim, amount) from their EOA, which sets _allowances[attacker][victim] = amount.msg.sender to call burnFrom(victim, amount), relying on the mis-indexed lookup to see a large allowance and then burn the victim’s balance.The ACT pre-state σ_B is Ethereum mainnet state just before inclusion of the exploit transaction 0x81e9918e248d14d78ff7b697355fd9f456c6d7881486ed14fdfb69db16631154 in block 14139082. The collected prestate balance diff shows the TCR/USDT pool’s TCR balance:
{
"token": "0xe38b72d6595fd3885d1d2f770aa23e94757f91a1",
"holder": "0x420725a69e79eeffb000f98ccd78a52369b6c5d4",
"before": "58027283904946",
"after": "10214462474",
"delta": "-58017069442472",
"contract_name": "TcrToken"
}
This shows that, over the course of the exploit transaction, the pool loses exactly 58,017,069,442,472 raw TCR units, matching the amount burned in the constructor path described below.
The seed transaction is a type‑2 contract-creation transaction from EOA 0xb19b7f59c08ea447f82b587c058ecbf5fde9c299 with hash:
0x81e9918e248d14d78ff7b697355fd9f456c6d7881486ed14fdfb69db16631154The receipt confirms deployment of contract 0x6653d9bcbc28fc5a2f5fb5650af8f2b2e1695a15 and significant interactions with WETH9, USDT, TcrToken, the TCR/USDT pool, and UniswapV2Router02. The trace (trace.cast.log) and decoded calldata show the constructor performing the following high-level steps:
0x7a250d5630b4cf539739df2c5dacb4c659f2488d) to spend unlimited USDT and TCR on behalf of the exploit contract.0x420725a69e79eeffb000f98ccd78a52369b6c5d4 for a very large TCR allowance using TcrToken’s approve.burnFrom-style function on TcrToken with from = 0x420725a69e79eeffb000f98ccd78a52369b6c5d4 and amount = 58017069442472 TCR units, relying on the mis-indexed _allowances[msg.sender][from] mapping to satisfy the allowance check based on the earlier self-approval.USDT Transfer logs in the exploit receipt show:
{
"address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
"data": "0x0000000000000000000000000000000000000000000000000000000006ba2816",
"topics": [
"Transfer(...)",
"0x0000000000000000000000000d4a11d5eeaac28ec3f61d100daf4d40471f1852",
"0x000000000000000000000000420725a69e79eeffb000f98ccd78a52369b6c5d4"
]
}
and a subsequent Transfer from the exploit contract to the attacker EOA, confirming that 639222253258 raw USDT units (639,222.253258 USDT with 6 decimals) are ultimately delivered to 0xb19b7f59c08ea447f82b587c058ecbf5fde9c299.
The native balance diff for the exploit transaction shows:
101095144261776538 wei.40000000000000000 wei.1230886000000000 wei.From the receipt, gasUsed = 0x12c826 and effectiveGasPrice = 0xb8e7b741f. Multiplying these yields an exact gas fee of 61095144261776538 wei (0.061095144261776538 ETH). The remaining ETH delta corresponds to the 0.04 ETH value sent in the contract-creation transaction.
The USDT inflow is completely determined by the USDT Transfer logs: the attacker EOA receives exactly 639222253258 USDT units (639,222.253258 USDT). Valuing ETH at approximately 3,000 USDT around the 2022‑02‑04 block timestamp, the gas fee corresponds to about 183.29 USDT. Treating the attacker’s pre‑tx USDT balance as 0 in the reference portfolio, the exploit yields:
value_before ≈ 0 USDT,value_after ≈ 639,222.253258 USDT,value_delta ≈ +639,038.97 USDT net of gas.This fulfills the ACT profit predicate: the adversary’s portfolio value in the USDT reference asset strictly increases after fees.
For this ACT opportunity to exist, the following conditions must hold:
burnFrom allowance check (_allowances[msg.sender][from]).burnFrom.burnFrom against the victim, and route swaps through a DEX router to extract USDT.All of these conditions are satisfied in the observed attack, and they remain reproducible for any adversary that can deploy an equivalent constructor against the same vulnerable TcrToken deployment.
The adversary-related cluster consists of:
0xb19b7f59c08ea447f82b587c058ecbf5fde9c299: sender of the exploit transaction and final recipient of 639,222.253258 USDT.0x6653d9bcbc28fc5a2f5fb5650af8f2b2e1695a15: deployed by the EOA; its constructor performs the TcrToken approvals, the abusive burnFrom call, and the swaps via UniswapV2Router02 that move USDT from the pool to the EOA.Victim-related contracts are:
0xe38b72d6595fd3885d1d2f770aa23e94757f91a1 (verified source available).0x420725a69e79eeffb000f98ccd78a52369b6c5d4 (pair contract used as the TCR holder and USDT source).Initial funding
0xfaf32d4a7eb2b17857d8d17b6aaa457cbc68b73ed84c8a4a3b23aa959380a2d5 (block 14138961),0x91946c20c99d3d3837244f23f0406f82ca3482ac95ae4e6c017984d1125994c7 (block 14139280),0xee1e24d077f96393d1439f6bf20e48a3122ec9c252de69eb69154f7cf4a14f7e (block 14139320).Exploit contract deployment
0x81e9918e248d14d78ff7b697355fd9f456c6d7881486ed14fdfb69db16631154, deploying the exploit contract 0x6653d9bcbc28fc5a2f5fb5650af8f2b2e1695a15.Constructor exploit and payout
approve to set large allowances from the contract to UniswapV2Router02 and to the TCR/USDT pool address.burnFrom path with from = 0x420725a69e79eeffb000f98ccd78a52369b6c5d4 and an amount of 58017069442472 TCR units, relying on the mis-indexed _allowances[msg.sender][from] check.Because all of these steps are driven by a single public transaction from an unprivileged EOA and rely only on publicly deployed contracts and on-chain state, the strategy is an ACT opportunity.
On-chain balances and logs quantify the impact as follows:
58,017,069,442,472 raw TCR units. With 8 decimals, this corresponds to 580,170,694.42472 TCR in economic exposure.639,222.253258 USDT, as shown by TetherToken Transfer logs routing USDT from the pool to the exploit contract and then to the attacker EOA.The direct victims are liquidity providers in the TCR/USDT pool, whose TCR and USDT positions are depleted. The TcrToken contract itself remains deployed with the same vulnerable logic, so the same pattern can be applied to any other TCR holder that is not otherwise protected.
Seed exploit transaction and trace
Ethereum mainnet tx 0x81e9918e248d14d78ff7b697355fd9f456c6d7881486ed14fdfb69db16631154 (block 14139082), including RPC metadata, receipt, trace, and prestate balance diff (local artifacts: tx.rpc.json, receipt.rpc.json, trace.cast.log, balance_diff.prestate.json).
TecraCoin TcrToken contract source
Verified source for TcrToken at 0xe38b72d6595fd3885d1d2f770aa23e94757f91a1, including the vulnerable burnFrom implementation (local artifact: Contract.sol).
Attacker EOA funding history
Address-level txlists for 0xb19b7f59c08ea447f82b587c058ecbf5fde9c299, showing internal ETH funding transactions and the single exploit transaction with nonce 0.
TCR/USDT pool behavior
Prestate ERC20 balance diff and USDT Transfer logs demonstrating the TCR burn and USDT outflow from 0x420725a69e79eeffb000f98ccd78a52369b6c5d4 to the exploit contract and then to the attacker EOA.
ACT opportunity characterization
Root cause and ACT opportunity definitions as encoded in the analysis artifacts, tying the mis-indexed burnFrom allowance check to an anyone-can-take, single-tx profit strategy.