Solidity | Экземпляры контрактов
Всем примет. Сегодня говорим об экземплярах контрактов и их особенностях. Покажу как работать с ними и их подводные камни.
Для чего вообще нам нужны экземпляры контрактов?
Самое очевидное, это для взаимодействия с контрактом.
Например: у нас есть контракт А, который реализует методы, и мы хотим их использовать у себя в контракте.
Иногда наш код удобно разделить на части, но как это было у меня в прошлом проекте, наследование использовать не получиться, потому что код слишком большой и в следствии смарт-контракт не может быть развернут. В таком случае нам приходит на помощь экземпляры контрактов.
Также удобно создавать ролевую систему, тоже было показано в прошлом проекте, где вызов функций смарт-контракта A мог только смарт-контракт B
В общем это очень сильный инструмент для разработки, без которого нельзя. Важно понимать, что мы можем брать экземпляр только развернутого контракта. Поэтому мы передаем адрес контракта для его инициализации.
Пример использования:
Самый очевидный и популярный пример:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract A{
IERC20 token;
constructor(address _token){
token = IERC20(_token);
}
}В данном примере я объявляю переменную типа интерфейс IERC20
token = IERC20(_token); - эта строка кода создает переменную token и присваивает ей значение, являющееся экземпляром смарт-контракта, реализующего интерфейс IERC20
address _token - это адрес любого токена ERC20.
Таким образом мы получаем доступ ко всем методам токена стандарта ERC20, адрес которого мы передали.
// SPDX-License-Identifier: MITpragma solidity ^0.8.9;
contract FirstContract{
struct human{
string name;
uint age;
}
address public owner;
mapping(address=>human) public humans;
function setName(string calldata _name) public{
humans[msg.sender].name = _name;
}
function setAge(uint _age) public{
humans[msg.sender].age = _age;
}
} // SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import "./test.sol";
contract B{
FirstContract public firstContract;
constructor(address _A){
firstContract = FirstContract(_A);
}
function check() public view returns(string memory, uint){
(string memory _name, uint _age) = firstContract.humans(msg.sender);
return (_name, _age);
}
function checkOwner() public view returns(address){
return firstContract.owner();
}
}Если у нас есть структура, маппинг или переменная, то обращаться мы можем к ней только под видом функции.
firstContract.owner() - для того, чтоб узнать содержимое переменной нам нужно обратиться к ней, как к функции.
firstContract.owner - так это выглядело, если бы у нас firstContract вызывался через наследование.
Для того, чтоб вытащить поля из структуры, которая находиться в маппинге, нужно создавать кортеж переменных и в данном случае мы обращаемся к маппингу как к функции, таким образом доставая нужные нам поля.
Если мы хотим достать только определенное поле структуры, то можно сделать так: (string memory _name, ) = firstContract.humans(msg.sender);
Тут я достаю только имя из нашей структуры.
Мы не можем изменять переменные у экземпляра контракта в своем контракте, если нет функций, разрешающих это сделать.
Как видно у меня в примере, в FirstContract я создал 2 функции устанавливающие значения полям структуры. И теперь вызвав эти функции у себя в смарт-контракте, мы можем изменить эти поля.
function setName_(string memory _name) public{
firstContract.humans(msg.sender).name = _name;
} function setName_(string memory _name) public{
firstContract.setName(_name);
}Нужно понимать, что сам контракт B не видит эти функции, как при наследовании, поэтому нельзя взять экземпляр и таким образом использовать все его функции. Нужно явно объявлять их у себя.
Еще нельзя забывать, что мы должны импортировать интерфейс или сам смарт-контракт, чтоб наш контракт понимал с чем взаимодействовать.
В общем это основные особенности, при использовании экземпляра контракта. Мы должны рассматривать каждую переменную как функцию, а все остальное такое же как и в наследовании.
Это была небольшая статься, потому что я для себя подметил ряд необычных механик, которые думаю можно было рассмотреть. Всем удачи.