TGViewer
Из Solidity в AI и дальше Из Solidity в AI и дальше @solidityset · 2.48K subscribers
Post #832 1.03K
Организация storage в прокси контракте

В процессе аудита протокола Arcade встретился лицом к лицу с не совсем обычной организацией storage в контракте. Не совсем обычной для меня. Возможно, более опытные разработчики уже сталкивались с подобной реализацией.

Я могу ошибиться в некоторых моментах описания и прошу поправить меня, если вдруг, что не так.

P.S. В посте будут приведены ссылки на контракты из открытого конкурсного репозитория, актуального на время написания поста.

Итак, у нас есть прокси контакт - NFTBoostVault, который наследует функции от двух библиотек, которые и позволяют работать с памятью контракта так, чтобы при обновлениях не было коллизии в данных - Storage и NFTBoostVaultStorage.

Примечательно здесь то, что базовые типы данных, например address и uint, которые не поддерживают определенные места хранения в storage (как mapping), хранятся в структуре с одноименным названием, например:

struct Address {
address data;
}

Так в конструкторе или функции мы можем установить / обновить для них значения с помощью:

Storage.set(Storage.uint256Ptr("locked"), 1);

где Storage.uint256Ptr("locked") - место в памяти, а 1 - значения для установки.

Или также для типов address:

Storage.set(Storage.addressPtr("manager"), manager);

где manager - тип address из аргументов функции.

Доставать значения из такого слота памяти можно при помощи других функций из библиотеки:

function getIsLocked() public view override returns (uint256) {
return Storage.uint256Ptr("locked").data;
}

т.е. мы запрашиваем в storage слот с хешем uint256Ptr("locked") и достаем оттуда необходимые данные.

Но еще интереснее дела обстоят с работой mapping. Посмотрите на следующий код:

NFTBoostVaultStorage.Registration storage registration = _getRegistrations()[msg.sender];

Здесь мы достаем структурные данные из памяти, которые хранятся в виде mapping! Вот его другие функции:

function _getRegistrations() internal pure returns (mapping(address => NFTBoostVaultStorage.Registration) storage) {
return NFTBoostVaultStorage.mappingAddressToRegistrationPtr("registrations");
}

function mappingAddressToRegistrationPtr(
string memory name
) internal pure returns (mapping(address => Registration) storage data) {
bytes32 offset = keccak256(abi.encodePacked(REGISTRATION_TYPEHASH, name));
assembly {
data.slot := offset
}
}

Я и сейчас на 100% не уверен как работает "под капотом" преобразование данные в _getRegistrations()[msg.sender], так, чтобы получился mapping. Но выглядит интересно.

Solidity не перестает меня удивлять!

В общем, если вас это заинтересовало, то советую самим посмотреть контракты и попробовать чуть лучше разобраться. Буду также рад, если дадите свои комментарии по этому вопросу.

P.S. Отдельное спасибо @elawbek, что помог мне чуть лучше понять, как это все работает.

#storage #mapping #proxy
  • 🔥 6
  • 👍 4
More from @solidityset
  1. Oct 2, 2026Вторая сложность — как доказать, что установилось именно опубликованное. В первом варианте…
  2. Oct 2, 2026Задача с полуоткрытым кодом На днях, в процессе создания одного приложения, столкнулся с и…
  3. Sep 22, 2026Какой язык программирования учить сейчас? На днях в Твиттере увидел небольшой пост о разви…
  4. Sep 18, 2026Интересная модель Jev Буквально пару дней назад в Твиттере многие начали обсуждение новой…
  5. Sep 14, 2026Графы повсюду Если вы также следите за новостями в мире ИИ, то наверняка уже все чаще встр…
  6. Sep 10, 2026GTA6, Cyberleek, блокчейн и безопасность Увидел несколько постов (тут и тут) про Cyberleek…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →