0

I'm quite new at smart contracts/Solidity, which I'm learning for a postgraduate course.

In one of the assignments, we have to implement a little competitive game (something like the game of Seven Kingdoms). The main goal of puzzle is to be king and not be overthrow.

The contract of the SevenKingdoms

pragma solidity 0.5.0;

 contract SevenKingdoms {

  address payable public owner;
  address payable public king;
  uint public price;

  constructor(string memory _token) public payable {
    owner = msg.sender;
    king = msg.sender;
    price = msg.value;
  }

  function() external payable {
    require(msg.value > price);
    king.transfer(msg.value);
    king = msg.sender;
    price = msg.value;
  }
 }

From articles like this, I understood that may be an issue when a contract is receiving money and doesn't implement receive method.

I decided to take advantage of this issue in order to be the king (address) of seven kingdoms, so I created the following contract.

King contact:

pragma solidity 0.6.1;

contract King {
    
    address payable public owner;
    uint public _price;

    modifier onlyOwner {
        require(msg.sender == owner);
        _;
    }

    constructor () payable public {
        owner = msg.sender;
        _price = msg.value;
    }
    
    function triggerAddress(address payable _addr, uint256 valueInWei) public payable {
    _addr.transfer(valueInWei);  
   }
    
    receive() external payable {
        require(msg.sender == owner, "Sorry I cannot receive money");
    }
}

Now when I am deploying the contracts in Remix and trying to transfer money(in Wei) from King to SevenKingdoms via its address (address contract for example 0x515df7f7cF195BFAA0f59bdD30B30f48B785aaFf) I am getting the following error message.

Note: The called function should be payable if you send value and the value you send should be less than your current balance.

What I am doing wrong? Is there problem in the way how I use transfer method between contracts? How I can send money between contracts leveraging cotract's address ?

Thank you in advance.

1

The problem is in King's triggerAddress function. When it is used for transferring ether to SevenKingdoms' contract it will set the gas available to 2300.

function triggerAddress(address payable _addr, uint256 valueInWei) public payable {
    _addr.transfer(valueInWei);  
}

SevenKingdoms' fallback receives 2300 as gas stipend

function() external payable {
    require(msg.value > price);
    king.transfer(msg.value);
    king = msg.sender;
    price = msg.value;
}

Now when trying to transfer to previous the king it will run out of gas because a transfer cost 9000 gas.

A workaround is to use low-level call to make the transfer

function triggerAddress(address payable _addr, uint256 valueInWei) public payable {
    _addr.call.gas(gasleft()).value(valueInWei)("");  
}
2
  • Hello Ismael thank you for instant reply. In Javascript VM your solution works as expected but when I deploy the contracts to Ropsten Test Network and subsequently trigger "triggerAddress" function from King contract I get Out of gas. See transaction log ropsten.etherscan.io/tx/… – nikos bob Jun 23 '20 at 19:14
  • @nikosbob Did you try calling the function with more gas? You can check how much is used in remix and use that gas amount as base. – Ismael Jun 23 '20 at 22:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.