Transaction Hash:
Block:
15925780 at Nov-08-2022 02:01:47 PM +UTC
Transaction Fee:
0.005277310510252212 ETH
$12.99
Gas Used:
233,886 Gas / 22.563601542 Gwei
Emitted Events:
131 |
MinimalProxyFactory.VestingCreated( _address=TokenVesting, _salt=528DE7F96B05E0A63A96A6D7516BF21C78D7C28FB2E1979261F8BC89C6C1C882 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x2a686603...4179b2bfe |
0 Eth
Nonce: 0
|
0 Eth
Nonce: 1
| |||
0x95222290...5CC4BAfe5
Miner
| (beaverbuild) | 3.131838456746360789 Eth | 3.132189285746360789 Eth | 0.000350829 | |
0xBef99f5f...e1386a9b0 |
0.800297864612942844 Eth
Nonce: 66
|
0.795020554102690632 Eth
Nonce: 67
| 0.005277310510252212 | ||
0xE3572735...53FD3f6d0 |
Execution Trace
BatchVestings.createVestings( _factory=0xE357273545C152f07afE2c38257B7b653FD3f6d0, _implementation=0x42F32e19365D8045661A006408Cc6d1064039FbF, _salt=88A065F11EB7A9D5EF074D5452A8487C34C91EAD089BB2ADA374D6933731C632, _datas=[hBvuDQAAAAAAAAAAAAAAAIkhTIyppJ5go7+o4AVE84TJNxmxAAAAAAAAAAAAAAAAPGcwIn9Xhbo36NRGTb+aHYfk8KwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY2lxlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJ40AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADtTgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAGsXVHTokJTETamLlU7t6sSVJx0P] )
MinimalProxyFactory.createVesting( _implementation=0x42F32e19365D8045661A006408Cc6d1064039FbF, _salt=528DE7F96B05E0A63A96A6D7516BF21C78D7C28FB2E1979261F8BC89C6C1C882, _data=0x841BEE0D00000000000000000000000089214C8CA9A49E60A3BFA8E00544F384C93719B10000000000000000000000003C6730227F5785BA37E8D4464DBF9A1D87E4F0AC00000000000000000000000000000000000000000000000000000000636971940000000000000000000000000000000000000000000000000000000000278D000000000000000000000000000000000000000000000000000000000000ED4E0000000000000000000000000000000000000000000000000000000000000000010000000000000000000000006B175474E89094C44DA98B954EEDEAC495271D0F ) => ( addr=0x2a6866032afbCB3cee58BEE4a1EeD054179b2bfe )
-
TokenVesting.3d602d80( )
TokenVesting.initialize( _owner=0x89214c8Ca9A49E60a3bfa8e00544F384C93719b1, _beneficiary=0x3C6730227F5785bA37e8d4464DBF9A1D87e4f0AC, _start=1667854740, _cliff=2592000, _duration=15552000, _revocable=True, _token=0x6B175474E89094C44Da98b954EedeAC495271d0F )
-
TokenVesting.initialize( _owner=0x89214c8Ca9A49E60a3bfa8e00544F384C93719b1, _beneficiary=0x3C6730227F5785bA37e8d4464DBF9A1D87e4f0AC, _start=1667854740, _cliff=2592000, _duration=15552000, _revocable=True, _token=0x6B175474E89094C44Da98b954EedeAC495271d0F )
-
-
createVestings[BatchVestings (ln:14)]
createVesting[BatchVestings (ln:21)]
encode[BatchVestings (ln:21)]
File 1 of 4: BatchVestings
File 2 of 4: MinimalProxyFactory
File 3 of 4: TokenVesting
File 4 of 4: TokenVesting
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IVestingFactory { function createVesting( address _implementation, bytes32 _salt, bytes calldata _data ) external returns (address addr); } contract BatchVestings { function createVestings( IVestingFactory _factory, address _implementation, bytes32 _salt, bytes[] calldata _datas ) external { for (uint256 i = 0; i < _datas.length; i++) { _factory.createVesting(_implementation, keccak256(abi.encode(_salt, i)), _datas[i]); } } }
File 2 of 4: MinimalProxyFactory
// SPDX-License-Identifier: MIT pragma solidity ^0.6.2; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // According to EIP-1052, 0x0 is the value returned for not-yet created accounts // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned // for accounts without code, i.e. `keccak256('')` bytes32 codehash; bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; // solhint-disable-next-line no-inline-assembly assembly { codehash := extcodehash(account) } return (codehash != accountHash && codehash != 0x0); } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{ value: amount }(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain`call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { return _functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); return _functionCallWithValue(target, data, value, errorMessage); } function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) { require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: weiValue }(data); if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } } contract MinimalProxyFactory { using Address for address; event VestingCreated(address indexed _address, bytes32 _salt); constructor() public { } function createVesting(address _implementation, bytes32 _salt, bytes memory _data) public virtual returns (address addr) { bytes32 salt = keccak256(abi.encodePacked(_salt, msg.sender)); // solium-disable-next-line security/no-inline-assembly bytes memory slotcode = abi.encodePacked( hex"3d602d80600a3d3981f3363d3d373d3d3d363d73", _implementation, hex"5af43d82803e903d91602b57fd5bf3" ); assembly { addr := create2(0, add(slotcode, 0x20), mload(slotcode), salt) } require(addr != address(0), "MinimalProxyFactory#createVesting: CREATION_FAILED"); emit VestingCreated(addr, _salt); if (_data.length > 0) { (bool success,) = addr.call(_data); require(success, "MinimalProxyFactory#createVesting: CALL_FAILED"); } } }
File 3 of 4: TokenVesting
pragma solidity ^0.4.13; library Math { function max64(uint64 a, uint64 b) internal constant returns (uint64) { return a >= b ? a : b; } function min64(uint64 a, uint64 b) internal constant returns (uint64) { return a < b ? a : b; } function max256(uint256 a, uint256 b) internal constant returns (uint256) { return a >= b ? a : b; } function min256(uint256 a, uint256 b) internal constant returns (uint256) { return a < b ? a : b; } } library SafeMath { function mul(uint256 a, uint256 b) internal constant returns (uint256) { uint256 c = a * b; assert(a == 0 || c / a == b); return c; } function div(uint256 a, uint256 b) internal constant returns (uint256) { // assert(b > 0); // Solidity automatically throws when dividing by 0 uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } function sub(uint256 a, uint256 b) internal constant returns (uint256) { assert(b <= a); return a - b; } function add(uint256 a, uint256 b) internal constant returns (uint256) { uint256 c = a + b; assert(c >= a); return c; } } contract Ownable { address public owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev The Ownable constructor sets the original `owner` of the contract to the sender * account. */ function Ownable() { owner = msg.sender; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(msg.sender == owner); _; } /** * @dev Allows the current owner to transfer control of the contract to a newOwner. * @param newOwner The address to transfer ownership to. */ function transferOwnership(address newOwner) onlyOwner public { require(newOwner != address(0)); OwnershipTransferred(owner, newOwner); owner = newOwner; } } contract ERC20Basic { uint256 public totalSupply; function balanceOf(address who) public constant returns (uint256); function transfer(address to, uint256 value) public returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); } contract ERC20 is ERC20Basic { function allowance(address owner, address spender) public constant returns (uint256); function transferFrom(address from, address to, uint256 value) public returns (bool); function approve(address spender, uint256 value) public returns (bool); event Approval(address indexed owner, address indexed spender, uint256 value); } library SafeERC20 { function safeTransfer(ERC20Basic token, address to, uint256 value) internal { assert(token.transfer(to, value)); } function safeTransferFrom(ERC20 token, address from, address to, uint256 value) internal { assert(token.transferFrom(from, to, value)); } function safeApprove(ERC20 token, address spender, uint256 value) internal { assert(token.approve(spender, value)); } } contract TokenVesting is Ownable { using SafeMath for uint256; using SafeERC20 for ERC20; event Released(uint256 amount); event Revoked(); // beneficiary of tokens after they are released address public beneficiary; uint256 public cliff; uint256 public start; uint256 public duration; bool public revocable; bool public revoked; bool public initialized; uint256 public released; ERC20 public token; /** * @dev Creates a vesting contract that vests its balance of any ERC20 token to the * _beneficiary, gradually in a linear fashion until _start + _duration. By then all * of the balance will have vested. * @param _beneficiary address of the beneficiary to whom vested tokens are transferred * @param _cliff duration in seconds of the cliff in which tokens will begin to vest * @param _duration duration in seconds of the period in which the tokens will vest * @param _revocable whether the vesting is revocable or not * @param _token address of the ERC20 token contract */ function initialize( address _owner, address _beneficiary, uint256 _start, uint256 _cliff, uint256 _duration, bool _revocable, address _token ) public { require(!initialized); require(_beneficiary != 0x0); require(_cliff <= _duration); initialized = true; owner = _owner; beneficiary = _beneficiary; start = _start; cliff = _start.add(_cliff); duration = _duration; revocable = _revocable; token = ERC20(_token); } /** * @notice Only allow calls from the beneficiary of the vesting contract */ modifier onlyBeneficiary() { require(msg.sender == beneficiary); _; } /** * @notice Allow the beneficiary to change its address * @param target the address to transfer the right to */ function changeBeneficiary(address target) onlyBeneficiary public { require(target != 0); beneficiary = target; } /** * @notice Transfers vested tokens to beneficiary. */ function release() onlyBeneficiary public { require(now >= cliff); _releaseTo(beneficiary); } /** * @notice Transfers vested tokens to a target address. * @param target the address to send the tokens to */ function releaseTo(address target) onlyBeneficiary public { require(now >= cliff); _releaseTo(target); } /** * @notice Transfers vested tokens to beneficiary. */ function _releaseTo(address target) internal { uint256 unreleased = releasableAmount(); released = released.add(unreleased); token.safeTransfer(target, unreleased); Released(released); } /** * @notice Allows the owner to revoke the vesting. Tokens already vested are sent to the beneficiary. */ function revoke() onlyOwner public { require(revocable); require(!revoked); // Release all vested tokens _releaseTo(beneficiary); // Send the remainder to the owner token.safeTransfer(owner, token.balanceOf(this)); revoked = true; Revoked(); } /** * @dev Calculates the amount that has already vested but hasn't been released yet. */ function releasableAmount() public constant returns (uint256) { return vestedAmount().sub(released); } /** * @dev Calculates the amount that has already vested. */ function vestedAmount() public constant returns (uint256) { uint256 currentBalance = token.balanceOf(this); uint256 totalBalance = currentBalance.add(released); if (now < cliff) { return 0; } else if (now >= start.add(duration) || revoked) { return totalBalance; } else { return totalBalance.mul(now.sub(start)).div(duration); } } /** * @notice Allow withdrawing any token other than the relevant one */ function releaseForeignToken(ERC20 _token, uint256 amount) onlyOwner { require(_token != token); _token.transfer(owner, amount); } }
File 4 of 4: TokenVesting
pragma solidity ^0.4.13; library Math { function max64(uint64 a, uint64 b) internal constant returns (uint64) { return a >= b ? a : b; } function min64(uint64 a, uint64 b) internal constant returns (uint64) { return a < b ? a : b; } function max256(uint256 a, uint256 b) internal constant returns (uint256) { return a >= b ? a : b; } function min256(uint256 a, uint256 b) internal constant returns (uint256) { return a < b ? a : b; } } library SafeMath { function mul(uint256 a, uint256 b) internal constant returns (uint256) { uint256 c = a * b; assert(a == 0 || c / a == b); return c; } function div(uint256 a, uint256 b) internal constant returns (uint256) { // assert(b > 0); // Solidity automatically throws when dividing by 0 uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } function sub(uint256 a, uint256 b) internal constant returns (uint256) { assert(b <= a); return a - b; } function add(uint256 a, uint256 b) internal constant returns (uint256) { uint256 c = a + b; assert(c >= a); return c; } } contract Ownable { address public owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev The Ownable constructor sets the original `owner` of the contract to the sender * account. */ function Ownable() { owner = msg.sender; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(msg.sender == owner); _; } /** * @dev Allows the current owner to transfer control of the contract to a newOwner. * @param newOwner The address to transfer ownership to. */ function transferOwnership(address newOwner) onlyOwner public { require(newOwner != address(0)); OwnershipTransferred(owner, newOwner); owner = newOwner; } } contract ERC20Basic { uint256 public totalSupply; function balanceOf(address who) public constant returns (uint256); function transfer(address to, uint256 value) public returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); } contract ERC20 is ERC20Basic { function allowance(address owner, address spender) public constant returns (uint256); function transferFrom(address from, address to, uint256 value) public returns (bool); function approve(address spender, uint256 value) public returns (bool); event Approval(address indexed owner, address indexed spender, uint256 value); } library SafeERC20 { function safeTransfer(ERC20Basic token, address to, uint256 value) internal { assert(token.transfer(to, value)); } function safeTransferFrom(ERC20 token, address from, address to, uint256 value) internal { assert(token.transferFrom(from, to, value)); } function safeApprove(ERC20 token, address spender, uint256 value) internal { assert(token.approve(spender, value)); } } contract TokenVesting is Ownable { using SafeMath for uint256; using SafeERC20 for ERC20; event Released(uint256 amount); event Revoked(); // beneficiary of tokens after they are released address public beneficiary; uint256 public cliff; uint256 public start; uint256 public duration; bool public revocable; bool public revoked; bool public initialized; uint256 public released; ERC20 public token; /** * @dev Creates a vesting contract that vests its balance of any ERC20 token to the * _beneficiary, gradually in a linear fashion until _start + _duration. By then all * of the balance will have vested. * @param _beneficiary address of the beneficiary to whom vested tokens are transferred * @param _cliff duration in seconds of the cliff in which tokens will begin to vest * @param _duration duration in seconds of the period in which the tokens will vest * @param _revocable whether the vesting is revocable or not * @param _token address of the ERC20 token contract */ function initialize( address _owner, address _beneficiary, uint256 _start, uint256 _cliff, uint256 _duration, bool _revocable, address _token ) public { require(!initialized); require(_beneficiary != 0x0); require(_cliff <= _duration); initialized = true; owner = _owner; beneficiary = _beneficiary; start = _start; cliff = _start.add(_cliff); duration = _duration; revocable = _revocable; token = ERC20(_token); } /** * @notice Only allow calls from the beneficiary of the vesting contract */ modifier onlyBeneficiary() { require(msg.sender == beneficiary); _; } /** * @notice Allow the beneficiary to change its address * @param target the address to transfer the right to */ function changeBeneficiary(address target) onlyBeneficiary public { require(target != 0); beneficiary = target; } /** * @notice Transfers vested tokens to beneficiary. */ function release() onlyBeneficiary public { require(now >= cliff); _releaseTo(beneficiary); } /** * @notice Transfers vested tokens to a target address. * @param target the address to send the tokens to */ function releaseTo(address target) onlyBeneficiary public { require(now >= cliff); _releaseTo(target); } /** * @notice Transfers vested tokens to beneficiary. */ function _releaseTo(address target) internal { uint256 unreleased = releasableAmount(); released = released.add(unreleased); token.safeTransfer(target, unreleased); Released(released); } /** * @notice Allows the owner to revoke the vesting. Tokens already vested are sent to the beneficiary. */ function revoke() onlyOwner public { require(revocable); require(!revoked); // Release all vested tokens _releaseTo(beneficiary); // Send the remainder to the owner token.safeTransfer(owner, token.balanceOf(this)); revoked = true; Revoked(); } /** * @dev Calculates the amount that has already vested but hasn't been released yet. */ function releasableAmount() public constant returns (uint256) { return vestedAmount().sub(released); } /** * @dev Calculates the amount that has already vested. */ function vestedAmount() public constant returns (uint256) { uint256 currentBalance = token.balanceOf(this); uint256 totalBalance = currentBalance.add(released); if (now < cliff) { return 0; } else if (now >= start.add(duration) || revoked) { return totalBalance; } else { return totalBalance.mul(now.sub(start)).div(duration); } } /** * @notice Allow withdrawing any token other than the relevant one */ function releaseForeignToken(ERC20 _token, uint256 amount) onlyOwner { require(_token != token); _token.transfer(owner, amount); } }