Powered by TwinLabs | Developed by TwinDevs
Un token ERC-20 estable y seguro con características empresariales de control de acceso, gestión de blacklist y funcionalidades de seguridad avanzadas. Desarrollado con las mejores prácticas de seguridad en blockchain.
- Características Principales
- Especificaciones del Token
- Sistema de Roles
- Instalación
- Despliegue
- Uso
- API Reference
- Testing
- Seguridad
- Contacto
- Blacklist Integrada: Bloquea direcciones específicas según regulaciones
- Sistema de Pausas de Emergencia: Congelación inmediata de movimientos
- Control de Acceso Basado en Roles (RBAC): Granularidad total sobre permisos
- Librerías Auditadas: OpenZeppelin v5.0 probadas y auditadas por la comunidad
- Validación Robusta: Checks exhaustivos en operaciones críticas
- Nombre: Twin Stable
- Símbolo: TWIN
- Decimales: 18
- Supply Inicial: 0
- Supply Máximo: Ilimitado (Minteable)
- Burnable: Cualquiera puede quemar sus tokens
- Pausable: Congelación de emergencia
- Blacklistable: Cumplimiento regulatorio AML/KYC
| Rol | Permisos | Descripción |
|---|---|---|
| DEFAULT_ADMIN_ROLE | Control total | Owner del contrato, gestiona todos los roles |
| MINTER_ROLE | Mintear tokens | Solo estos pueden crear nuevos tokens |
| PAUSER_ROLE | Pausar/Reanudar | Pueden congelar/descongelar transferencias |
| BLACKLIST_ADMIN_ROLE | Gestionar blacklist | Administran la lista negra de direcciones |
✅ Overflow/Underflow protection (Solidity 0.8+) ✅ Reentrancy safe (No llamadas externas en transferencias) ✅ Checks-Effects-Interactions pattern ✅ Validación de direcciones (no address(0)) ✅ Event logging exhaustivo ✅ Rate limiting en funciones críticas
- Node.js v16+
- npm o yarn
- Cuenta con fondos en testnet (para despliegue)
# Clonar repositorio
git clone https://github.com/Daimon-Security/Twinstable.git
cd Twinstable
# Instalar dependencias
npm install
# O con yarn
yarn install# Copiar plantilla
cp .env.example .env
# Editar .env con tus valores
nano .envVariables requeridas:
# Network RPC URLs
SEPOLIA_RPC_URL=https://sepolia.infura.io/v3/YOUR_KEY
MAINNET_RPC_URL=https://mainnet.infura.io/v3/YOUR_KEY
# Private Key (NUNCA COMPARTAS!)
PRIVATE_KEY=your_private_key_here
# API Keys para verificación
ETHERSCAN_API_KEY=your_etherscan_key| Red | Blockchain | Estado | Chain ID |
|---|---|---|---|
| Ethereum Mainnet | Mainnet | ✅ Soportado | 1 |
| Sepolia Testnet | Ethereum | ✅ Recomendado | 11155111 |
| Polygon | L2 Scaling | ✅ Soportado | 137 |
| Arbitrum One | L2 Scaling | ✅ Soportado | 42161 |
| Optimism | L2 Scaling | ✅ Soportado | 10 |
| Base | L2 Scaling | ✅ Soportado | 8453 |
npm run compile
# Output: artifacts/contracts/TwinStable.sol/TwinStable.json# Tests completos
npm test
# Con reporte de cobertura
npm run test:coverage
# Con reporte de gas
npm run gas-report
# Tests en red local
npm run node
# (en otra terminal)
npm run deploy:localhost✅ Minting autorizado/no autorizado
✅ Burning de tokens propios
✅ Blacklist functionality
✅ Pausable operations
✅ Role management
✅ Transferencias estándar
✅ Edge cases y validaciones
✅ Eventos correctos
# Terminal 1: Inicia nodo local
npm run node
# Terminal 2: Despliega contrato
npm run deploy:localhostnpm run deploy:sepolia
# Output esperado:
# 🚀 Iniciando despliegue de TwinStable...
# 📍 Desplegador: 0x...
# 💰 Balance: X.XX ETH
# ✅ TwinStable desplegado en: 0x...# ⚠️ CUIDADO: Verifica todo antes de desplegar en mainnet
npm run deploy:mainnet# Después del despliegue
npx hardhat verify --network sepolia CONTRACT_ADDRESS
# Con constructor arguments (si aplica)
npx hardhat verify --network sepolia CONTRACT_ADDRESS "arg1" "arg2"const hre = require("hardhat");
async function mintTokens() {
const TwinStable = await hre.ethers.getContractFactory("TwinStable");
const token = TwinStable.attach("0x...CONTRACT_ADDRESS");
// Mintear 1000 TWIN (1000 * 10^18 unidades atómicas)
const tx = await token.mint(
"0x...RECIPIENT_ADDRESS",
hre.ethers.parseEther("1000")
);
console.log("Mint tx:", tx.hash);
await tx.wait();
console.log("✅ 1000 TWIN minteados!");
}
mintTokens().catch(console.error);// Desde una billetera con tokens
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
// Usar en ethers.js o truffle
const token = new ethers.Contract(tokenAddress, ABI, signer);
// Quemar 100 TWIN propios
await token.burn(ethers.parseEther("100"));// Añadir dirección a blacklist
await token.addToBlacklist("0x...ADDRESS_TO_BLOCK");
// Verificar si está bloqueada
const isBlocked = await token.isBlacklisted("0x...ADDRESS");
console.log("¿Bloqueada?", isBlocked);
// Remover de blacklist
await token.removeFromBlacklist("0x...ADDRESS");// Asignar rol de minteador
const MINTER_ROLE = await token.MINTER_ROLE();
await token.grantMinterRole("0x...NEW_MINTER");
// Verificar si tiene rol
const hasMinterRole = await token.hasRole(MINTER_ROLE, "0x...ADDRESS");
// Revocar rol
await token.revokeMinterRole("0x...OLD_MINTER");// Pausar todas las transferencias
await token.pause();
console.log("🛑 Token pausado");
// Reanudar
await token.unpause();
console.log("▶️ Token reanudado");function mint(address to, uint256 amount)
public onlyRole(MINTER_ROLE)Mintea nuevos tokens y los asigna a una dirección.
- Requisitos: Llamador debe tener MINTER_ROLE
- Parámetros:
to(destinatario),amount(cantidad en wei) - Emite:
Transferevent
function burn(uint256 amount) publicQuema tokens propios, eliminándolos de circulación.
function burnFrom(address account, uint256 amount) publicQuema tokens de otra dirección (requiere aprobación).
function pause() public onlyRole(PAUSER_ROLE)
function unpause() public onlyRole(PAUSER_ROLE)Pausa/Reanuda todas las transferencias de tokens.
function addToBlacklist(address account)
public onlyRole(BLACKLIST_ADMIN_ROLE)Añade una dirección a la blacklist.
function removeFromBlacklist(address account)
public onlyRole(BLACKLIST_ADMIN_ROLE)Remueve una dirección de la blacklist.
function isBlacklisted(address account)
public view returns (bool)Verifica si una dirección está en la blacklist.
function grantMinterRole(address account)
public onlyRole(DEFAULT_ADMIN_ROLE)
function revokeMinterRole(address account)
public onlyRole(DEFAULT_ADMIN_ROLE)
function grantPauserRole(address account)
public onlyRole(DEFAULT_ADMIN_ROLE)
function revokePauserRole(address account)
public onlyRole(DEFAULT_ADMIN_ROLE)
function grantBlacklistAdminRole(address account)
public onlyRole(DEFAULT_ADMIN_ROLE)
function revokeBlacklistAdminRole(address account)
public onlyRole(DEFAULT_ADMIN_ROLE)Asigna y revoca roles administrativos.
function transfer(address to, uint256 amount)
public returns (bool)
function transferFrom(address from, address to, uint256 amount)
public returns (bool)
function approve(address spender, uint256 amount)
public returns (bool)
function balanceOf(address account)
public view returns (uint256)
function allowance(address owner, address spender)
public view returns (uint256)
function totalSupply()
public view returns (uint256)
function decimals()
public pure returns (uint8)// Blacklist
event AddedToBlacklist(address indexed account);
event RemovedFromBlacklist(address indexed account);
// ERC20 (heredados)
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
// Pausable (heredados)
event Paused(address indexed account);
event Unpaused(address indexed account);
// AccessControl (heredados)
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);✅ NatSpec Completo: Todas las funciones documentadas ✅ Auditoría OpenZeppelin: Librerías probadas ✅ RBAC Granular: Control fino de permisos ✅ Validación Exhaustiva: Checks en operaciones críticas ✅ Event Logging: Todos los cambios auditables ✅ Emergency Pause: Congelación inmediata
Consulta docs/SECURITY.md para información completa sobre:
- Verificaciones de seguridad
- Protecciones contra ataques comunes
- Limitaciones conocidas
- Checklist pre-deployment
- Proceso de reporte responsable
NO publiques vulnerabilidades en issues públicos.
Por favor envía un email a: security@twinlabs.io
Incluir:
- Descripción detallada
- Proof of Concept (PoC)
- Impacto potencial
Estimaciones de gas para operaciones comunes:
transfer() ~52,000 gas (depende de la red)
mint() ~72,000 gas
burn() ~52,000 gas
addToBlacklist() ~48,000 gas
pause() ~28,000 gas
Para reporte detallado:
npm run gas-report¡Las contribuciones son bienvenidas! Por favor consulta CONTRIBUTING.md para:
- Estándares de código
- Proceso de Pull Request
- Requisitos de tests
- Guías de seguridad
Pasos rápidos:
# 1. Fork el repositorio
# 2. Crea rama de feature
git checkout -b feature/mi-feature
# 3. Commit cambios
git commit -m "feat: descripción"
# 4. Push a rama
git push origin feature/mi-feature
# 5. Abre Pull Request- Smart Contract Source - Código fuente con NatSpec
- Security Documentation - Análisis de seguridad
- Contributing Guidelines - Guía de contribución
- OpenZeppelin Docs - Referencia de librerías
- Solidity Docs - Lenguaje Solidity
- ERC-20 Standard
- Ethereum Development Guide
- Hardhat Documentation
- Web3.js Documentation
- Ethers.js Documentation
Twinstable/
├── contracts/
│ └── TwinStable.sol # Smart contract principal
├── scripts/
│ └── deploy.js # Script de despliegue
├── test/
│ └── TwinStable.test.js # Tests unitarios
├── docs/
│ └── SECURITY.md # Documentación de seguridad
├── .env.example # Variables de entorno (plantilla)
├── hardhat.config.js # Configuración Hardhat
├── package.json # Dependencias
├── README.md # Este archivo
├── CONTRIBUTING.md # Guía de contribución
└── LICENSE # Licencia MIT
const hre = require("hardhat");
async function main() {
// Desplegar contrato
const TwinStable = await hre.ethers.getContractFactory("TwinStable");
const token = await TwinStable.deploy();
await token.waitForDeployment();
const contractAddress = await token.getAddress();
console.log("✅ Token desplegado en:", contractAddress);
// Obtener información
const name = await token.name();
const symbol = await token.symbol();
const totalSupply = await token.totalSupply();
console.log(`Nombre: ${name}`);
console.log(`Símbolo: ${symbol}`);
console.log(`Supply Total: ${totalSupply}`);
// Mintear 1000 TWIN
const [owner] = await hre.ethers.getSigners();
const tx = await token.mint(owner.address, hre.ethers.parseEther("1000"));
await tx.wait();
console.log("✅ 1000 TWIN minteados!");
// Verificar balance
const balance = await token.balanceOf(owner.address);
console.log(`Balance: ${hre.ethers.formatEther(balance)} TWIN`);
}
main().catch(console.error);- Discord: TwinLabs Community
- Twitter: @TwinLabsIO
- Email: dev@twinlabs.io
- Website: https://twinlabs.io
- Organización GitHub: Daimon-Security
Este contrato se proporciona "tal cual" sin ninguna garantía. Aunque se han tomado todas las precauciones de seguridad, los usuarios asumen todo el riesgo.
Para aplicaciones críticas o en producción, se recomienda encarecidamente:
- ✅ Auditoría profesional independiente
- ✅ Testnet deployment extensivo
- ✅ Monitoring continuo
- ✅ Plan de respuesta a incidentes
Este proyecto está licenciado bajo la Licencia MIT. Ver archivo LICENSE para detalles completos.
MIT License
Copyright (c) 2024 TwinLabs - Powered by TwinDevs
Permission is hereby granted, free of charge...
Este proyecto es mantenido por TwinDevs - Powered by TwinLabs, dedicados a educación en blockchain, desarrollo de smart contracts seguros y mejores prácticas en Web3.
- Smart Contract Development
- Security Best Practices
- Blockchain Architecture
- Token Economics
Si encontraste útil este proyecto, ¡por favor deja una estrella! ⭐
Hecho con ❤️ por TwinDevs - Powered by TwinLabs