Warnung: Die Verwendung von "Call" auf niedriger Ebene sollte nach Möglichkeit vermieden werden

Ich schreibe meinen eigenen Smart Contract und möchte eine Funktion aus einem bereits bereitgestellten Vertrag aufrufen. Das Fragment meines Codes:

function myFunc(address _contractAddress, address _user, uint _price) onlyOwner {
        //... some code ...

        require(_contractAddress.call(bytes4(sha3("func(address, uint256)")), _user, _price));

        //... some code ...
    }

Ich verwende Remix IDE. Es zeigt mir diese Warnung:

Verwendung von „call“: Die Verwendung von „call“ auf niedriger Ebene sollte nach Möglichkeit vermieden werden. Es kann zu unerwartetem Verhalten führen, wenn der Rückgabewert nicht richtig behandelt wird. Bitte nutzen Sie Direct Calls über die Angabe der Schnittstelle des aufgerufenen Vertrags.

Wie soll ich dieses Problem lösen? Delegatecall erzeugt eine ähnliche Warnung. Vielleicht gibt es andere Möglichkeiten, die Funktion eines anderen Vertrags aufzurufen?

Antworten (2)

In neueren Versionen von Solidity können Sie entweder abstrakte Verträge oder Schnittstellen verwenden .

  • Abstrakte Verträge benötigen jetzt das abstractSchlüsselwort, um korrekt zu kompilieren, und den virtualModifikator für Funktionen.
  • Schnittstellen sind hier viel besser für Ihren Zweck geeignet, dafür wurden sie entwickelt.

Ich bin mir ziemlich sicher, dass Schnittstellen auf niedriger Ebene durch abstrakte Verträge mit allen externen virtuellen Funktionen und ohne interne Datenfelder dargestellt werden.

MeinVertrag.sol:

// SPDX-License-Identifier: Unlicense                                                                               
pragma solidity >0.8.5;

abstract contract OtherContract {
    function otherMethod(address _to, uint _price) external virtual;
}

interface OtherContractInterface {
    function otherMethod(address _to, uint _price) external;
}

contract MyContract {
    uint public unitPrice = 100;

    function myMethod(address _destination, uint _count) external {
        // _destination is a contract that implements OtherContract

        // this uses the interface.
        OtherContractInterface oci = OtherContractInterface(_destination);
        oci.otherMethod(address(this), _count * unitPrice);

        // this code uses the abstract contract
        OtherContract oc = OtherContract(_destination);
        oc.otherMethod(address(this), _count * unitPrice);
    }
}

Wenn Sie die aufzurufende Methode kennen, können Sie einen abstrakten Vertrag verwenden

contract OtherContract {
    function otherMethod(address _to, uint _price);
}

contract MyContract {
    uint public unitPrice = 100;

    function myMethod(address _destination, uint _count) {
        // _destination is a contract that implements OtherContract
        OtherContract oc = OtherContract(_destination);
        // call method from other contract
        oc.otherMethod(address(this), _count * unitPrice);
    }
}
Meine Verträge befinden sich in separaten Dateien, daher wird dies nicht funktionieren.
Wenn sich die Verträge in separaten Dateien befinden, können Sie sie importieren oder eine Datei erstellen, die nur die Deklarationen der Methoden enthält, ein "abstrakter Vertrag" im Solidity-Jargon.
Das Importieren des Vertrags ist dasselbe wie das Deklarieren oben in derselben Datei. Meine Situation ist, dass diese Verträge separat bereitgestellt werden
Es ist eine gängige Technik, die in Crowdsales verwendet wird. Sie haben zwei unabhängig voneinander bereitgestellte Verträge Crowdsale y CrowdsaleToken. Der Crowdsale benötigt Zugriff auf CrowdsaleToken, aber wenn Sie ihn in die Datei Crowdsale.sol importieren, wird der Bytecode erhöht. Sie erstellen also ein abstraktes Vertragstoken ohne Implementierung, nur die Methodendeklaration und importieren es aus dem Crowdsale.