11

Do you know if is it possible to call the function of an other contract in Solidity used in Substrate based chain and compiled with solang ? At first glance it seems impossible but I doubt it.

As a basic example I'm trying to get a "incrementor" working only if a "flipper" is on:

contract Flipper {
  bool private value;

  constructor (bool initValue) {
    value = initValue;
  }

  function flip () public {
    value = !value;
  }

  function get () public view returns (bool) {
    return value;
  }

}

I want to use a Flipper instance in my Incrementor contract to allow / disallow incrementing.

import "flipper.sol";

contract Incrementor {

    uint256 _count;
    Flipper _flipper;

    constructor (uint256 _initialValue, Flipper _flipperContract) {
        _count = _initialValue;
        _flipper = _flipperContract;
    }

    // --
    // Mutators
    // --

    function increment () public {
      require(_flipper.get(), "Flipper must be ON");
      _count += 1;
    }

    function superFlip () public {
      _flipper.flip();
    }

    function setValue (uint256 v) public {
        _count = v;
    }

    // --
    // Accessors
    // --

    function count () public view returns (uint256) {
        return _count;
    }

}

When testing all of this on polkadotjs; I have a negative answer saying contract trapped ALONG with a success message (but the totality doesn't work).

(Failure on the "increment" message):

enter image description here


I'm not sure but I suspect this problem to arise from the difference in addressing in the EVM vs WASM.

In the article linked bellow, we can see how an external contract function is "manually" invoked with an "address.call(bytes4(keccack25('...')), args)".

https://medium.com/@blockchain101/calling-the-function-of-another-contract-in-solidity-f9edfa921f4c

Except this is working in a EVM environment; not a WASM substrate environment.

Solang Version : v0.1.9 https://github.com/hyperledger-labs/solang/releases/tag/v0.1.9

Substrate Version: v4.0.0-dev

Contract Node version: 0.6.0 https://github.com/paritytech/substrate-contracts-node

Contracts deployed from PolkadotJS api v7.8.1 apps v0.105.2-27

Incrementor Contract: enter image description here

Flipper Contract: enter image description here

Can someone help ?

4
  • 2
    So theoretically this should work the way you described it in your example but with more information we cannot really know what is going wrong. Please add the following information: 1. Version of solang used. 2. Which node and which version did you test against 3. How did you deploy those two contracts? Feb 14, 2022 at 15:29
  • @AlexanderTheißen topic updated with theses informations
    – Dream
    Feb 14, 2022 at 15:44
  • The version of the contracts node you posted doesn't make sense. Try substrate-contracts-node --version. Also, couldn't it just be that your require evaluates to false? In that case it would also trap. Feb 14, 2022 at 15:47
  • @AlexanderTheißen ok topic updated with correct informations
    – Dream
    Feb 14, 2022 at 15:55

2 Answers 2

13

I was able to reproduce your problem. I even stripped down your contracts even more and was able to isolate the cross contract call as root of the problem. I also compiled with the latest solang commit (95f2969) and the bug is still there.

I added some debug output to the substrate node in order to find out what is going on. It turns out that the error which makes the cross contract call fail is ContractNotFound. The reason why you see ContractTrapped is because the caller contract traps (revert without output data) when the call fails.

I inspected the storage of the deployed Incrementer contract to see whether it stored the wrong value for _flipper. It turns out that is stores the correct value. I added further debugging to the node which revealed that the wrong address is passed when Flipper is called by Incrementer. The reason must therefore lie within the code in solang which generates the contract call because the solidity code is correct as far as I can tell.

The minimal reproducer I used:

contract Flipper {
  function flip () pure public {}
}

contract Inc {
  Flipper _flipper;

  constructor (Flipper _flipperContract) {
      _flipper = _flipperContract;
  }

  function superFlip () pure public {
    _flipper.flip();
  }
}

I opened a bug report here: https://github.com/hyperledger-labs/solang/issues/666

1
  • 1
    Thank you ! If I understand it correctly we need to wait for a new Solang compiler version including a fix for this issue ?
    – Wisebaboon
    Feb 21, 2022 at 12:22
4

I've created some testcases in the solang repo here https://github.com/hyperledger-labs/solang/pull/671

Everything works fine in both the mock substrate that solang uses, and also with Substrate 3.0 (see PR).

Looks like something has changed between Substrate 3.0 and current substrate, which breaks solang compiled contracts. Any suggestions for where to look?

Solang integration tests could really do with upgrading to the latest substrate and any issues fixing.

1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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