ETH Price: $2,489.43 (+1.31%)

Transaction Decoder

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 Code
(Titan Builder)
13.79223073635153262 Eth13.79223741885153262 Eth0.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 )
      File 1 of 3: LnProxyERC20
      // 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;
          }
      }