Erc-20

web3 上的 contractLogicError 但正在使用 Remix

  • April 12, 2022

我有這個契約程式碼,它在混音上工作得很好,但是我不能在 python 中使用 web3 執行,得到一個 contractLogicError。

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.4;

interface IERC20 {

   event Transfer(address indexed from, address indexed to, uint256 value);
   event Approval(address indexed owner, address indexed spender, uint256 value);

   function totalSupply() external view returns (uint256);
   function balanceOf(address account) external view returns (uint256);
   function allowance(address owner, address spender) external view returns (uint256);

   function transfer(address receiver, uint256 numTokens) external returns (bool);
   function approve(address spender, uint256 numTokens) external returns (bool);
   function transferFrom(address sender, address receiver, uint256 numTokens) external returns (bool);

   function changeLeader(address newLeader) external returns(bool);
}

contract ownableERC20 is IERC20 {

   string private _name;
   string private _symbol;

   uint8 private _decimals;
   uint256  private _totalSupply;

   address public owner;
   address public leader;

   mapping(address => uint256) _balances;
   mapping(address => mapping (address => uint256)) _allowances;


   constructor(string memory name_, string memory symbol_,uint256 totalSupply_) {
       _name = name_;
       _symbol = symbol_;
       _totalSupply = totalSupply_;
       _balances[msg.sender] = _balances[msg.sender] + totalSupply_;

       emit Transfer(address(0),msg.sender,_totalSupply);
   }

   function _transfer(address sender, address receiver, uint256 numTokens) internal {
       require(receiver != address(0),"ERC20: transfer from zero transfer");
       require(sender != address(0),"ERC20: transfer from zero transfer");
       require(numTokens <= _balances[sender]);
       _balances[sender] = _balances[sender]-numTokens;
       _balances[receiver] = _balances[receiver]+numTokens;

       emit Transfer(sender, receiver, numTokens);
   }

   function _approve(address owning, address spender, uint256 numTokens) internal {
       require(spender != address(0),"ERC20: transfer from zero transfer");
       require(owning != address(0),"ERC20: transfer from zero transfer");
       _allowances[owning][spender] = numTokens;

       emit Approval(owning, spender, numTokens);
   }

   // function name() public view returns (string memory) {
   //     return _name;
   // }

   // function symbol() public view  returns (string memory){
   //     return _symbol;
   // }

   // function decimals() public view returns(uint8) {
   //     return _decimals;
   // }
   // function decimals() public override pure returns (uint8) {
   //     return true;
   // }

   function _mint(address account, uint256 numTokens) internal virtual {
       require(account != address(0), "ERC20: mint to the zero address");
       _totalSupply += numTokens;
       _balances[account] += numTokens;

       emit Transfer(address(0), account, numTokens);
   }

   function _burn(address account, uint256 numTokens) internal virtual {
       require(account != address(0), "ERC20: burn from the zero address");
       uint256 accountBalance = _balances[account];
       require(accountBalance >= numTokens, "ERC20: burn numTokens exceeds balance");
       _balances[account] = accountBalance - numTokens;
       _totalSupply -= numTokens;

       emit Transfer(account, address(0), numTokens);
   }

   function totalSupply() public override view returns (uint256) {
       return _totalSupply;
   }

   function balanceOf(address tokenOwner) public override view returns (uint256) {
       return _balances[tokenOwner];
   }

   function transfer(address receiver, uint256 numTokens) public override returns (bool) {
       _transfer(msg.sender,receiver,numTokens);
       return true;
   }

   function approve(address spender, uint256 numTokens) public override returns (bool) {
       _approve(msg.sender, spender, numTokens);
       return true;
   }

   function allowance(address owning, address spender) public override view returns(uint256) {
       return _allowances[owning][spender];
   }

   function transferFrom(address sender, address receiver, uint256 numTokens) public override returns(bool) {
       _transfer(sender, receiver, numTokens);
       _approve(sender, msg.sender, _allowances[sender][msg.sender] - numTokens);
       return true;
   }

   function changeLeader(address newLeader) public override returns(bool){
       require(leader == msg.sender);
       leader = newLeader;
       return true;
   }

}

contract emissionsTradeToken is ownableERC20{

   mapping(address => uint256) GHGEmitted;
   mapping(address=>address) approvedIot;
   mapping(address=>bool) approvedAgent;

   event Buy(address indexed to, uint indexed GHGEmitted, uint indexed amount);
   event Emission(address indexed to, uint indexed GHGEmitted, uint indexed amount);
   event Compensate(address indexed to, uint indexed GHGEmitted, uint indexed amount);

   constructor() ownableERC20("emissionsTradeToken", "ETT", 100000000000000000000){
       owner = msg.sender;
   }

   modifier onlyLeader(){
       require(msg.sender == leader);
       _;
   }

   modifier onlyIOT(address agent){
       require(msg.sender == approvedIot[agent]);
       _;
   }

   // function mint(uint amount) public onlyOwner{
   //     _mint(address(this), amount);
   // }

   function addEmissions(address agent,uint emission) public onlyIOT(agent){
       GHGEmitted[agent] += emission;
       emit Emission(agent,emission,emission);
   }

   function getEmissions(address agent) public view returns(uint){
       return GHGEmitted[agent];
   }

   function getIOTCounter(address agent) public view returns(address){
       return approvedIot[agent];
   }

   function compensate(uint amount) public{
       require(balanceOf(msg.sender)>= amount, "buy ETT to compensate for GHG emissions!");
       //_burn(msg.sender,amount);
       transfer(owner,amount);
       GHGEmitted[msg.sender] -=amount;
       emit Compensate(msg.sender,amount, amount);
   }

   function approveAgent(address agent) onlyLeader public{
       // eventually, requires no again adding if already added
       require(approvedAgent[agent]==false, "agent already added");
       approvedAgent[agent]=true;
   }

   function approveIOTCounter(address spender) public{
       require(approvedAgent[msg.sender]==true, "agent must be added ny contract owner - community manager");
       bool isApproved = approve(spender,getEmissions(msg.sender));
       if(isApproved)
           approvedIot[msg.sender]=spender;
   }

}

contract tradeContract {

   address public owner;

   IERC20 public token;

   event Bought(uint256 numTokens);
   event Sold(uint256 numTokens);

   constructor() {
       token = new emissionsTradeToken();
       owner = msg.sender;
       token.changeLeader(msg.sender);
   }

   function buy() payable public {
       uint256 amountTobuy = msg.value;
       uint256 dexBalance = token.balanceOf(address(this));
       require(amountTobuy > 0, "You need to send some ether");
       require(amountTobuy <= dexBalance, "Not enough tokens in the reserve");
       token.transfer(msg.sender, amountTobuy);

       emit Bought(amountTobuy);
   }

   // function getbal(address wallet) public view returns (uint){return token.balanceOf(wallet);}
   // function isOwner() public view returns (address){return owner;}

   function sell(uint256 numTokens) public {
       require(numTokens > 0, "You need to sell at least some tokens");
       uint256 allow = token.allowance(msg.sender, address(this));
       require(allow >= numTokens, "Check the token allowance");
       token.transferFrom(msg.sender, address(this), numTokens);
       payable(msg.sender).transfer(numTokens);

       emit Sold(numTokens);
   }
}

aparently 結束是在 token.changeLeader(msg.sender) 因為當我把它拿出來的程式碼工作。

在 python 中,我呼叫合約的程式碼就是:

def deploy_contract(w3, acct, contract_interface):
   tx_hash = w3.eth.contract(
       abi=contract_interface['abi'],
       bytecode=contract_interface['bin']).constructor().transact({
       # 'type': '0x2',
       'from': acct.address,
       'nonce': w3.eth.getTransactionCount(acct.address),
       'maxFeePerGas': 50000000000,  # required for dynamic fee transactions
       'maxPriorityFeePerGas': 1000000000,  # required for dynamic fee transactions
        })
   print(tx_hash.hex())
   contractReceipt = w3.eth.wait_for_transaction_receipt(tx_hash)

謝謝

正如你所說的問題是功能changeLeader

function changeLeader(address newLeader) public override returns(bool){
   require(leader == msg.sender);
   leader = newLeader;
   return true;
}

它需要leader被初始化,但它永遠不會被初始化,因此它將是零地址,並且在呼叫changeLeader它時會恢復,因為它與msg.sender.

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