Можно ли взаимодействовать с контрактом, развернутым внутри другого контракта, через web3js?

Очень полезно узнать, возможен ли описанный ниже сценарий.

контракт A { импорт "./B.sol";

... адрес c = новый B(); б = В (в)

}

//где-то в JS instance_of_B = web3.eth.contract(B.abi).at(c);

Ответы (2)

Да, это возможно.

Web3.js не волнует, как был развернут контракт. Ему просто нужны: - ABI контракта - адрес контракта - и провайдер для передачи запросов в блокчейн Ethereum

Теперь вам нужно вернуть адрес нового созданного контракта во внешний мир, чтобы web3 мог его увидеть. Вы не можете вернуть данные из транзакции, однако вы можете использовать событие с адресом контракта, и web3 отслеживает это событие.

Вы примерно ответили на свой вопрос. Давайте пройдемся по деталям и разберемся с проблемами и синтаксисом.

Требования к чтению договора

  1. Знание АБИ. Это может быть получено путем компиляции исходного кода или просто задано.
  2. Знание адреса контракта.

Дизайн контракта может помочь со вторым требованием.

Вы бы не сделали:

contract A { import "./B.sol"; ...

Но, вы могли бы сделать

import "./B.sol";

contract A { ...

И у вас может быть функция для развертывания нового B:

function createB() public returns(address contractB) {
  B b = new B(); // cast b as B, defined by "contract B" in the imported file
  return address(b);
}

Поскольку это функция изменения состояния, программные клиенты будут получать только transactionHash, а не address(b)- этот ответ доступен только для других контрактов. Это может быть очень полезно, и обычно рекомендуется также генерировать событие для такого важного изменения состояния, как это. События наблюдаются наблюдателем Web3.

import "./B.sol";

contract A {

  event LogNewB(address creator, address contractB);

  function createB() public returns(address contractB) {
    B b = new B();
    emit LogNewB(msg.sender, b);
    return address(b);
  }

Что, если наблюдатель не смотрит? Может быть полезно сделать это обнаруживаемым путем проверки контракта. A может отслеживать экземпляры B, которые он развертывает:

address[] public bList;
...
bList.push(b);

Всего ...

import "./B.sol";

contract A {

  address[] public bList;
  event LogNewB(address creator, address contractB);

  function createB() public returns(address contractB) {
    B b = new B();
    emit LogNewB(msg.sender, b);
    bList.push(address(b));
    return address(b);
  }

Поскольку bListis public, вы получаете «бесплатный» геттер, который будет возвращать адрес в строке, что примерно эквивалентно:

function bList(uint row) public view returns(address) {
  return bList[row];
}

Теперь у клиента Web3 есть три способа составить список всех контрактов B, которые были развернуты A. Они могут прослушивать журналы событий, разрешать добытые хэши транзакций и проверять аргументы журнала или проверять файл bList. Вместе со знанием ABI for B клиент может:

var instanceB = web3.eth.contract(abi).at(address);

Как отметил Жюльен, Web3 безразличен метод, который использовался для развертывания контракта.

Надеюсь, поможет.

ps Может быть полезно добавить быструю функцию для определения длины bListмассива, иначе программные клиенты не будут знать, где находится конец массива. Что-то вроде:

function getBCount() public view returns(uint) { return bList.length; }