Перейти до основного вмісту

Взаємодія з іншими контрактами за допомогою Solidity

смарт-контракти
Solidity
Remix
розгортання
компонованість
Просунутий рівень
jdourlens
5 квітня 2020 р.
4 хвилин на читання
Редагувати сторінку (opens in a new tab)

У попередніх посібниках ми багато дізналися про те, як розгорнути свій перший смарт-контракт та додати до нього деякі функції, як-от контроль доступу за допомогою модифікаторів (opens in a new tab) або обробка помилок у Solidity (opens in a new tab). У цьому посібнику ми дізнаємося, як розгорнути смарт-контракт з існуючого контракту та взаємодіяти з ним.

Ми створимо контракт, який дозволить будь-кому мати власний смарт-контракт Counter, створивши для нього фабрику, її назва буде CounterFactory. Спочатку ось код нашого початкового смарт-контракту Counter:

Зверніть увагу, що ми трохи змінили код контракту, щоб відстежувати адресу фабрики та адресу власника контракту. Коли ви викликаєте код контракту з іншого контракту, msg.sender посилатиметься на адресу нашої фабрики контрактів. Це дуже важливий момент для розуміння, оскільки використання контракту для взаємодії з іншими контрактами є поширеною практикою. Тому в складних випадках слід звертати увагу на те, хто є відправником.

Для цього ми також додали модифікатор onlyFactory, який гарантує, що функція зміни стану може бути викликана лише фабрикою, яка передасть початкового ініціатора виклику як параметр.

Усередині нашої нової CounterFactory, яка керуватиме всіма іншими лічильниками, ми додамо відображення (mapping), яке пов'язуватиме власника з адресою його контракту лічильника:

mapping(address => Counter) _counters;

В Етеріумі відображення (mapping) є еквівалентом об'єктів у JavaScript, вони дозволяють зіставити ключ типу A зі значенням типу B. У цьому випадку ми зіставляємо адресу власника з екземпляром його лічильника (Counter).

Створення екземпляра нового лічильника для когось виглядатиме так:

  function createCounter() public {
      require (_counters[msg.sender] == Counter(0));
      _counters[msg.sender] = new Counter(msg.sender);
  }

Спочатку ми перевіряємо, чи особа вже має лічильник. Якщо вона не має лічильника, ми створюємо новий лічильник, передаючи її адресу в конструктор Counter, і призначаємо новостворений екземпляр у відображення.

Отримання значення конкретного лічильника виглядатиме так:

function getCount(address account) public view returns (uint256) {
    require (_counters[account] != Counter(0));
    return (_counters[account].getCount());
}

function getMyCount() public view returns (uint256) {
    return (getCount(msg.sender));
}

Перша функція перевіряє, чи існує контракт лічильника для заданої адреси, а потім викликає метод getCount з екземпляра. Друга функція: getMyCount — це просто скорочення для передачі msg.sender безпосередньо у функцію getCount.

Функція increment досить схожа, але передає початкового відправника транзакції до контракту Counter:

function increment() public {
      require (_counters[msg.sender] != Counter(0));
      Counter(_counters[msg.sender]).increment(msg.sender);
  }

Зверніть увагу, що якщо викликати його занадто багато разів, наш лічильник може стати жертвою переповнення. Вам слід якомога частіше використовувати бібліотеку SafeMath (opens in a new tab), щоб захиститися від цього можливого випадку.

Щоб розгорнути наш контракт, вам потрібно буде надати код як CounterFactory, так і Counter. Під час розгортання, наприклад, у Remix, вам потрібно буде вибрати CounterFactory.

Ось повний код:

Після компіляції в розділі розгортання Remix ви виберете фабрику для розгортання:

Selecting the factory to be deployed in Remix

Потім ви можете поекспериментувати з вашою фабрикою контрактів і перевірити зміну значення. Якщо ви хочете викликати смарт-контракт з іншої адреси, вам потрібно буде змінити адресу в полі вибору акаунта (Account) у Remix.

Останнє оновлення сторінки: 3 березня 2026 р.