web3.js kann ich eine Smart-Contract-Funktion aufrufen, ohne die ABI zu kennen?

In einer web3 JS dApp (z. B. mit Metamask),
wenn ich nur die Adresse eines Vertrags und den Methodennamen kenne , wie kann ich diese Methode aufrufen?

ABI kenne ich nicht.

Dies ist möglich, wenn Sie die Methodensignatur (einschließlich der Typen der Parameter) kennen , aber nicht nur den Namen.

Antworten (3)

Ich poste hier eine richtige Antwort - danke an @smarx und andere von SO, die mir geholfen haben, zu dieser Lösung zu führen.

Die Antwort

Dies ist möglich, wenn Sie die Methodensignatur (einschließlich der Typen der Parameter) kennen , aber nicht nur den Namen. – @smart


ERC20-Beispiel - Saldo eines beliebigen Tokens anzeigen

So implementiert beispielsweise ein ERC20 - konformer Token-Vertrag eine balanceOf()Methode.
Die Signatur dieser Methode sieht so aus (siehe unten, wie man sie erhält):

var abi = [{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}]

Holen Sie sich jetzt die Vertragsadresse der Token, an denen Sie interessiert sind.
Als Beispiel gibt es im Ropsten -Netzwerk einen Panda-Token-Vertrag unter 0x45135b8ED5f52528175CCC6D7add2228779eDeE0 (spenden Sie Ropsten ETH hier , um einige Panda-Token zu erhalten), damit Sie Ihr Panda-Token-Guthaben sehen können mit dem folgenden Code (zusätzlich zur obigen abi-Zeile):

var tokenContractAddress = "0x45135b8ED5f52528175CCC6D7add2228779eDeE0"
var contract = web3.eth.contract( abi ).at( tokenContractAddress )
var account 
web3.eth.getAccounts( (err, ok) => account = ok[0] )
// wait for account to be set ...
contract.balanceOf( account, function(err,ok) { console.log(err,ok.c[0]) } )

So erhalten Sie die ERC20- balanceOf() Signatur

Um die Signatur dieser Methode zu erhalten, ging ich einfach zu Remix und fügte Folgendes als Vertrag ein (nachdem ich die Funktionsdefinition aus der ERC20-Definition erhalten hatte ):

contract ERC20 {
      function balanceOf(address _owner) constant returns (uint balance);
}

Gehen Sie dann zu Compile > Details > INTERFACE - ABI (Copy)

Wenn Sie die ABI oder den Bytecode nicht kennen (wenn Sie also den Vertragscode nicht haben), können Sie keine Transaktion(en) oder Aufruf(e) senden.

Aber wenn Sie es wissen, tun Sie es in web3js 1.0.0-beta einfach:

contractInstance.methods.getBalance().call(address, function(result){
//do something with the variable
});

Oder für eine Transaktion:

contractInstance.methods.setBalance(address).send({from: someone}, function(hash){
//dosomething
});

Für Kommentare bearbeiten: So erstellen Sie die ContractInstance

if (contractInstance == null || contractInstance == 'undefined') {
        console.log("Making a new contract instance");
        var code = fs.readFileSync(solidityFile).toString();
        // Compile the contract code
        var compiledCode = solc.compile(code);
        //Generate the ABI 
        abi = JSON.parse(compiledCode.contracts[':NAMEOFYOUCONTRACT'].interface);
        contractInstance = new web3.eth.Contract(abi, contractAddress);
        console.log("Contract instance created successfully");
Wie instanziieren Sie contractInstanceden Beispielcode in Ihrer Antwort? kann es ohne die ABI erstellt werden?
Ich habe die Antwort aktualisiert. Und wie ich darin sagte, nein, das geht nicht, wenn Sie weder die ABI noch den Bytecode haben
Wie ruft OpenSea die NFT-Methoden auf einem ERC-721-Vertrag auf, der den Code dann nicht veröffentlicht hat?
Ich habe das nicht überprüft. Da ERC jedoch ein Standard ist, könnte man wahrscheinlich den ABI generieren. (reine Spekulation). Beachten Sie außerdem, dass diese Antwort 5 Jahre alt ist und sich die Dinge möglicherweise geändert haben (und wahrscheinlich geändert haben).

Bitte beachten Sie, dass die Länge der Argumente, die die Funktion benötigt, bekannt sein muss. Argumente ist eine Liste der Datenstrukturen, die die Funktion benötigt. zum Beispiel: ["Adresse","bool"]

Wenn Sie sich über den Typ nicht sicher sind, verwenden Sie "int"

const genericABIGenerator = (
  args,
  function_name,
  returnType = "int"
) => {
  return [
    {
      inputs: args.map((value, index) => ({
        name: `arg${index}`,
        type: value ?? "int",
      })),
      name: function_name,
      outputs: [
        {
          name: "output",
          type: returnType,
        },
      ],
      stateMutability: "view",
      type: "function",
    },
  ];
};

Codeausführung

const contract = new client.eth.Contract(
    genericABIGenerator(inputTypeList, function_name, outputType),
    contractAddress
  );
const result = await contract.methods[function_name](...args).call();