ERC-1155: пакетная передача и связь массивов
Два отдельных issue означают две отдельные транзакции. Между ними состояние может измениться, а одна выдача может пройти при отклонении другой. Если библиотеке нужен единый набор лабораторных ресурсов, ERC-1155 позволяет передать несколько видов за одну операцию. Ключевая особенность — позиционная связь ids и amounts.
В позиции i первого массива находится идентификатор, в той же позиции второго — количество для него. Нельзя независимо сортировать один массив и оставить второй прежним. Такое изменение выдаст правильные числа неправильным видам. Для пользователя это предметная ошибка, даже если длины формально совпадают.
Собственный метод ограниченного набора
Ниже фрагмент, который нужно добавить в полный LibraryResources предыдущего урока. Он использует уже объявленные LAB_PASS, REVIEW_INVITE, InvalidIssue и onlyOwner. Это не самостоятельный файл, и показанные проверки не применяются автоматически к унаследованной публичной передаче.
function issuePack(address to, uint256[] calldata ids, uint256[] calldata amounts)
external onlyOwner
{
if (ids.length == 0 || ids.length > 8 || ids.length != amounts.length)
revert InvalidIssue();
for (uint256 i; i < ids.length; ++i) {
if ((ids[i] != LAB_PASS && ids[i] != REVIEW_INVITE) || amounts[i] == 0)
revert InvalidIssue();
}
_mintBatch(to, ids, amounts, "");
}
Граница восемь является нашим учебным правилом. Стандарт не устанавливает именно это число. Мы ограничиваем собственный публичный путь выпуска, чтобы операция имела небольшой предсказуемый объём проверки. Для другого продукта границу выбирают из реальных требований и исследованного профиля исполнения.
Все виды проверяются до вызова _mintBatch. Если третий элемент содержит недопустимый id, операция не должна выдать первые два как частичный набор. Даже если записи внутри библиотечной операции уже начались бы, revert откатил бы состояние всей транзакции. Предварительная проверка здесь делает предметный договор понятным ещё до взаимодействия с получателем.
Пример с двумя видами
Возьмём ids=[17,18] и amounts=[3,2]. У R до выпуска нулевые количества обоих видов. После ожидаемого успешного issuePack(R,ids,amounts) баланс 17 равен 3, баланс 18 равен 2. Значение to одно для всего набора; массив адресатов этот метод не принимает.
Теперь поменяем только ids на [18,17], сохранив amounts. Результат становится другим: три приглашения вида 18 и два пропуска вида 17. Наличие тех же чисел в двух массивах не сохраняет смысл. Сериализация, форма и таблица подтверждения должны держать пары вместе.
В клиентском представлении удобно сначала хранить строки объектов с id и amount, а при подготовке ABI получать оба массива из одного упорядоченного списка. Это уменьшает вероятность рассинхронизации. Но клиентская структура не заменяет проверки контракта: другой вызывающий может собрать calldata самостоятельно.
Повторный идентификатор
Наш фрагмент не запрещает ids=[17,17]. В выбранной реализации изменения идут по порядку, поэтому количества 2 и 3 приводят к суммарному увеличению вида 17 на пять. Этот результат допустим по показанному договору, хотя интерфейс может предпочесть объединить строки для понятного отображения.
Если продукт требует уникальные id в наборе, это условие нужно добавить явно. Для небольшого предела восемь возможна понятная проверка пар, а для больших наборов требуются иные ограничения представления. Нельзя заявить уникальность только потому, что слово «набор» обычно напоминает математическое множество.
Особенно важно учитывать повторения при собственной политике лимита. Проверка каждого элемента против одного прежнего количества без учёта суммарного увеличения может разрешить превышение через несколько одинаковых id. Решение зависит от того, запрещены повторения или корректно накоплены суммы в ограниченной модели.
События и callback
У закреплённого ERC1155 форма события и проверки получателя зависит от длины массива. Для одного элемента библиотечная _update испускает TransferSingle, а при другом размере — TransferBatch; проверка приёма также выбирает соответствующий маршрут. Название вызываемой функции issuePack не гарантирует единственный универсальный формат события.
Поэтому индексатор изучает фактические события используемой версии. Если он принимает только TransferBatch после любого _mintBatch, выдача массива длины один может пропасть из его списка. Число элементов является частью наблюдаемого поведения, которое стоит сохранять рядом с разбором receipt.
При отклонении callback получателя откатывается весь набор. Изменённые балансы и события не остаются успешным частичным итогом. Приёмный контракт может прочитать уже обновлённые количества внутри hook, но дальнейшее поведение его кода требует отдельного рассмотрения, особенно если вокруг выпуска добавляются обязательства приложения.
Передача набора читателем
Унаследованный safeBatchTransferFrom разрешает владельцу или его оператору переносить количества между адресами. Наш предел восемь для issuePack не ограничивает этот метод. Если необходимо единое ограничение на все маршруты, потребуется явное изменение соответствующих публичных или внутренних путей и анализ совместимости.
Для передачи [17,18] с [2,1] R должен иметь достаточное количество каждого вида. Нехватка второго отменяет весь переход, даже если первого хватает. Такая атомарность полезна, но означает, что один неподходящий элемент блокирует результат всего выбранного набора.
Чтение balanceOfBatch тоже использует позиционные пары, однако там первый массив содержит адреса, а второй идентификаторы. Он не является списком балансов всех видов одного человека по умолчанию. Чтобы узнать два вида R, адрес R повторяется в обеих позициях.
Для самостоятельного разбора составьте четыре входа: разные длины, пустой массив, повторный id и недопустимый третий элемент. Запишите ожидаемый исход и причину для каждого. Затем сравните issuePack с двумя независимыми issue и объясните, почему их наблюдаемая атомарность различается. Никакие транзакции или проверки сейчас не выполняются.
Сумма и представление подтверждения
Таблица подтверждения должна показывать каждую пару вида и количества. Общая сумма пять не объясняет, получит ли читатель пять лабораторных пропусков или три пропуска и два приглашения. Виды могут иметь разные функции, поэтому арифметический итог не заменяет предметный состав.
При повторном id интерфейс может объединить количества, но тогда он должен подготовить согласованные calldata и показать именно их перед подписью. Нельзя подписать один набор и затем нарисовать другой только ради аккуратной таблицы. Для отчёта сохраняется фактический порядок массивов, поскольку именно он определяет исполненную операцию.
Для самостоятельного уточнения: ERC1155.sol (5.4.0), eip-1155.
Оглавление курса. Листинги, расчёты и наблюдения здесь разобраны как ожидаемое поведение; компиляция, учебные программы и проверки при написании не запускались.