github.com/ethereum-optimism/optimism@v1.7.2/packages/contracts-bedrock/src/periphery/TransferOnion.sol (about)

     1  // SPDX-License-Identifier: MIT
     2  pragma solidity 0.8.15;
     3  
     4  import { ReentrancyGuard } from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
     5  import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
     6  import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
     7  
     8  /// @title  TransferOnion
     9  /// @notice TransferOnion is a hash onion for distributing tokens. The shell commits
    10  ///         to an ordered list of the token transfers and can be permissionlessly
    11  ///         unwrapped in order. The SENDER must `approve` this contract as
    12  ///         `transferFrom` is used to move the token balances.
    13  contract TransferOnion is ReentrancyGuard {
    14      using SafeERC20 for ERC20;
    15  
    16      /// @notice Struct representing a layer of the onion.
    17      struct Layer {
    18          address recipient;
    19          uint256 amount;
    20          bytes32 shell;
    21      }
    22  
    23      /// @notice Address of the token to distribute.
    24      ERC20 public immutable TOKEN;
    25  
    26      /// @notice Address of the account to distribute tokens from.
    27      address public immutable SENDER;
    28  
    29      /// @notice Current shell hash.
    30      bytes32 public shell;
    31  
    32      /// @notice Constructs a new TransferOnion.
    33      /// @param _token  Address of the token to distribute.
    34      /// @param _sender Address of the sender to distribute from.
    35      /// @param _shell  Initial shell of the onion.
    36      constructor(ERC20 _token, address _sender, bytes32 _shell) {
    37          TOKEN = _token;
    38          SENDER = _sender;
    39          shell = _shell;
    40      }
    41  
    42      /// @notice Peels layers from the onion and distributes tokens.
    43      /// @param _layers Array of onion layers to peel.
    44      function peel(Layer[] memory _layers) public nonReentrant {
    45          bytes32 tempShell = shell;
    46          uint256 length = _layers.length;
    47          for (uint256 i = 0; i < length;) {
    48              Layer memory layer = _layers[i];
    49  
    50              // Confirm that the onion layer is correct.
    51              require(
    52                  keccak256(abi.encode(layer.recipient, layer.amount, layer.shell)) == tempShell,
    53                  "TransferOnion: what are you doing in my swamp?"
    54              );
    55  
    56              // Update the onion layer.
    57              tempShell = layer.shell;
    58  
    59              // Transfer the tokens.
    60              // slither-disable-next-line arbitrary-send-erc20
    61              TOKEN.safeTransferFrom(SENDER, layer.recipient, layer.amount);
    62  
    63              // Unchecked increment to save some gas.
    64              unchecked {
    65                  ++i;
    66              }
    67          }
    68  
    69          shell = tempShell;
    70      }
    71  }