Как сгенерировать сигнатуру функции кодирования прочности из Javascript?

То, что я пытаюсь достичь, похоже на то, что я должен иметь возможность динамически вызывать набор функций прочности на основе некоторых критериев. я использую метод call() для достижения того же.

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

dataпеременная содержит строку вызова функции "testCall(string)". вместо кодирования из контракта я должен иметь возможность кодировать то же самое с помощью javascript (из-за некоторой логики генерации аргументов). так что я могу вызвать функцию как APContract.call(data). Есть ли какой-нибудь метод, который поможет добиться того же?

Просто уточнение: я хотел, чтобы фрагмент javascript эквивалентенabi.encodeWithSignature("testCall(string)", "hello")

Ответы (2)

Не уверен, что полностью понял ваш вопрос, но вы можете взглянуть на спецификацию ABI контракта Solidity Documentation: https://docs.soliditylang.org/en/latest/abi-spec.html#examples .

Чтобы увидеть, как кодировать параметры самостоятельно. По сути, это большой набор связанных строк, состоящий из хэша имени функции и аргументов функции.

Вы также можете взглянуть на эту библиотеку, которая выполняет «вызовы пользовательских контрактов» (поэтому не полагаясь на какой-либо ABI): https://github.com/ERC725Alliance/erc725.js/blob/main/src/lib/utils.ts .

Ручной способ

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 dict, тогда web3 выполнит вышеуказанное преобразование за вас:

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 использует способ

Используйте вспомогательные функции из: https://web3js.readthedocs.io/en/v1.3.0/web3-eth-abi.html , чтобы создать то, что вам нужно.

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

Изменить: вы также можете проверить исходный код web3

Спасибо, что приложили усилия для ответа. Я хотел закодировать метод из javascript, используя метод, эквивалентный abi.encodeWithSignature("testCall(string)", "hello"). и закодированные байты будут переданы параметром функции солидности (будет вызовом web3). эта конкретная функция будет вызывать как aPContract.call(data). dataзакодированные байты пришли в качестве аргумента вызываемой функции. Будет полезно, если вы будете вести себя таким образом

Вот что я использовал для взлома уровня Ethernaut Puzzle Wallet . Я считаю, encodeFunctionCallчто это именно то, что вы ищете:

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
})