Aufruffunktion aus bereitgestelltem Vertrag

Ich möchte wissen, wie ein bestehender Vertrag, der auf der Blockchain bereitgestellt wird, mithilfe seiner Adresse instanziiert wird. z.B:

contract A {
    function f1()
    {}
}

Awird auf der Blockchain bereitgestellt, und im Vertrag Bmöchte ich die Funktion aufrufen f1()und ihre Rückgabe erhalten. z.B:

contract B {
    address contrac_A=0x123456;

    //call f1 from A
}

Wie soll ich es mit der Adresse nennen A?

Antworten (4)

Wenn der bereitgestellte Vertrag nicht der ABI entspricht, Sie aber die Vertragssignatur (Name und Argumenttypen) kennen, können Sie Folgendes verwenden:

contract_address.call(bytes4(sha3("function_name(types)")),parameters_values)

zum Beispiel: contrac_A.call(bytes4(sha3("f()"))Während es in Ihrem Beispiel keine Eingabe gibt, gibt es keine Parameter.

Ersetzen Sie contract_address,function_name,parameters_values ​​durch Ihre Anmeldeinformationen.

Bearbeiten: Da sha3 veraltet ist, ist es besser, stattdessen keccak256 wie folgt zu verwenden:bytes4(keccak256("f()")).

Darüber hinaus wurden seit solidity 0.4.22 die globalen Funktionen abi.encode(), abi.encodePacked(), abi.encodeWithSelector() and abi.encodeWithSignature()definiert, um strukturierte Daten zu codieren und uns daher dabei zu helfen, gültige Aufrufe zu erstellen (sie geben die erforderlichen 4 Bytes zurück) wie folgt:

contract_address.call.value(1 ether).gas(10)(abi.encodeWithSignature("register(string)", "MyName"));

Dokumentation :

https://github.com/ethereum/wiki/wiki/Solidity-Features#generic-call-method

https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI#function-selector

Ich habe eine Funktion wie folgt gesehen. Funktion transfer (Adresse _to, uint _value, Bytes _data, String _custom_fallback) gibt zurück (bool Erfolg) {ContractReceiver receiver = ContractReceiver(_to); receiver.call.value(0)(bytes4(sha3(_custom_fallback)), msg.sender, _value, _data); gib true zurück; } .....Was ist die Verwendung von Wert(0) hier??

Verwenden Sie einen abstrakten Vertrag (bevorzugt)

Weitere Klarstellungen zu @Edmunds Antwort:

contract A { // This doesn't have to match the real contract name. Call it what you like.
   function f1(bool arg1, uint arg2) returns(uint); // No implementation, just the function signature. This is just so Solidity can work out how to call it.
}

contract YourContract {
  function doYourThing(address addressOfA) returns(uint) {
    A my_a = A(addressOfA);
    return my_a.f1(true, 3);
  }
}

Dies zeigt die Verwendung des Rückgabewerts von f1.

Wenn f1eine Ausnahme auftritt (stellen Sie sich vor, ihre Implementierung ist function f1(bool arg1, uint arg2) returns(uint) { throw; }), wird die Ausnahme weitergegeben und my_a.f1wird auch throweine Transaktion zurücksetzen, die aufgerufen wurde doYourThing.

In der Praxis haben Sie 3 Dateien.

AbstractA.sol enthält:

contract A {
   function f1(bool arg1, uint arg2) returns(uint); // No implementation, just the function signature. This is just so Solidity can work out how to call it.
}

IhrVertrag.sol enthält:

import "AbstractA.sol"

contract YourContract {
  function doYourThing(address addressOfA) returns(uint) {
    A my_a = A(addressOfA);
    return my_a.f1(true, 3);
  }
}

A.sol enthält:

contract A {
   // implementation of f1
   function f1(bool arg1, uint arg2) returns(uint) {
       if (arg1) {
           throw;
       } else {
           return arg2;
       }
   }
}

Einschränkungen der Verwendungcall

callwird in der Antwort von @Badr vorgeschlagen, sollte aber sehr vorsichtig verwendet werden. In Solidity -Dokumenten heißt es :

Alle drei Funktionen und sind Funktionen callauf sehr niedriger Ebene und sollten nur als letztes Mittel verwendet werden, da sie die Typsicherheit von Solidity verletzen.delegatecallcallcode

Außerdem kann der Rückgabewert von f1nicht mit calllike abgerufen werden, addressOfA.call(bytes4(keccak256("f1(bool, uint256)")), true, 3)da callnur ein bool( zurückgegeben falsewird, wenn der Aufruf auf eine Ausnahme stößt).

Das bedeutet, dass die Ausnahme wie folgt manuell weitergegeben werden muss:

if (!addressOfA.call(bytes4(keccak256("f1(bool, uint256)")), true, 3)) {
    throw;
}
Müssen wir Sichtbarkeit und Modifikatoren einbeziehen, wenn wir die Funktionssignatur angeben?
@DigitalJedi Ja, seit 2017 wurden Verbesserungen an Solidity vorgenommen, und dazu gehört auch die explizite Angabe der Sichtbarkeit.
contract A { // This doesn't have to match the real contract name. Call it what you like.
   function f1(){} // No implementation, just the function signature. This is just so Solidity can work out how to call it.
}

contract YourContract 
  function doYourThing() {
    A my_a = A(contract_A);
    my_a.f1();
  }
}
Sie befinden sich nicht in derselben Vertragsdatei. Der Compiler erkennt den Vertrag A nicht, also nein A my_a = A(contract_A);
Fügen Sie sie in dieselbe Datei ein. Sie benötigen nicht die vollständige Implementierung, sondern nur die Funktionssignaturen.
Ich frage nach einem bereits bereitgestellten Vertrag.
Sie benötigen nicht den vollständigen Quellcode. Sie müssen den Namen der Methode kennen, die Sie aufrufen, und welche Parameter sie braucht, also kleben Sie das in eine Vertragsdefinition namens A, lassen Sie den Funktionskörper leer und platzieren Sie ihn über dem Vertrag, der sie aufrufen wird.
Meine Antwort wurde bearbeitet, um den Kontext bereitzustellen. Das ist wirklich alles, was Sie brauchen, egal ob der Vertrag bereits im Einsatz ist oder nicht. Wenn Ihr Originalcode nicht kompiliert werden kann, überprüfen Sie die Schreibweise von "Funktion".
@EdmundEdgar Ich habe eine Funktion wie folgt gesehen. Funktion transfer (Adresse _to, uint _value, Bytes _data, String _custom_fallback) gibt zurück (bool Erfolg) {ContractReceiver receiver = ContractReceiver(_to); receiver.call.value(0)(bytes4(sha3(_custom_fallback)), msg.sender, _value, _data); gib true zurück; } .....Was ist die Verwendung von Wert(0) hier??
Dies sollte der Fall sein. Gute Lösung!

Hier ist ein Solidity-Code für den neuen Vertrag , der die Funktion f1() aus Ihrem alten Vertrag aufrufen kann . Hoffe das hilft. Ich habe versucht, es so einfach wie möglich zu halten.

    import "./Old.sol";    // You import the existing contract. 
        
        
            /**
            * The NEW contract will call the Old one
            */
        
          contract New {
          
               Old OLD; // Intitilize old contract variable (empty)
        
            /**
             * Set the address for Old contract (We call this function and enter the address of the OLD contract)
             */
            function setOldContractAddress(address addr) public {
                OLD = Old(addr);
            }
        
        
             /**
             * Function that allows us to call f1() from the Old contract
             */
            function callOLDcontract() public {
                OLD.f1();
             
                }
            
            }