Ethereumjs

transferFrom 功能在 ICO 智能合約中不起作用

  • August 9, 2019

transferFrom遇到了智能合約地址 0x6560a9b6436e129cf835ab9da96201207facd4f8 的功能問題:

  1. 我從 etherscan.io 複製了智能合約程式碼並部署在 ropsten 網路上。當我部署它時,我發現生成的令牌與部署它的地址有關。它應該是智能合約的地址。
  2. transferFrom當我試圖將令牌從一個地址轉移到另一個地址時,函式不起作用並引發異常錯誤,即使這兩個帳戶都允許使用給定數量的令牌。

/**
*Submitted for verification at Etherscan.io on 2018-10-11
*/

pragma solidity ^0.4.24;

// openzeppelin-solidity: 1.12.0-rc.2

/**
* @title Ownable
* @dev The Ownable contract has an owner address, and provides basic authorization control
* functions, this simplifies the implementation of "user permissions".
*/
contract Ownable {
 address public owner;


 event OwnershipRenounced(address indexed previousOwner);
 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;
 }

 /**
  * @dev Throws if called by any account other than the owner.
  */
 modifier onlyOwner() {
   require(msg.sender == owner);
   _;
 }

 /**
  * @dev Allows the current owner to relinquish control of the contract.
  * @notice Renouncing to ownership will leave the contract without an owner.
  * It will not be possible to call the functions with the `onlyOwner`
  * modifier anymore.
  */
 function renounceOwnership() public onlyOwner {
   emit OwnershipRenounced(owner);
   owner = address(0);
 }

 /**
  * @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 {
   _transferOwnership(_newOwner);
 }

 /**
  * @dev Transfers control of the contract to a newOwner.
  * @param _newOwner The address to transfer ownership to.
  */
 function _transferOwnership(address _newOwner) internal {
   require(_newOwner != address(0));
   emit OwnershipTransferred(owner, _newOwner);
   owner = _newOwner;
 }
}

/**
* @title Pausable
* @dev Base contract which allows children to implement an emergency stop mechanism.
*/
contract Pausable is Ownable {
 event Pause();
 event Unpause();

 bool public paused = false;


 /**
  * @dev Modifier to make a function callable only when the contract is not paused.
  */
 modifier whenNotPaused() {
   require(!paused);
   _;
 }

 /**
  * @dev Modifier to make a function callable only when the contract is paused.
  */
 modifier whenPaused() {
   require(paused);
   _;
 }

 /**
  * @dev called by the owner to pause, triggers stopped state
  */
 function pause() public onlyOwner whenNotPaused {
   paused = true;
   emit Pause();
 }

 /**
  * @dev called by the owner to unpause, returns to normal state
  */
 function unpause() public onlyOwner whenPaused {
   paused = false;
   emit Unpause();
 }
}

/**
* @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 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 Basic token
* @dev Basic version of StandardToken, with no allowances.
*/
contract BasicToken is ERC20Basic {
 using SafeMath for uint256;

 mapping(address => uint256) internal balances;

 uint256 internal totalSupply_;

 /**
 * @dev Total number of tokens in existence
 */
 function totalSupply() public view returns (uint256) {
   return totalSupply_;
 }

 /**
 * @dev Transfer token for a specified address
 * @param _to The address to transfer to.
 * @param _value The amount to be transferred.
 */
 function transfer(address _to, uint256 _value) public returns (bool) {
   require(_value <= balances[msg.sender]);
   require(_to != address(0));

   balances[msg.sender] = balances[msg.sender].sub(_value);
   balances[_to] = balances[_to].add(_value);
   emit Transfer(msg.sender, _to, _value);
   return true;
 }

 /**
 * @dev Gets the balance of the specified address.
 * @param _owner The address to query the the balance of.
 * @return An uint256 representing the amount owned by the passed address.
 */
 function balanceOf(address _owner) public view returns (uint256) {
   return balances[_owner];
 }

}

/**
* @title Standard ERC20 token
*
* @dev Implementation of the basic standard token.
* https://github.com/ethereum/EIPs/issues/20
* Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
*/
contract StandardToken is ERC20, BasicToken {

 mapping (address => mapping (address => uint256)) internal allowed;


 /**
  * @dev Transfer tokens from one address to another
  * @param _from address The address which you want to send tokens from
  * @param _to address The address which you want to transfer to
  * @param _value uint256 the amount of tokens to be transferred
  */
 function transferFrom(
   address _from,
   address _to,
   uint256 _value
 )
   public
   returns (bool)
 {
   require(_value <= balances[_from]);
   require(_value <= allowed[_from][msg.sender]);
   require(_to != address(0));

   balances[_from] = balances[_from].sub(_value);
   balances[_to] = balances[_to].add(_value);
   allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
   emit Transfer(_from, _to, _value);
   return true;
 }

 /**
  * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
  * Beware that changing an allowance with this method brings the risk that someone may use both the old
  * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
  * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
  * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
  * @param _spender The address which will spend the funds.
  * @param _value The amount of tokens to be spent.
  */
 function approve(address _spender, uint256 _value) public returns (bool) {
   allowed[msg.sender][_spender] = _value;
   emit Approval(msg.sender, _spender, _value);
   return true;
 }

 /**
  * @dev Function to check the amount of tokens that an owner allowed to a spender.
  * @param _owner address The address which owns the funds.
  * @param _spender address The address which will spend the funds.
  * @return A uint256 specifying the amount of tokens still available for the spender.
  */
 function allowance(
   address _owner,
   address _spender
  )
   public
   view
   returns (uint256)
 {
   return allowed[_owner][_spender];
 }

 /**
  * @dev Increase the amount of tokens that an owner allowed to a spender.
  * approve should be called when allowed[_spender] == 0. To increment
  * allowed value is better to use this function to avoid 2 calls (and wait until
  * the first transaction is mined)
  * From MonolithDAO Token.sol
  * @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
   returns (bool)
 {
   allowed[msg.sender][_spender] = (
     allowed[msg.sender][_spender].add(_addedValue));
   emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
   return true;
 }

 /**
  * @dev Decrease the amount of tokens that an owner allowed to a spender.
  * approve should be called when allowed[_spender] == 0. To decrement
  * allowed value is better to use this function to avoid 2 calls (and wait until
  * the first transaction is mined)
  * From MonolithDAO Token.sol
  * @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
   returns (bool)
 {
   uint256 oldValue = allowed[msg.sender][_spender];
   if (_subtractedValue >= oldValue) {
     allowed[msg.sender][_spender] = 0;
   } else {
     allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
   }
   emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
   return true;
 }

}

/**
* @title Pausable token
* @dev StandardToken modified with pausable transfers.
**/
contract PausableToken is StandardToken, Pausable {

 function transfer(
   address _to,
   uint256 _value
 )
   public
   whenNotPaused
   returns (bool)
 {
   return super.transfer(_to, _value);
 }

 function transferFrom(
   address _from,
   address _to,
   uint256 _value
 )
   public
   whenNotPaused
   returns (bool)
 {
   return super.transferFrom(_from, _to, _value);
 }

 function approve(
   address _spender,
   uint256 _value
 )
   public
   whenNotPaused
   returns (bool)
 {
   return super.approve(_spender, _value);
 }

 function increaseApproval(
   address _spender,
   uint _addedValue
 )
   public
   whenNotPaused
   returns (bool success)
 {
   return super.increaseApproval(_spender, _addedValue);
 }

 function decreaseApproval(
   address _spender,
   uint _subtractedValue
 )
   public
   whenNotPaused
   returns (bool success)
 {
   return super.decreaseApproval(_spender, _subtractedValue);
 }
}

/**
* @title Burnable Token
* @dev Token that can be irreversibly burned (destroyed).
*/
contract BurnableToken is BasicToken {

 event Burn(address indexed burner, uint256 value);

 /**
  * @dev Burns a specific amount of tokens.
  * @param _value The amount of token to be burned.
  */
 function burn(uint256 _value) public {
   _burn(msg.sender, _value);
 }

 function _burn(address _who, uint256 _value) internal {
   require(_value <= balances[_who]);
   // 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[_who] = balances[_who].sub(_value);
   totalSupply_ = totalSupply_.sub(_value);
   emit Burn(_who, _value);
   emit Transfer(_who, address(0), _value);
 }
}

/**
* @title Standard Burnable Token
* @dev Adds burnFrom method to ERC20 implementations
*/
contract StandardBurnableToken is BurnableToken, StandardToken {

 /**
  * @dev Burns a specific amount of tokens from the target address and decrements allowance
  * @param _from address The address which you want to send tokens from
  * @param _value uint256 The amount of token to be burned
  */
 function burnFrom(address _from, uint256 _value) public {
   require(_value <= allowed[_from][msg.sender]);
   // Should https://github.com/OpenZeppelin/zeppelin-solidity/issues/707 be accepted,
   // this function needs to emit an event with the updated approval.
   allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
   _burn(_from, _value);
 }
}

contract KratosToken is StandardBurnableToken, PausableToken {

   string constant public name = "KRATOS";
   string constant public symbol = "TOS";
   uint8 constant public decimals = 18;

   uint256 public timelockTimestamp = 0;
   mapping(address => uint256) public timelock;

   constructor(uint256 _totalSupply) public {
       // constructor
       totalSupply_ = _totalSupply;
       balances[msg.sender] = _totalSupply;
   }

   event TimeLocked(address indexed _beneficary, uint256 _timestamp);
   event TimeUnlocked(address indexed _beneficary);

   /**
   * @dev Modifier to make a function callable only when the contract is not timelocked or timelock expired.
   */
   modifier whenNotTimelocked(address _beneficary) {
       require(timelock[_beneficary] <= block.timestamp);
       _;
   }

   /**
   * @dev Modifier to make a function callable only when the contract is timelocked and not expired.
   */
   modifier whenTimelocked(address _beneficary) {
       require(timelock[_beneficary] > block.timestamp);
       _;
   }

   function enableTimelock(uint256 _timelockTimestamp) onlyOwner public {
       require(timelockTimestamp == 0 || _timelockTimestamp > block.timestamp);
       timelockTimestamp = _timelockTimestamp;
   }

   function disableTimelock() onlyOwner public {
       timelockTimestamp = 0;
   }

   /**
   * @dev called by the owner to timelock token belonging to beneficary
   */
   function addTimelock(address _beneficary, uint256 _timestamp) public onlyOwner {
       _addTimelock(_beneficary, _timestamp);
   }

   function _addTimelock(address _beneficary, uint256 _timestamp) internal whenNotTimelocked(_beneficary) {
       require(_timestamp > block.timestamp);
       timelock[_beneficary] = _timestamp;
       emit TimeLocked(_beneficary, _timestamp);
   }

   /**
   * @dev called by the owner to timeunlock token belonging to beneficary
   */
   function removeTimelock(address _beneficary) onlyOwner whenTimelocked(_beneficary) public {
       timelock[_beneficary] = 0;
       emit TimeUnlocked(_beneficary);
   }

   function transfer(address _to, uint256 _value) public whenNotTimelocked(msg.sender) returns (bool) {
       if (timelockTimestamp > block.timestamp)
           _addTimelock(_to, timelockTimestamp);
       return super.transfer(_to, _value);
   }

   function transferFrom(address _from, address _to, uint256 _value) public whenNotTimelocked(_from) returns (bool) {
       if (timelockTimestamp > block.timestamp)
           _addTimelock(_to, timelockTimestamp);
       return super.transferFrom(_from, _to, _value);
   }

   function approve(address _spender, uint256 _value) public whenNotTimelocked(_spender) returns (bool) {
       return super.approve(_spender, _value);
   }

   function increaseApproval(address _spender, uint _addedValue) public whenNotTimelocked(_spender) returns (bool success) {
       return super.increaseApproval(_spender, _addedValue);
   }

   function decreaseApproval(address _spender, uint _subtractedValue) public whenNotTimelocked(_spender) returns (bool success) {
       return super.decreaseApproval(_spender, _subtractedValue);
   }
}

失敗了transferFrom,我想,因為require(_value <= allowed[_from][msg.sender]);

您是否首先approve從地址msg.sender轉移代幣?_from在第三方需要將您的代幣轉移給其他人的情況下,您必須首先允許第三方使用您的一定數量的代幣,以便他可以代表您使用它。對於這種情況,有transferFrom. 這意味著,您必須首先approve將一定數量的代幣交給第三方spender

但是,如果您是第一方願意將代幣直接轉移給第二方,那麼您需要致電transfer(address _to, uint256 _value)

我發現生成的令牌與部署它的地址有關

代幣合約通常將總供應量分配給合約部署者,因此這是正常的。代幣合約是一個分類帳,通常不是資產的所有者,因此將創建的供應分配給應該知道下一步是什麼的部署者是明智的。

transferFrom 功能不起作用

它可能會。更有可能的是,您試圖用它做的事情在設計上是不允許的。這可能是契約正常運作的證據。transferFrom()經常被誤解,因此請考慮發布您的測試方法。

https://ethereum.stackexchange.com/search?tab=votes&q=transferFrom

希望能幫助到你。

引用自:https://ethereum.stackexchange.com/questions/73740