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 }