Transaction Hash:
Block:
21623932 at Jan-14-2025 04:29:59 PM +UTC
Transaction Fee:
0.000611723736826212 ETH
$1.54
Gas Used:
65,564 Gas / 9.330177183 Gwei
Emitted Events:
420 |
TokenProxy.0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925( 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925, 0x0000000000000000000000005f939de0e81a199a34e50615f34cbab82412459a, 0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d, 0000000000000000000000000000000000000000078452adf5f537ee4c200000 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x0815425f...18Fa7B907 | |||||
0x4838B106...B0BAD5f97
Miner
| (Titan Builder) | 13.79232749095153262 Eth | 13.79233404735153262 Eth | 0.0000065564 | |
0x5F939de0...82412459a |
8.036788964997186837 Eth
Nonce: 106
|
8.036177241260360625 Eth
Nonce: 107
| 0.000611723736826212 |
Execution Trace
TokenProxy.095ea7b3( )

AkropolisToken.approve( _spender=0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D, _value=2326363720000000000000000000 ) => ( True )
-
0x0815425f6a333b92d49b088aea2290418fa7b907.da46098c( )
-
approve[AkropolisToken (ln:776)]
approve[AkropolisToken (ln:778)]
File 1 of 2: TokenProxy
File 2 of 2: AkropolisToken
/* Akropolis Token, https://akropolis.io */ pragma solidity ^0.4.24; // File: openzeppelin-solidity/contracts/math/SafeMath.sol /** * @title SafeMath * @dev Math operations with safety checks that throw on error */ library SafeMath { /** * @dev Multiplies two numbers, throws on overflow. */ function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c) { // Gas optimization: this is cheaper than asserting 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 if (_a == 0) { return 0; } c = _a * _b; assert(c / _a == _b); return c; } /** * @dev Integer division of two numbers, truncating the quotient. */ function div(uint256 _a, uint256 _b) internal pure 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 _a / _b; } /** * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). */ function sub(uint256 _a, uint256 _b) internal pure returns (uint256) { assert(_b <= _a); return _a - _b; } /** * @dev Adds two numbers, throws on overflow. */ function add(uint256 _a, uint256 _b) internal pure returns (uint256 c) { c = _a + _b; assert(c >= _a); return c; } } // File: contracts/helpers/Ownable.sol /** * @title Ownable * @dev The Ownable contract has an owner address, and provides basic authorization control * functions, this simplifies the implementation of "user permissions". This adds two-phase * ownership control to OpenZeppelin's Ownable class. In this model, the original owner * designates a new owner but does not actually transfer ownership. The new owner then accepts * ownership and completes the transfer. */ contract Ownable { address public owner; address public pendingOwner; event OwnershipTransferred( address indexed previousOwner, address indexed newOwner ); /** * @dev The Ownable constructor sets the original `owner` of the contract to the sender * account. */ constructor() public { owner = msg.sender; pendingOwner = address(0); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(msg.sender == owner, "Account is not owner"); _; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyPendingOwner() { require(msg.sender == pendingOwner, "Account is not pending 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) public onlyOwner { require(_newOwner != address(0), "Empty address"); pendingOwner = _newOwner; } /** * @dev Allows the pendingOwner address to finalize the transfer. */ function claimOwnership() onlyPendingOwner public { emit OwnershipTransferred(owner, pendingOwner); owner = pendingOwner; pendingOwner = address(0); } } // File: contracts/token/dataStorage/AllowanceSheet.sol /** * @title AllowanceSheet * @notice A wrapper around an allowance mapping. */ contract AllowanceSheet is Ownable { using SafeMath for uint256; mapping (address => mapping (address => uint256)) public allowanceOf; function addAllowance(address _tokenHolder, address _spender, uint256 _value) public onlyOwner { allowanceOf[_tokenHolder][_spender] = allowanceOf[_tokenHolder][_spender].add(_value); } function subAllowance(address _tokenHolder, address _spender, uint256 _value) public onlyOwner { allowanceOf[_tokenHolder][_spender] = allowanceOf[_tokenHolder][_spender].sub(_value); } function setAllowance(address _tokenHolder, address _spender, uint256 _value) public onlyOwner { allowanceOf[_tokenHolder][_spender] = _value; } } // File: contracts/token/dataStorage/BalanceSheet.sol /** * @title BalanceSheet * @notice A wrapper around the balanceOf mapping. */ contract BalanceSheet is Ownable { using SafeMath for uint256; mapping (address => uint256) public balanceOf; uint256 public totalSupply; function addBalance(address _addr, uint256 _value) public onlyOwner { balanceOf[_addr] = balanceOf[_addr].add(_value); } function subBalance(address _addr, uint256 _value) public onlyOwner { balanceOf[_addr] = balanceOf[_addr].sub(_value); } function setBalance(address _addr, uint256 _value) public onlyOwner { balanceOf[_addr] = _value; } function addTotalSupply(uint256 _value) public onlyOwner { totalSupply = totalSupply.add(_value); } function subTotalSupply(uint256 _value) public onlyOwner { totalSupply = totalSupply.sub(_value); } function setTotalSupply(uint256 _value) public onlyOwner { totalSupply = _value; } } // File: contracts/token/dataStorage/TokenStorage.sol /** * @title TokenStorage */ contract TokenStorage { /** Storage */ BalanceSheet public balances; AllowanceSheet public allowances; string public name; //name of Token uint8 public decimals; //decimals of Token string public symbol; //Symbol of Token /** * @dev a TokenStorage consumer can set its storages only once, on construction * **/ constructor (address _balances, address _allowances, string _name, uint8 _decimals, string _symbol) public { balances = BalanceSheet(_balances); allowances = AllowanceSheet(_allowances); name = _name; decimals = _decimals; symbol = _symbol; } /** * @dev claim ownership of balance sheet passed into constructor. **/ function claimBalanceOwnership() public { balances.claimOwnership(); } /** * @dev claim ownership of allowance sheet passed into constructor. **/ function claimAllowanceOwnership() public { allowances.claimOwnership(); } } // File: zos-lib/contracts/upgradeability/Proxy.sol /** * @title Proxy * @dev Implements delegation of calls to other contracts, with proper * forwarding of return values and bubbling of failures. * It defines a fallback function that delegates all calls to the address * returned by the abstract _implementation() internal function. */ contract Proxy { /** * @dev Fallback function. * Implemented entirely in `_fallback`. */ function () payable external { _fallback(); } /** * @return The Address of the implementation. */ function _implementation() internal view returns (address); /** * @dev Delegates execution to an implementation contract. * This is a low level function that doesn't return to its internal call site. * It will return to the external caller whatever the implementation returns. * @param implementation Address to delegate. */ function _delegate(address implementation) internal { assembly { // Copy msg.data. We take full control of memory in this inline assembly // block because it will not return to Solidity code. We overwrite the // Solidity scratch pad at memory position 0. calldatacopy(0, 0, calldatasize) // Call the implementation. // out and outsize are 0 because we don't know the size yet. let result := delegatecall(gas, implementation, 0, calldatasize, 0, 0) // Copy the returned data. returndatacopy(0, 0, returndatasize) switch result // delegatecall returns 0 on error. case 0 { revert(0, returndatasize) } default { return(0, returndatasize) } } } /** * @dev Function that is run as the first thing in the fallback function. * Can be redefined in derived contracts to add functionality. * Redefinitions must call super._willFallback(). */ function _willFallback() internal { } /** * @dev fallback implementation. * Extracted to enable manual triggering. */ function _fallback() internal { _willFallback(); _delegate(_implementation()); } } // File: openzeppelin-solidity/contracts/AddressUtils.sol /** * Utility library of inline functions on addresses */ library AddressUtils { /** * Returns whether the target address is a contract * @dev This function will return false if invoked during the constructor of a contract, * as the code is not actually created until after the constructor finishes. * @param _addr address to check * @return whether the target address is a contract */ function isContract(address _addr) internal view returns (bool) { uint256 size; // XXX Currently there is no better way to check if there is a contract in an address // than to check the size of the code at that address. // See https://ethereum.stackexchange.com/a/14016/36603 // for more details about how this works. // TODO Check this again before the Serenity release, because all addresses will be // contracts then. // solium-disable-next-line security/no-inline-assembly assembly { size := extcodesize(_addr) } return size > 0; } } // File: zos-lib/contracts/upgradeability/UpgradeabilityProxy.sol /** * @title UpgradeabilityProxy * @dev This contract implements a proxy that allows to change the * implementation address to which it will delegate. * Such a change is called an implementation upgrade. */ contract UpgradeabilityProxy is Proxy { /** * @dev Emitted when the implementation is upgraded. * @param implementation Address of the new implementation. */ event Upgraded(address implementation); /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "org.zeppelinos.proxy.implementation", and is * validated in the constructor. */ bytes32 private constant IMPLEMENTATION_SLOT = 0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3; /** * @dev Contract constructor. * @param _implementation Address of the initial implementation. */ constructor(address _implementation) public { assert(IMPLEMENTATION_SLOT == keccak256("org.zeppelinos.proxy.implementation")); _setImplementation(_implementation); } /** * @dev Returns the current implementation. * @return Address of the current implementation */ function _implementation() internal view returns (address impl) { bytes32 slot = IMPLEMENTATION_SLOT; assembly { impl := sload(slot) } } /** * @dev Upgrades the proxy to a new implementation. * @param newImplementation Address of the new implementation. */ function _upgradeTo(address newImplementation) internal { _setImplementation(newImplementation); emit Upgraded(newImplementation); } /** * @dev Sets the implementation address of the proxy. * @param newImplementation Address of the new implementation. */ function _setImplementation(address newImplementation) private { require(AddressUtils.isContract(newImplementation), "Cannot set a proxy implementation to a non-contract address"); bytes32 slot = IMPLEMENTATION_SLOT; assembly { sstore(slot, newImplementation) } } } // File: contracts/token/TokenProxy.sol /** * @title TokenProxy * @notice A proxy contract that serves the latest implementation of TokenProxy. */ contract TokenProxy is UpgradeabilityProxy, TokenStorage, Ownable { constructor(address _implementation, address _balances, address _allowances, string _name, uint8 _decimals, string _symbol) UpgradeabilityProxy(_implementation) TokenStorage(_balances, _allowances, _name, _decimals, _symbol) public { } /** * @dev Upgrade the backing implementation of the proxy. * Only the admin can call this function. * @param newImplementation Address of the new implementation. */ function upgradeTo(address newImplementation) public onlyOwner { _upgradeTo(newImplementation); } /** * @return The address of the implementation. */ function implementation() public view returns (address) { return _implementation(); } }
File 2 of 2: AkropolisToken
pragma solidity >=0.4.24; /** * @title SafeMath * @dev Math operations with safety checks that throw on error */ library SafeMath { /** * @dev Multiplies two numbers, throws on overflow. */ function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c) { // Gas optimization: this is cheaper than asserting 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 if (_a == 0) { return 0; } c = _a * _b; assert(c / _a == _b); return c; } /** * @dev Integer division of two numbers, truncating the quotient. */ function div(uint256 _a, uint256 _b) internal pure 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 _a / _b; } /** * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). */ function sub(uint256 _a, uint256 _b) internal pure returns (uint256) { assert(_b <= _a); return _a - _b; } /** * @dev Adds two numbers, throws on overflow. */ function add(uint256 _a, uint256 _b) internal pure returns (uint256 c) { c = _a + _b; assert(c >= _a); return c; } } /** * @title Ownable * @dev The Ownable contract has an owner address, and provides basic authorization control * functions, this simplifies the implementation of "user permissions". This adds two-phase * ownership control to OpenZeppelin's Ownable class. In this model, the original owner * designates a new owner but does not actually transfer ownership. The new owner then accepts * ownership and completes the transfer. */ contract Ownable { address public owner; address public pendingOwner; event OwnershipTransferred( address indexed previousOwner, address indexed newOwner ); /** * @dev The Ownable constructor sets the original `owner` of the contract to the sender * account. */ constructor() public { owner = msg.sender; pendingOwner = address(0); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(msg.sender == owner, "Account is not owner"); _; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyPendingOwner() { require(msg.sender == pendingOwner, "Account is not pending 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) public onlyOwner { require(_newOwner != address(0), "Empty address"); pendingOwner = _newOwner; } /** * @dev Allows the pendingOwner address to finalize the transfer. */ function claimOwnership() onlyPendingOwner public { emit OwnershipTransferred(owner, pendingOwner); owner = pendingOwner; pendingOwner = address(0); } } /** * @title AllowanceSheet * @notice A wrapper around an allowance mapping. */ contract AllowanceSheet is Ownable { using SafeMath for uint256; mapping (address => mapping (address => uint256)) public allowanceOf; function addAllowance(address _tokenHolder, address _spender, uint256 _value) public onlyOwner { allowanceOf[_tokenHolder][_spender] = allowanceOf[_tokenHolder][_spender].add(_value); } function subAllowance(address _tokenHolder, address _spender, uint256 _value) public onlyOwner { allowanceOf[_tokenHolder][_spender] = allowanceOf[_tokenHolder][_spender].sub(_value); } function setAllowance(address _tokenHolder, address _spender, uint256 _value) public onlyOwner { allowanceOf[_tokenHolder][_spender] = _value; } } /** * @title BalanceSheet * @notice A wrapper around the balanceOf mapping. */ contract BalanceSheet is Ownable { using SafeMath for uint256; mapping (address => uint256) public balanceOf; uint256 public totalSupply; function addBalance(address _addr, uint256 _value) public onlyOwner { balanceOf[_addr] = balanceOf[_addr].add(_value); } function subBalance(address _addr, uint256 _value) public onlyOwner { balanceOf[_addr] = balanceOf[_addr].sub(_value); } function setBalance(address _addr, uint256 _value) public onlyOwner { balanceOf[_addr] = _value; } function addTotalSupply(uint256 _value) public onlyOwner { totalSupply = totalSupply.add(_value); } function subTotalSupply(uint256 _value) public onlyOwner { totalSupply = totalSupply.sub(_value); } function setTotalSupply(uint256 _value) public onlyOwner { totalSupply = _value; } } /** * @title TokenStorage */ contract TokenStorage { /** Storage */ BalanceSheet public balances; AllowanceSheet public allowances; string public name; //name of Token uint8 public decimals; //decimals of Token string public symbol; //Symbol of Token /** * @dev a TokenStorage consumer can set its storages only once, on construction * **/ constructor (address _balances, address _allowances, string _name, uint8 _decimals, string _symbol) public { balances = BalanceSheet(_balances); allowances = AllowanceSheet(_allowances); name = _name; decimals = _decimals; symbol = _symbol; } /** * @dev claim ownership of balance sheet passed into constructor. **/ function claimBalanceOwnership() public { balances.claimOwnership(); } /** * @dev claim ownership of allowance sheet passed into constructor. **/ function claimAllowanceOwnership() public { allowances.claimOwnership(); } } /** * Utility library of inline functions on addresses */ library AddressUtils { /** * Returns whether the target address is a contract * @dev This function will return false if invoked during the constructor of a contract, * as the code is not actually created until after the constructor finishes. * @param _addr address to check * @return whether the target address is a contract */ function isContract(address _addr) internal view returns (bool) { uint256 size; // XXX Currently there is no better way to check if there is a contract in an address // than to check the size of the code at that address. // See https://ethereum.stackexchange.com/a/14016/36603 // for more details about how this works. // TODO Check this again before the Serenity release, because all addresses will be // contracts then. // solium-disable-next-line security/no-inline-assembly assembly { size := extcodesize(_addr) } return size > 0; } } /** * @title ERC20Basic * @dev Simpler version of ERC20 interface * See https://github.com/ethereum/EIPs/issues/179 */ contract ERC20Basic { function totalSupply() public view returns (uint256); function balanceOf(address _who) public view returns (uint256); function transfer(address _to, uint256 _value) public returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); } /** * @title ERC20 interface * @dev see https://github.com/ethereum/EIPs/issues/20 */ contract ERC20 is ERC20Basic { function allowance(address _owner, address _spender) public view 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 ); } /** * @title AkropolisBaseToken * @notice A basic ERC20 token with modular data storage */ contract AkropolisBaseToken is ERC20, TokenStorage, Ownable { using SafeMath for uint256; /** Events */ event Mint(address indexed to, uint256 value); event MintFinished(); event MintStarted(); event Burn(address indexed burner, uint256 value); event Transfer(address indexed from, address indexed to, uint256 value); event Approval( address indexed owner, address indexed spender, uint256 value ); constructor( address _balances, address _allowances, string _name, uint8 _decimals, string _symbol ) public TokenStorage(_balances, _allowances, _name, _decimals, _symbol) {} /** Modifiers **/ modifier canMint() { require(!isMintingFinished()); _; } /** Functions **/ function mint(address _to, uint256 _amount) public onlyOwner canMint { _mint(_to, _amount); } function burn(uint256 _amount) public onlyOwner { _burn(msg.sender, _amount); } function isMintingFinished() public view returns (bool) { bytes32 slot = keccak256(abi.encode("Minting", "mint")); uint256 v; assembly { v := sload(slot) } return v != 0; } function setMintingFinished(bool value) internal { bytes32 slot = keccak256(abi.encode("Minting", "mint")); uint256 v = value ? 1 : 0; assembly { sstore(slot, v) } } function mintFinished() public onlyOwner { setMintingFinished(true); emit MintFinished(); } function mintStarted() public onlyOwner { setMintingFinished(false); emit MintStarted(); } function approve(address _spender, uint256 _value) public returns (bool) { allowances.setAllowance(msg.sender, _spender, _value); emit Approval(msg.sender, _spender, _value); return true; } function transfer(address _to, uint256 _amount) public returns (bool) { require(_to != address(0), "to address cannot be 0x0"); require( _amount <= balanceOf(msg.sender), "not enough balance to transfer" ); balances.subBalance(msg.sender, _amount); balances.addBalance(_to, _amount); emit Transfer(msg.sender, _to, _amount); return true; } function transferFrom( address _from, address _to, uint256 _amount ) public returns (bool) { require( _amount <= allowance(_from, msg.sender), "not enough allowance to transfer" ); require(_to != address(0), "to address cannot be 0x0"); require(_amount <= balanceOf(_from), "not enough balance to transfer"); allowances.subAllowance(_from, msg.sender, _amount); balances.addBalance(_to, _amount); balances.subBalance(_from, _amount); emit Transfer(_from, _to, _amount); return true; } /** * @notice Implements balanceOf() as specified in the ERC20 standard. */ function balanceOf(address who) public view returns (uint256) { return balances.balanceOf(who); } /** * @notice Implements allowance() as specified in the ERC20 standard. */ function allowance(address owner, address spender) public view returns (uint256) { return allowances.allowanceOf(owner, spender); } /** * @notice Implements totalSupply() as specified in the ERC20 standard. */ function totalSupply() public view returns (uint256) { return balances.totalSupply(); } /** Internal functions **/ function _burn(address _tokensOf, uint256 _amount) internal { require(_amount <= balanceOf(_tokensOf), "not enough balance to burn"); // no need to require value <= totalSupply, since that would imply the // sender's balance is greater than the totalSupply, which *should* be an assertion failure balances.subBalance(_tokensOf, _amount); balances.subTotalSupply(_amount); emit Burn(_tokensOf, _amount); emit Transfer(_tokensOf, address(0), _amount); } function _mint(address _to, uint256 _amount) internal { balances.addTotalSupply(_amount); balances.addBalance(_to, _amount); emit Mint(_to, _amount); emit Transfer(address(0), _to, _amount); } } /** * @title Lockable * @dev Base contract which allows children to lock certain methods from being called by clients. * Locked methods are deemed unsafe by default, but must be implemented in children functionality to adhere by * some inherited standard, for example. */ contract Lockable is Ownable { // Events event Unlocked(); event Locked(); // Modifiers /** * @dev Modifier that disables functions by default unless they are explicitly enabled */ modifier whenUnlocked() { require(!isLocked(), "Contact is locked"); _; } /** * @dev called by the owner to disable method, back to normal state */ function lock() public onlyOwner { setLock(true); emit Locked(); } // Methods /** * @dev called by the owner to enable method */ function unlock() public onlyOwner { setLock(false); emit Unlocked(); } function setLock(bool value) internal { bytes32 slot = keccak256(abi.encode("Lockable", "lock")); uint256 v = value ? 1 : 0; assembly { sstore(slot, v) } } function isLocked() public view returns (bool) { bytes32 slot = keccak256(abi.encode("Lockable", "lock")); uint256 v; assembly { v := sload(slot) } return v != 0; } } /** * @title Pausable * @dev Base contract which allows children to implement an emergency stop mechanism. Identical to OpenZeppelin version * except that it uses local Ownable contract */ contract Pausable is Ownable { event Pause(); event Unpause(); /** * @dev Modifier to make a function callable only when the contract is not paused. */ modifier whenNotPaused() { require(!isPaused(), "Contract is paused"); _; } /** * @dev Modifier to make a function callable only when the contract is paused. */ modifier whenPaused() { require(isPaused(), "Contract is not paused"); _; } /** * @dev called by the owner to pause, triggers stopped state */ function pause() public onlyOwner whenNotPaused { setPause(true); emit Pause(); } /** * @dev called by the owner to unpause, returns to normal state */ function unpause() public onlyOwner whenPaused { setPause(false); emit Unpause(); } function setPause(bool value) internal { bytes32 slot = keccak256(abi.encode("Pausable", "pause")); uint256 v = value ? 1 : 0; assembly { sstore(slot, v) } } function isPaused() public view returns (bool) { bytes32 slot = keccak256(abi.encode("Pausable", "pause")); uint256 v; assembly { v := sload(slot) } return v != 0; } } /** * @title Whitelist * @dev Base contract which allows children to implement an emergency whitelist mechanism. Identical to OpenZeppelin version * except that it uses local Ownable contract */ contract Whitelist is Ownable { event AddToWhitelist(address indexed to); event RemoveFromWhitelist(address indexed to); event EnableWhitelist(); event DisableWhitelist(); event AddPermBalanceToWhitelist(address indexed to, uint256 balance); event RemovePermBalanceToWhitelist(address indexed to); mapping(address => bool) internal whitelist; mapping (address => uint256) internal permBalancesForWhitelist; /** * @dev Modifier to make a function callable only when msg.sender is in whitelist. */ modifier onlyWhitelist() { if (isWhitelisted() == true) { require(whitelist[msg.sender] == true, "Address is not in whitelist"); } _; } /** * @dev Modifier to make a function callable only when msg.sender is in permitted balance */ modifier checkPermBalanceForWhitelist(uint256 value) { if (isWhitelisted() == true) { require(permBalancesForWhitelist[msg.sender]==0 || permBalancesForWhitelist[msg.sender]>=value, "Not permitted balance for transfer"); } _; } /** * @dev called by the owner to set permitted balance for transfer */ function addPermBalanceToWhitelist(address _owner, uint256 _balance) public onlyOwner { permBalancesForWhitelist[_owner] = _balance; emit AddPermBalanceToWhitelist(_owner, _balance); } /** * @dev called by the owner to remove permitted balance for transfer */ function removePermBalanceToWhitelist(address _owner) public onlyOwner { permBalancesForWhitelist[_owner] = 0; emit RemovePermBalanceToWhitelist(_owner); } /** * @dev called by the owner to enable whitelist */ function enableWhitelist() public onlyOwner { setWhitelisted(true); emit EnableWhitelist(); } /** * @dev called by the owner to disable whitelist */ function disableWhitelist() public onlyOwner { setWhitelisted(false); emit DisableWhitelist(); } /** * @dev called by the owner to enable some address for whitelist */ function addToWhitelist(address _address) public onlyOwner { whitelist[_address] = true; emit AddToWhitelist(_address); } /** * @dev called by the owner to disable address for whitelist */ function removeFromWhitelist(address _address) public onlyOwner { whitelist[_address] = false; emit RemoveFromWhitelist(_address); } // bool public whitelisted = false; function setWhitelisted(bool value) internal { bytes32 slot = keccak256(abi.encode("Whitelist", "whitelisted")); uint256 v = value ? 1 : 0; assembly { sstore(slot, v) } } function isWhitelisted() public view returns (bool) { bytes32 slot = keccak256(abi.encode("Whitelist", "whitelisted")); uint256 v; assembly { v := sload(slot) } return v != 0; } } /** * @title blacklist * @dev Base contract which allows children to implement an emergency blacklist mechanism. Identical to OpenZeppelin version * except that it uses local Ownable contract */ contract Blacklist is Ownable { event AddToBlacklist(address indexed to); event RemoveFromBlacklist(address indexed to); event EnableBlacklist(); event DisableBlacklist(); event RemovePermBalanceToblacklist(address indexed to); mapping(address => bool) internal blacklist; /** * @dev Modifier to make a function callable only when msg.sender is in not blacklist. */ modifier notForBlacklist(address account) { if (isBlacklisted() == true) { require(blacklist[account] == false, "Address is in blacklist"); } _; } /** * @dev Modifier to make a function callable only when msg.sender is in not blacklist. */ modifier forBlacklist(address account) { if (isBlacklisted() == true) { require(blacklist[account] == true, "Address is not in blacklist"); } _; } /** * @dev called by the owner to enable blacklist */ function enableBlacklist() public onlyOwner { setBlacklisted(true); emit EnableBlacklist(); } /** * @dev called by the owner to disable blacklist */ function disableBlacklist() public onlyOwner { setBlacklisted(false); emit DisableBlacklist(); } /** * @dev called by the owner to enable some address for blacklist */ function addToBlacklist(address _address) public onlyOwner { blacklist[_address] = true; emit AddToBlacklist(_address); } /** * @dev called by the owner to disable address for blacklist */ function removeFromblacklist(address _address) public onlyOwner { blacklist[_address] = false; emit RemoveFromBlacklist(_address); } // bool public blacklisted = false; function setBlacklisted(bool value) internal { bytes32 slot = keccak256(abi.encode("Blacklist", "blacklisted")); uint256 v = value ? 1 : 0; assembly { sstore(slot, v) } } function isBlacklisted() public view returns (bool) { bytes32 slot = keccak256(abi.encode("Blacklist", "blacklisted")); uint256 v; assembly { v := sload(slot) } return v != 0; } } /** * @title AkropolisToken * @notice Adds pausability and disables approve() to defend against double-spend attacks in addition * to inherited AkropolisBaseToken behavior */ contract AkropolisToken is AkropolisBaseToken, Pausable, Lockable, Whitelist, Blacklist { using SafeMath for uint256; /** Events */ constructor (address _balances, address _allowances, string _name, uint8 _decimals, string _symbol) public AkropolisBaseToken(_balances, _allowances, _name, _decimals, _symbol) {} /** Modifiers **/ /** Functions **/ function mint(address _to, uint256 _amount) public { super.mint(_to, _amount); } function burn(uint256 _amount) public whenUnlocked { super.burn(_amount); } /** * @notice Implements ERC-20 standard approve function. * double spend attacks. To modify allowances, clients should call safer increase/decreaseApproval methods. * Upon construction, all calls to approve() will revert unless this contract owner explicitly unlocks approve() */ function approve(address _spender, uint256 _value) public whenNotPaused whenUnlocked returns (bool) { return super.approve(_spender, _value); } /** * @dev Increase the amount of tokens that an owner allowed to a spender. * @notice increaseApproval should be used instead of approve when the user's allowance * is greater than 0. Using increaseApproval protects against potential double-spend attacks * by moving the check of whether the user has spent their allowance to the time that the transaction * is mined, removing the user's ability to double-spend * @param _spender The address which will spend the funds. * @param _addedValue The amount of tokens to increase the allowance by. */ function increaseApproval(address _spender, uint256 _addedValue) public whenNotPaused returns (bool) { increaseApprovalAllArgs(_spender, _addedValue, msg.sender); return true; } /** * @dev Decrease the amount of tokens that an owner allowed to a spender. * @notice decreaseApproval should be used instead of approve when the user's allowance * is greater than 0. Using decreaseApproval protects against potential double-spend attacks * by moving the check of whether the user has spent their allowance to the time that the transaction * is mined, removing the user's ability to double-spend * @param _spender The address which will spend the funds. * @param _subtractedValue The amount of tokens to decrease the allowance by. */ function decreaseApproval(address _spender, uint256 _subtractedValue) public whenNotPaused returns (bool) { decreaseApprovalAllArgs(_spender, _subtractedValue, msg.sender); return true; } function transfer(address _to, uint256 _amount) public whenNotPaused onlyWhitelist notForBlacklist(msg.sender) returns (bool) { return super.transfer(_to, _amount); } /** * @notice Initiates a transfer operation between address `_from` and `_to`. Requires that the * message sender is an approved spender on the _from account. * @dev When implemented, it should use the transferFromConditionsRequired() modifier. * @param _to The address of the recipient. This address must not be blacklisted. * @param _from The address of the origin of funds. This address _could_ be blacklisted, because * a regulator may want to transfer tokens out of a blacklisted account, for example. * In order to do so, the regulator would have to add themselves as an approved spender * on the account via `addBlacklistAddressSpender()`, and would then be able to transfer tokens out of it. * @param _amount The number of tokens to transfer * @return `true` if successful */ function transferFrom(address _from, address _to, uint256 _amount) public whenNotPaused onlyWhitelist notForBlacklist(_from) returns (bool) { return super.transferFrom(_from, _to, _amount); } /** Internal functions **/ function decreaseApprovalAllArgs(address _spender, uint256 _subtractedValue, address _tokenHolder) internal { uint256 oldValue = allowances.allowanceOf(_tokenHolder, _spender); if (_subtractedValue > oldValue) { allowances.setAllowance(_tokenHolder, _spender, 0); } else { allowances.subAllowance(_tokenHolder, _spender, _subtractedValue); } emit Approval(_tokenHolder, _spender, allowances.allowanceOf(_tokenHolder, _spender)); } function increaseApprovalAllArgs(address _spender, uint256 _addedValue, address _tokenHolder) internal { allowances.addAllowance(_tokenHolder, _spender, _addedValue); emit Approval(_tokenHolder, _spender, allowances.allowanceOf(_tokenHolder, _spender)); } }