🛡️ OpenZeppelin & Staking con Rewards

La librería estándar de seguridad + construye un protocolo de staking desde cero

Semanas 3-4: OpenZeppelin y Staking
OpenZeppelin v5Ownable / AccessControlReentrancyGuardStaking Rewards
🛡️ Piénsalo así: OpenZeppelin es como los cimientos antisísmicos de un edificio. No los inventas tú ” los usa toda la industria, están auditados miles de veces, y si hay un bug ya lo encontraron otros. Ownable, ReentrancyGuard, Pausable: son módulos probados en batalla que heredas con una sola línea. El protocolo de staking es el caso de uso perfecto: los usuarios depositan tokens para ganar rewards. La fórmula de distribución de Synthetix (rewardPerToken) es el estándar de la industria.
📚 Refs: OpenZeppelin Docs v5 ” openzeppelin.com/contracts · Synthetix StakingRewards.sol (Kain Warwick, 2019)

Configurar Staking Pool

50%
90
10,000

OZ Modules usados

Ownable ” admin funciones
ReentrancyGuard ” anti-reentry
Pausable ” emergency stop
SafeERC20 ” transfer seguro

Estado del Pool

$0
TVL
0
Reward/Token
0
Días activos
0
Rewards dist.

Stakers (0)

Solidity ” StakingRewards (patrón Synthetix)

contract StakingRewards is Ownable, ReentrancyGuard, Pausable {
  IERC20 public immutable stakingToken;
  IERC20 public immutable rewardsToken;

  uint256 public rewardRate;
  uint256 public rewardPerTokenStored;
  uint256 public lastUpdateTime;
  uint256 private _totalSupply;

  mapping(address => uint256) private _balances;
  mapping(address => uint256) public userRewardPerTokenPaid;
  mapping(address => uint256) public rewards;

  modifier updateReward(address account) {
    rewardPerTokenStored = rewardPerToken();
    lastUpdateTime = block.timestamp;
    if (account != address(0)) {
      rewards[account] = earned(account);
      userRewardPerTokenPaid[account] = rewardPerTokenStored;
    }
    _;
  }

  function stake(uint256 amount)
    external nonReentrant whenNotPaused updateReward(msg.sender) {
    _totalSupply += amount;
    _balances[msg.sender] += amount;
    stakingToken.safeTransferFrom(msg.sender, address(this), amount);
  }

  function earned(address account) public view returns (uint256) {
    return _balances[account]
      * (rewardPerToken() - userRewardPerTokenPaid[account])
      / 1e18
      + rewards[account];
  }
}
🛡️ Despliega el pool, agrega stakers y avanza el tiempo para ver cómo se acumulan los rewards con la fórmula de Synthetix.