Transaction Hash:
Block:
21623932 at Jan-14-2025 04:29:59 PM +UTC
Transaction Fee:
0.000623489090253975 ETH
$1.55
Gas Used:
66,825 Gas / 9.330177183 Gwei
Emitted Events:
400 |
LnProxyERC20.Approval( owner=[Sender] 0x5f939de0e81a199a34e50615f34cbab82412459a, spender=0x68b34658...D8665Fc45, value=285260000000000000000000000 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x4838B106...B0BAD5f97
Miner
| (Titan Builder) | 13.79223073635153262 Eth | 13.79223741885153262 Eth | 0.0000066825 | |
0x5F939de0...82412459a |
8.045816340609889755 Eth
Nonce: 86
|
8.04519285151963578 Eth
Nonce: 87
| 0.000623489090253975 | ||
0xf1A16D77...71eCF6CfE |
Execution Trace
LnProxyERC20.approve( spender=0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45, value=285260000000000000000000000 ) => ( True )

-
LinearFinance.setMessageSender( sender=0x5F939de0E81a199a34e50615F34cBAb82412459a )
LinearFinance.approve( spender=0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45, value=285260000000000000000000000 ) => ( True )
-
LnTokenStorage.setAllowance( tokenOwner=0x5F939de0E81a199a34e50615F34cBAb82412459a, spender=0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45, value=285260000000000000000000000 )
-
LnProxyERC20.Log3( callData=0x000000000000000000000000000000000000000000EBF627960EA18257800000, topic1=8C5BE1E5EBEC7D5BD14F71427D1E84F3DD0314C0F7B2291E5B200AC8C7C3B925, topic2=0000000000000000000000005F939DE0E81A199A34E50615F34CBAB82412459A, topic3=00000000000000000000000068B3465833FB72A70ECDF485E0E4C7BD8665FC45 )
-
approve[LnProxyERC20 (ln:236)]
setMessageSender[LnProxyERC20 (ln:238)]
approve[LnProxyERC20 (ln:240)]
File 1 of 3: LnProxyERC20
File 2 of 3: LinearFinance
File 3 of 3: LnTokenStorage
// SPDX-License-Identifier: MIT pragma solidity ^0.6.12; interface IERC20 { function name() external view returns (string memory); function symbol() external view returns (string memory); function decimals() external view returns (uint8); function totalSupply() external view returns (uint); function balanceOf(address owner) external view returns (uint); function allowance(address owner, address spender) external view returns (uint); function transfer(address to, uint value) external returns (bool); function approve(address spender, uint value) external returns (bool); function transferFrom( address from, address to, uint value ) external returns (bool); event Transfer(address indexed from, address indexed to, uint value); event Approval(address indexed owner, address indexed spender, uint value); } contract LnAdmin { address public admin; address public candidate; constructor(address _admin) public { require(_admin != address(0), "admin address cannot be 0"); admin = _admin; emit AdminChanged(address(0), _admin); } function setCandidate(address _candidate) external onlyAdmin { address old = candidate; candidate = _candidate; emit candidateChanged( old, candidate); } function becomeAdmin( ) external { require( msg.sender == candidate, "Only candidate can become admin"); address old = admin; admin = candidate; emit AdminChanged( old, admin ); } modifier onlyAdmin { require( (msg.sender == admin), "Only the contract admin can perform this action"); _; } event candidateChanged(address oldCandidate, address newCandidate ); event AdminChanged(address oldAdmin, address newAdmin); } contract LnProxyBase is LnAdmin { LnProxyImpl public target; constructor(address _admin) public LnAdmin(_admin) {} function setTarget(LnProxyImpl _target) external onlyAdmin { target = _target; emit TargetUpdated(_target); } function Log0( bytes calldata callData ) external onlyTarget { uint size = callData.length; bytes memory _callData = callData; assembly { log0(add(_callData, 32), size) } } function Log1( bytes calldata callData, bytes32 topic1 ) external onlyTarget { uint size = callData.length; bytes memory _callData = callData; assembly { log1(add(_callData, 32), size, topic1 ) } } function Log2( bytes calldata callData, bytes32 topic1, bytes32 topic2 ) external onlyTarget { uint size = callData.length; bytes memory _callData = callData; assembly { log2(add(_callData, 32), size, topic1, topic2 ) } } function Log3( bytes calldata callData, bytes32 topic1, bytes32 topic2, bytes32 topic3 ) external onlyTarget { uint size = callData.length; bytes memory _callData = callData; assembly { log3(add(_callData, 32), size, topic1, topic2, topic3 ) } } function Log4( bytes calldata callData, bytes32 topic1, bytes32 topic2, bytes32 topic3, bytes32 topic4 ) external onlyTarget { uint size = callData.length; bytes memory _callData = callData; assembly { log4(add(_callData, 32), size, topic1, topic2, topic3, topic4 ) } } //receive: It is executed on a call to the contract with empty calldata. This is the function that is executed on plain Ether transfers (e.g. via .send() or .transfer()). //fallback: can only rely on 2300 gas being available, receive() external payable { target.setMessageSender(msg.sender); assembly { let free_ptr := mload(0x40) calldatacopy(free_ptr, 0, calldatasize()) let result := call(gas(), sload(target_slot), callvalue(), free_ptr, calldatasize(), 0, 0) returndatacopy(free_ptr, 0, returndatasize()) if iszero(result) { revert(free_ptr, returndatasize()) } return(free_ptr, returndatasize()) } } modifier onlyTarget { require(LnProxyImpl(msg.sender) == target, "Must be proxy target"); _; } event TargetUpdated(LnProxyImpl newTarget); } abstract contract LnProxyImpl is LnAdmin { LnProxyBase public proxy; LnProxyBase public integrationProxy; address public messageSender; constructor(address payable _proxy) internal { require(admin != address(0), "Admin must be set"); proxy = LnProxyBase(_proxy); emit ProxyUpdated(_proxy); } function setProxy(address payable _proxy) external onlyAdmin { proxy = LnProxyBase(_proxy); emit ProxyUpdated(_proxy); } function setIntegrationProxy(address payable _integrationProxy) external onlyAdmin { integrationProxy = LnProxyBase(_integrationProxy); } function setMessageSender(address sender) external onlyProxy { messageSender = sender; } modifier onlyProxy { require(LnProxyBase(msg.sender) == proxy || LnProxyBase(msg.sender) == integrationProxy, "Only the proxy can call"); _; } modifier optionalProxy { if (LnProxyBase(msg.sender) != proxy && LnProxyBase(msg.sender) != integrationProxy && messageSender != msg.sender) { messageSender = msg.sender; } _; } modifier optionalProxy_onlyAdmin { if (LnProxyBase(msg.sender) != proxy && LnProxyBase(msg.sender) != integrationProxy && messageSender != msg.sender) { messageSender = msg.sender; } require(messageSender == admin, "only for admin"); _; } event ProxyUpdated(address proxyAddress); } contract LnProxyERC20 is LnProxyBase, IERC20 { constructor(address _admin) public LnProxyBase(_admin) {} function name() public view override returns (string memory) { return IERC20(address(target)).name(); } function symbol() public view override returns (string memory) { return IERC20(address(target)).symbol(); } function decimals() public view override returns (uint8) { return IERC20(address(target)).decimals(); } function totalSupply() public view override returns (uint256) { return IERC20(address(target)).totalSupply(); } function balanceOf(address account) public view override returns (uint256) { return IERC20(address(target)).balanceOf(account); } function allowance(address owner, address spender) public view override returns (uint256) { return IERC20(address(target)).allowance(owner, spender); } function transfer(address to, uint256 value) public override returns (bool) { target.setMessageSender(msg.sender); IERC20(address(target)).transfer(to, value); return true; } function approve(address spender, uint256 value) public override returns (bool) { target.setMessageSender(msg.sender); IERC20(address(target)).approve(spender, value); return true; } function transferFrom( address from, address to, uint256 value ) public override returns (bool) { target.setMessageSender(msg.sender); IERC20(address(target)).transferFrom(from, to, value); return true; } }
File 2 of 3: LinearFinance
// SPDX-License-Identifier: MIT pragma solidity ^0.6.12; abstract contract Context { function _msgSender() internal view virtual returns (address payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } } contract Pausable is Context { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ constructor () internal { _paused = false; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view returns (bool) { return _paused; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { require(!_paused, "Pausable: paused"); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { require(_paused, "Pausable: not paused"); _; } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } } library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } } interface IERC20 { function name() external view returns (string memory); function symbol() external view returns (string memory); function decimals() external view returns (uint8); function totalSupply() external view returns (uint); function balanceOf(address owner) external view returns (uint); function allowance(address owner, address spender) external view returns (uint); function transfer(address to, uint value) external returns (bool); function approve(address spender, uint value) external returns (bool); function transferFrom( address from, address to, uint value ) external returns (bool); event Transfer(address indexed from, address indexed to, uint value); event Approval(address indexed owner, address indexed spender, uint value); } library SafeDecimalMath { using SafeMath for uint; uint8 public constant decimals = 18; uint8 public constant highPrecisionDecimals = 27; uint public constant UNIT = 10**uint(decimals); uint public constant PRECISE_UNIT = 10**uint(highPrecisionDecimals); uint private constant UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR = 10**uint(highPrecisionDecimals - decimals); function unit() external pure returns (uint) { return UNIT; } function preciseUnit() external pure returns (uint) { return PRECISE_UNIT; } function multiplyDecimal(uint x, uint y) internal pure returns (uint) { return x.mul(y) / UNIT; } function _multiplyDecimalRound( uint x, uint y, uint precisionUnit ) private pure returns (uint) { uint quotientTimesTen = x.mul(y) / (precisionUnit / 10); if (quotientTimesTen % 10 >= 5) { quotientTimesTen += 10; } return quotientTimesTen / 10; } function multiplyDecimalRoundPrecise(uint x, uint y) internal pure returns (uint) { return _multiplyDecimalRound(x, y, PRECISE_UNIT); } function multiplyDecimalRound(uint x, uint y) internal pure returns (uint) { return _multiplyDecimalRound(x, y, UNIT); } function divideDecimal(uint x, uint y) internal pure returns (uint) { return x.mul(UNIT).div(y); } function _divideDecimalRound( uint x, uint y, uint precisionUnit ) private pure returns (uint) { uint resultTimesTen = x.mul(precisionUnit * 10).div(y); if (resultTimesTen % 10 >= 5) { resultTimesTen += 10; } return resultTimesTen / 10; } function divideDecimalRound(uint x, uint y) internal pure returns (uint) { return _divideDecimalRound(x, y, UNIT); } function divideDecimalRoundPrecise(uint x, uint y) internal pure returns (uint) { return _divideDecimalRound(x, y, PRECISE_UNIT); } function decimalToPreciseDecimal(uint i) internal pure returns (uint) { return i.mul(UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR); } function preciseDecimalToDecimal(uint i) internal pure returns (uint) { uint quotientTimesTen = i / (UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR / 10); if (quotientTimesTen % 10 >= 5) { quotientTimesTen += 10; } return quotientTimesTen / 10; } } contract LnAdmin { address public admin; address public candidate; constructor(address _admin) public { require(_admin != address(0), "admin address cannot be 0"); admin = _admin; emit AdminChanged(address(0), _admin); } function setCandidate(address _candidate) external onlyAdmin { address old = candidate; candidate = _candidate; emit candidateChanged( old, candidate); } function becomeAdmin( ) external { require( msg.sender == candidate, "Only candidate can become admin"); address old = admin; admin = candidate; emit AdminChanged( old, admin ); } modifier onlyAdmin { require( (msg.sender == admin), "Only the contract admin can perform this action"); _; } event candidateChanged(address oldCandidate, address newCandidate ); event AdminChanged(address oldAdmin, address newAdmin); } contract LnProxyBase is LnAdmin { LnProxyImpl public target; constructor(address _admin) public LnAdmin(_admin) {} function setTarget(LnProxyImpl _target) external onlyAdmin { target = _target; emit TargetUpdated(_target); } function Log0( bytes calldata callData ) external onlyTarget { uint size = callData.length; bytes memory _callData = callData; assembly { log0(add(_callData, 32), size) } } function Log1( bytes calldata callData, bytes32 topic1 ) external onlyTarget { uint size = callData.length; bytes memory _callData = callData; assembly { log1(add(_callData, 32), size, topic1 ) } } function Log2( bytes calldata callData, bytes32 topic1, bytes32 topic2 ) external onlyTarget { uint size = callData.length; bytes memory _callData = callData; assembly { log2(add(_callData, 32), size, topic1, topic2 ) } } function Log3( bytes calldata callData, bytes32 topic1, bytes32 topic2, bytes32 topic3 ) external onlyTarget { uint size = callData.length; bytes memory _callData = callData; assembly { log3(add(_callData, 32), size, topic1, topic2, topic3 ) } } function Log4( bytes calldata callData, bytes32 topic1, bytes32 topic2, bytes32 topic3, bytes32 topic4 ) external onlyTarget { uint size = callData.length; bytes memory _callData = callData; assembly { log4(add(_callData, 32), size, topic1, topic2, topic3, topic4 ) } } //receive: It is executed on a call to the contract with empty calldata. This is the function that is executed on plain Ether transfers (e.g. via .send() or .transfer()). //fallback: can only rely on 2300 gas being available, receive() external payable { target.setMessageSender(msg.sender); assembly { let free_ptr := mload(0x40) calldatacopy(free_ptr, 0, calldatasize()) let result := call(gas(), sload(target_slot), callvalue(), free_ptr, calldatasize(), 0, 0) returndatacopy(free_ptr, 0, returndatasize()) if iszero(result) { revert(free_ptr, returndatasize()) } return(free_ptr, returndatasize()) } } modifier onlyTarget { require(LnProxyImpl(msg.sender) == target, "Must be proxy target"); _; } event TargetUpdated(LnProxyImpl newTarget); } abstract contract LnProxyImpl is LnAdmin { LnProxyBase public proxy; LnProxyBase public integrationProxy; address public messageSender; constructor(address payable _proxy) internal { require(admin != address(0), "Admin must be set"); proxy = LnProxyBase(_proxy); emit ProxyUpdated(_proxy); } function setProxy(address payable _proxy) external onlyAdmin { proxy = LnProxyBase(_proxy); emit ProxyUpdated(_proxy); } function setIntegrationProxy(address payable _integrationProxy) external onlyAdmin { integrationProxy = LnProxyBase(_integrationProxy); } function setMessageSender(address sender) external onlyProxy { messageSender = sender; } modifier onlyProxy { require(LnProxyBase(msg.sender) == proxy || LnProxyBase(msg.sender) == integrationProxy, "Only the proxy can call"); _; } modifier optionalProxy { if (LnProxyBase(msg.sender) != proxy && LnProxyBase(msg.sender) != integrationProxy && messageSender != msg.sender) { messageSender = msg.sender; } _; } modifier optionalProxy_onlyAdmin { if (LnProxyBase(msg.sender) != proxy && LnProxyBase(msg.sender) != integrationProxy && messageSender != msg.sender) { messageSender = msg.sender; } require(messageSender == admin, "only for admin"); _; } event ProxyUpdated(address proxyAddress); } contract LnErc20Handler is IERC20, LnAdmin, LnProxyImpl { using SafeMath for uint; using SafeDecimalMath for uint; LnTokenStorage public tokenStorage; string public override name; string public override symbol; uint public override totalSupply; uint8 public override decimals; constructor( address payable _proxy, LnTokenStorage _tokenStorage, string memory _name, string memory _symbol, uint _totalSupply, uint8 _decimals, address _admin ) public LnAdmin(_admin) LnProxyImpl(_proxy) { tokenStorage = _tokenStorage; name = _name; symbol = _symbol; totalSupply = _totalSupply; decimals = _decimals; } function allowance(address owner, address spender) public view virtual override returns (uint) { return tokenStorage.allowance(owner, spender); } function balanceOf(address account) external view override returns (uint) { return tokenStorage.balanceOf(account); } function setTokenStorage(LnTokenStorage _tokenStorage) external optionalProxy_onlyAdmin { tokenStorage = _tokenStorage; emitTokenStorageUpdated(address(tokenStorage)); } function _internalTransfer( address from, address to, uint value ) internal returns (bool) { require(to != address(0) && to != address(this) && to != address(proxy), "Cannot transfer to this address"); _beforeTokenTransfer(from, to, value); tokenStorage.setBalanceOf(from, tokenStorage.balanceOf(from).sub(value)); tokenStorage.setBalanceOf(to, tokenStorage.balanceOf(to).add(value)); emitTransfer(from, to, value); return true; } function _transferByProxy( address from, address to, uint value ) internal returns (bool) { return _internalTransfer(from, to, value); } function _transferFromByProxy( address sender, address from, address to, uint value ) internal returns (bool) { tokenStorage.setAllowance(from, sender, tokenStorage.allowance(from, sender).sub(value)); return _internalTransfer(from, to, value); } function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { } // default transfer function transfer(address to, uint value) external virtual override optionalProxy returns (bool) { _transferByProxy(messageSender, to, value); return true; } // default transferFrom function transferFrom( address from, address to, uint value ) external virtual override optionalProxy returns (bool) { return _transferFromByProxy(messageSender, from, to, value); } function approve(address spender, uint value) public virtual override optionalProxy returns (bool) { address sender = messageSender; tokenStorage.setAllowance(sender, spender, value); emitApproval(sender, spender, value); return true; } function addressToBytes32(address input) internal pure returns (bytes32) { return bytes32(uint256(uint160(input))); } event Transfer(address indexed from, address indexed to, uint value); bytes32 internal constant TRANSFER_SIG = keccak256("Transfer(address,address,uint256)"); function emitTransfer( address from, address to, uint value ) internal { proxy.Log3( abi.encode(value), TRANSFER_SIG, addressToBytes32(from), addressToBytes32(to) ); } event Approval(address indexed owner, address indexed spender, uint value); bytes32 internal constant APPROVAL_SIG = keccak256("Approval(address,address,uint256)"); function emitApproval( address owner, address spender, uint value ) internal { proxy.Log3( abi.encode(value), APPROVAL_SIG, addressToBytes32(owner), addressToBytes32(spender) ); } event TokenStorageUpdated(address newTokenStorage); bytes32 internal constant TOKENSTORAGE_UPDATED_SIG = keccak256("TokenStorageUpdated(address)"); function emitTokenStorageUpdated(address newTokenStorage) internal { proxy.Log1( abi.encode(newTokenStorage), TOKENSTORAGE_UPDATED_SIG ); } } abstract contract LnOperatorModifier is LnAdmin { address public operator; constructor(address _operator) internal { require(admin != address(0), "admin must be set"); operator = _operator; emit OperatorUpdated(_operator); } function setOperator(address _opperator) external onlyAdmin { operator = _opperator; emit OperatorUpdated(_opperator); } modifier onlyOperator() { require(msg.sender == operator, "Only operator can perform this action"); _; } event OperatorUpdated(address operator); } contract LnTokenStorage is LnAdmin, LnOperatorModifier { mapping(address => uint) public balanceOf; mapping(address => mapping(address => uint)) public allowance; constructor(address _admin, address _operator) public LnAdmin(_admin) LnOperatorModifier(_operator) {} function setAllowance(address tokenOwner, address spender, uint value) external onlyOperator { allowance[tokenOwner][spender] = value; } function setBalanceOf(address account, uint value) external onlyOperator { balanceOf[account] = value; } } contract LinearFinance is LnErc20Handler { string public constant TOKEN_NAME = "Linear Token"; string public constant TOKEN_SYMBOL = "LINA"; uint8 public constant DECIMALS = 18; uint256 public constant MAX_SUPPLY = 10000000000e18; constructor( address payable _proxy, LnTokenStorage _tokenStorage, address _admin, uint _totalSupply ) public LnErc20Handler(_proxy, _tokenStorage, TOKEN_NAME, TOKEN_SYMBOL, _totalSupply, DECIMALS, _admin) { } // function _mint(address account, uint256 amount) private { require(account != address(0), "ERC20: mint to the zero address"); require(totalSupply.add(amount) <= MAX_SUPPLY, "Can not mint over max supply"); _beforeTokenTransfer(address(0), account, amount); tokenStorage.setBalanceOf(account, tokenStorage.balanceOf(account).add(amount)); totalSupply = totalSupply.add(amount); emitTransfer(address(0), account, amount); } function mint(address account, uint256 amount) external onlyAdmin { _mint(account, amount); } function _burn(address account, uint256 amount) private { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); tokenStorage.setBalanceOf(account, tokenStorage.balanceOf(account).sub(amount)); totalSupply = totalSupply.sub(amount); emitTransfer(account, address(0), amount); } function burn(address account, uint256 amount) external onlyAdmin { _burn(account, amount); } function _beforeTokenTransfer(address from, address to, uint256 amount) internal override { super._beforeTokenTransfer(from, to, amount); require(!paused, "ERC20Pausable: token transfer while paused"); } ////////////////////////////////////////////////////// paused bool public paused = false; modifier notPaused { require(!paused, "This action cannot be performed while the contract is paused"); _; } function setPaused(bool _paused) external onlyAdmin { if (_paused == paused) { return; } paused = _paused; emit PauseChanged(paused); } ////////////////////////////////////////////////////// event PauseChanged(bool isPaused); }
File 3 of 3: LnTokenStorage
// SPDX-License-Identifier: MIT pragma solidity ^0.6.12; contract LnAdmin { address public admin; address public candidate; constructor(address _admin) public { require(_admin != address(0), "admin address cannot be 0"); admin = _admin; emit AdminChanged(address(0), _admin); } function setCandidate(address _candidate) external onlyAdmin { address old = candidate; candidate = _candidate; emit candidateChanged( old, candidate); } function becomeAdmin( ) external { require( msg.sender == candidate, "Only candidate can become admin"); address old = admin; admin = candidate; emit AdminChanged( old, admin ); } modifier onlyAdmin { require( (msg.sender == admin), "Only the contract admin can perform this action"); _; } event candidateChanged(address oldCandidate, address newCandidate ); event AdminChanged(address oldAdmin, address newAdmin); } abstract contract LnOperatorModifier is LnAdmin { address public operator; constructor(address _operator) internal { require(admin != address(0), "admin must be set"); operator = _operator; emit OperatorUpdated(_operator); } function setOperator(address _opperator) external onlyAdmin { operator = _opperator; emit OperatorUpdated(_opperator); } modifier onlyOperator() { require(msg.sender == operator, "Only operator can perform this action"); _; } event OperatorUpdated(address operator); } contract LnTokenStorage is LnAdmin, LnOperatorModifier { mapping(address => uint) public balanceOf; mapping(address => mapping(address => uint)) public allowance; constructor(address _admin, address _operator) public LnAdmin(_admin) LnOperatorModifier(_operator) {} function setAllowance(address tokenOwner, address spender, uint value) external onlyOperator { allowance[tokenOwner][spender] = value; } function setBalanceOf(address account, uint value) external onlyOperator { balanceOf[account] = value; } }