Transaction Hash:
Block:
19508319 at Mar-25-2024 01:42:23 AM +UTC
Transaction Fee:
0.00068375410717104 ETH
$1.75
Gas Used:
46,520 Gas / 14.698067652 Gwei
Emitted Events:
388 |
OLAS.Transfer( from=[Sender] 0x2c6d818b97f2730084cfc1b610afde6467223d81, to=0x9ecb44B6D9319d7483b36990E193002a1073ffae, amount=81949568141350542146 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x0001A500...c28E45CB0 | |||||
0x2C6d818b...467223D81 |
0.023665359245757217 Eth
Nonce: 102
|
0.022981605138586177 Eth
Nonce: 103
| 0.00068375410717104 | ||
0x4838B106...B0BAD5f97
Miner
| (Titan Builder) | 13.168586147073762012 Eth | 13.168588473073762012 Eth | 0.000002326 |
Execution Trace
OLAS.transfer( to=0x9ecb44B6D9319d7483b36990E193002a1073ffae, amount=81949568141350542146 ) => ( True )
transfer[ERC20 (ln:178)]
Transfer[ERC20 (ln:185)]
// SPDX-License-Identifier: MIT pragma solidity ^0.8.15; import "../lib/solmate/src/tokens/ERC20.sol"; /// @dev Only `manager` has a privilege, but the `sender` was provided. /// @param sender Sender address. /// @param manager Required sender address as a manager. error ManagerOnly(address sender, address manager); /// @dev Provided zero address. error ZeroAddress(); /// @title OLAS - Smart contract for the OLAS token. /// @author AL /// @author Aleksandr Kuperman - <[email protected]> contract OLAS is ERC20 { event MinterUpdated(address indexed minter); event OwnerUpdated(address indexed owner); // One year interval uint256 public constant oneYear = 1 days * 365; // Total supply cap for the first ten years (one billion OLAS tokens) uint256 public constant tenYearSupplyCap = 1_000_000_000e18; // Maximum annual inflation after first ten years uint256 public constant maxMintCapFraction = 2; // Initial timestamp of the token deployment uint256 public immutable timeLaunch; // Owner address address public owner; // Minter address address public minter; constructor() ERC20("Autonolas", "OLAS", 18) { owner = msg.sender; minter = msg.sender; timeLaunch = block.timestamp; } /// @dev Changes the owner address. /// @param newOwner Address of a new owner. function changeOwner(address newOwner) external { if (msg.sender != owner) { revert ManagerOnly(msg.sender, owner); } if (newOwner == address(0)) { revert ZeroAddress(); } owner = newOwner; emit OwnerUpdated(newOwner); } /// @dev Changes the minter address. /// @param newMinter Address of a new minter. function changeMinter(address newMinter) external { if (msg.sender != owner) { revert ManagerOnly(msg.sender, owner); } if (newMinter == address(0)) { revert ZeroAddress(); } minter = newMinter; emit MinterUpdated(newMinter); } /// @dev Mints OLAS tokens. /// @param account Account address. /// @param amount OLAS token amount. function mint(address account, uint256 amount) external { // Access control if (msg.sender != minter) { revert ManagerOnly(msg.sender, minter); } // Check the inflation schedule and mint if (inflationControl(amount)) { _mint(account, amount); } } /// @dev Provides various checks for the inflation control. /// @param amount Amount of OLAS to mint. /// @return True if the amount request is within inflation boundaries. function inflationControl(uint256 amount) public view returns (bool) { uint256 remainder = inflationRemainder(); return (amount <= remainder); } /// @dev Gets the reminder of OLAS possible for the mint. /// @return remainder OLAS token remainder. function inflationRemainder() public view returns (uint256 remainder) { uint256 _totalSupply = totalSupply; // Current year uint256 numYears = (block.timestamp - timeLaunch) / oneYear; // Calculate maximum mint amount to date uint256 supplyCap = tenYearSupplyCap; // After 10 years, adjust supplyCap according to the yearly inflation % set in maxMintCapFraction if (numYears > 9) { // Number of years after ten years have passed (including ongoing ones) numYears -= 9; for (uint256 i = 0; i < numYears; ++i) { supplyCap += (supplyCap * maxMintCapFraction) / 100; } } // Check for the requested mint overflow remainder = supplyCap - _totalSupply; } /// @dev Burns OLAS tokens. /// @param amount OLAS token amount to burn. function burn(uint256 amount) external { _burn(msg.sender, amount); } /// @dev Decreases the allowance of another account over their tokens. /// @param spender Account that tokens are approved for. /// @param amount Amount to decrease approval by. /// @return True if the operation succeeded. function decreaseAllowance(address spender, uint256 amount) external returns (bool) { uint256 spenderAllowance = allowance[msg.sender][spender]; if (spenderAllowance != type(uint256).max) { spenderAllowance -= amount; allowance[msg.sender][spender] = spenderAllowance; emit Approval(msg.sender, spender, spenderAllowance); } return true; } /// @dev Increases the allowance of another account over their tokens. /// @param spender Account that tokens are approved for. /// @param amount Amount to increase approval by. /// @return True if the operation succeeded. function increaseAllowance(address spender, uint256 amount) external returns (bool) { uint256 spenderAllowance = allowance[msg.sender][spender]; spenderAllowance += amount; allowance[msg.sender][spender] = spenderAllowance; emit Approval(msg.sender, spender, spenderAllowance); return true; } } // SPDX-License-Identifier: MIT pragma solidity >=0.8.0; /// @notice Modern and gas efficient ERC20 + EIP-2612 implementation. /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC20.sol) /// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol) /// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it. abstract contract ERC20 { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); /*////////////////////////////////////////////////////////////// METADATA STORAGE //////////////////////////////////////////////////////////////*/ string public name; string public symbol; uint8 public immutable decimals; /*////////////////////////////////////////////////////////////// ERC20 STORAGE //////////////////////////////////////////////////////////////*/ uint256 public totalSupply; mapping(address => uint256) public balanceOf; mapping(address => mapping(address => uint256)) public allowance; /*////////////////////////////////////////////////////////////// EIP-2612 STORAGE //////////////////////////////////////////////////////////////*/ uint256 internal immutable INITIAL_CHAIN_ID; bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR; mapping(address => uint256) public nonces; /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor( string memory _name, string memory _symbol, uint8 _decimals ) { name = _name; symbol = _symbol; decimals = _decimals; INITIAL_CHAIN_ID = block.chainid; INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator(); } /*////////////////////////////////////////////////////////////// ERC20 LOGIC //////////////////////////////////////////////////////////////*/ function approve(address spender, uint256 amount) public virtual returns (bool) { allowance[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } function transfer(address to, uint256 amount) public virtual returns (bool) { balanceOf[msg.sender] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(msg.sender, to, amount); return true; } function transferFrom( address from, address to, uint256 amount ) public virtual returns (bool) { uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals. if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; balanceOf[from] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(from, to, amount); return true; } /*////////////////////////////////////////////////////////////// EIP-2612 LOGIC //////////////////////////////////////////////////////////////*/ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual { require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED"); // Unchecked because the only math done is incrementing // the owner's nonce which cannot realistically overflow. unchecked { address recoveredAddress = ecrecover( keccak256( abi.encodePacked( "\\x19\\x01", DOMAIN_SEPARATOR(), keccak256( abi.encode( keccak256( "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" ), owner, spender, value, nonces[owner]++, deadline ) ) ) ), v, r, s ); require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER"); allowance[recoveredAddress][spender] = value; } emit Approval(owner, spender, value); } function DOMAIN_SEPARATOR() public view virtual returns (bytes32) { return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator(); } function computeDomainSeparator() internal view virtual returns (bytes32) { return keccak256( abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256(bytes(name)), keccak256("1"), block.chainid, address(this) ) ); } /*////////////////////////////////////////////////////////////// INTERNAL MINT/BURN LOGIC //////////////////////////////////////////////////////////////*/ function _mint(address to, uint256 amount) internal virtual { totalSupply += amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(address(0), to, amount); } function _burn(address from, uint256 amount) internal virtual { balanceOf[from] -= amount; // Cannot underflow because a user's balance // will never be larger than the total supply. unchecked { totalSupply -= amount; } emit Transfer(from, address(0), amount); } }