Wie generiert man eine Solidity-Encode-Funktionssignatur aus Javascript?

Was ich zu erreichen versuche, ist wie, ich sollte in der Lage sein, eine Reihe von Solidity-Funktionen dynamisch basierend auf einigen Kriterien aufzurufen. Ich verwende die call () -Methode, um dasselbe zu erreichen.

(bool success, bytes memory result) =APContract.call(abi.encodeWithSignature(string(data), "hello"));

dataVariable enthält den Funktionsaufruf-String "testCall(string)". Anstatt aus dem Vertrag zu codieren, sollte ich in der Lage sein, dasselbe mit Javascript zu codieren (wegen einer Logik zur Argumentgenerierung). damit ich die Funktion wie aufrufen kann APContract.call(data). Gibt es eine Methode, die hilft, dasselbe zu erreichen?

Nur zur Klarstellung: Was ich wollte, ist ein Javascript-Snipet-Äquivalentabi.encodeWithSignature("testCall(string)", "hello")

Antworten (2)

Ich bin mir nicht sicher, ob ich Ihre Frage vollständig verstanden habe, aber Sie können sich die ABI-Spezifikation des Solidity Documentation Contract ansehen: https://docs.soliditylang.org/en/latest/abi-spec.html#examples

Um zu sehen, wie Sie die Parameter selbst codieren können. Es ist im Grunde ein großer Satz verketteter Zeichenfolgen aus Funktionsnamen-Hash und Funktionsargumenten.

Sie können sich auch diese Bibliothek ansehen, die "kundenspezifische Vertragsaufrufe" durchführt (also sich nicht auf ABI verlässt): https://github.com/ERC725Alliance/erc725.js/blob/main/src/lib/utils.ts

Manueller Weg

import Web3 from 'web3';

const web3 = new Web3();

const methodId = web3.utils.keccak256('testCall(string)').substr(0, 10); //0xc7cee1b7

// In this function call, the first and only parameter uses a dynamic type: string
// https://docs.soliditylang.org/en/latest/abi-spec.html#use-of-dynamic-types

// we use the offset in bytes to the start of their data area, measured from the start of the value encoding
// offset to start of data part of second parameter, 1*32 bytes, exactly the size of the head part

const stringArgument = web3.utils.padLeft(web3.utils.toHex(1*32), 64).replace('0x', '');
// 0000000000000000000000000000000000000000000000000000000000000020


const stringValue = 'TODO' // This one is a bit tricky, the docs explain it well: https://docs.soliditylang.org/en/latest/abi-spec.html#use-of-dynamic-types

const call = methodId + stringArgument + stringValue;

ABI-Weg

Sie können jederzeit Ihr eigenes ABI-Diktat erstellen, dann übernimmt web3 die obige Konvertierung für Sie:

const contract = new web3.eth.Contract(
        [
            {
                name: 'testCall',
                inputs: [
                    { type: 'bytes32', name: '_hash', internalType: 'bytes32' },
                ],
            },
        ],
        contractAddress,
    );

const answer = await contract.methods
            .testCall(messageHash)
            .call();

ABI nutzt Weg

Verwenden Sie die Hilfsfunktionen von: https://web3js.readthedocs.io/en/v1.3.0/web3-eth-abi.html, um das zu erstellen, was Sie benötigen.

web3.eth.abi.encodeParameter('string', 'Hello')

Bearbeiten: Sie können auch den Quellcode von web3 überprüfen

Vielen Dank, dass Sie sich um die Beantwortung bemüht haben. Was ich tun wollte, ist, die Methode aus Javascript mit einer Methode zu codieren, die äquivalent ist zu abi.encodeWithSignature("testCall(string)", "hello"). und die codierten Bytes werden an einen Parameter einer Solidity-Funktion übergeben (wird ein Web3-Aufruf sein). diese spezielle Funktion wird like aufrufen aPContract.call(data). datasind die kodierten Bytes als Argument der aufgerufenen Funktion gekommen. Es wird eine große Hilfe sein, wenn Sie auf diese Weise führen

Hier ist, was ich verwendet habe, um das Ethernaut Puzzle Wallet-Level zu knacken . Ich glaube encodeFunctionCallgenau das was du suchst:

let deposit   = web3.eth.abi.encodeFunctionCall(contract.abi[2], [])
let multicall = web3.eth.abi.encodeFunctionCall(contract.abi[6], [[deposit]])
let calldata  = web3.eth.abi.encodeFunctionCall(contract.abi[6], [[deposit, multicall]])

await sendTransaction({
  from:  player, 
  to:    instance,
  value: web3.utils.toWei('0.001', "ether"),
  data:  calldata
})