Loading...
Loading...
call, staticcall и delegatecall после использования encodeWithSignature:contract AlexCallDecoding { // Пример контракта для взаимодействия contract SimpleStorage { uint256 public value;
function setValue(uint256 _value) public { value = _value; }
function getValue() public view returns (uint256) { return value; }
function addValues(uint256 a, uint256 b) public pure returns (uint256) { return a + b; } }
address public storageAddress;
constructor(address _storage) { storageAddress = _storage; }
// Декодирование результата функции, возвращающей uint256 function getValueFromStorage() public view returns (uint256) { // Кодируем вызов функции getValue() bytes memory data = abi.encodeWithSignature("getValue()");
// Выполняем staticcall (для view функций) (bool success, bytes memory returnData) = storageAddress.staticcall(data); require(success, "Call failed");
// Декодируем результат в uint256 uint256 result = abi.decode(returnData, (uint256)); return result; }
// Декодирование результата функции с параметрами function calculateSum(uint256 a, uint256 b) public view returns (uint256) { // Кодируем вызов функции addValues с параметрами bytes memory data = abi.encodeWithSignature( "addValues(uint256,uint256)", a, b );
// Выполняем call (bool success, bytes memory returnData) = storageAddress.staticcall(data); require(success, "Calculation failed");
// Декодируем результат uint256 sum = abi.decode(returnData, (uint256)); return sum; }
// Проверка успешности выполнения функции, которая ничего не возвращает function setValueInStorage(uint256 newValue) public { // Кодируем вызов функции setValue bytes memory data = abi.encodeWithSignature( "setValue(uint256)", newValue );
// Выполняем call (bool success, bytes memory returnData) = storageAddress.call(data); require(success, "Set value failed");
// Для функций, которые ничего не возвращают, returnData будет пустым // Но если функция возвращает bool, можно декодировать: // bool result = abi.decode(returnData, (bool)); }}contract AlexAdvancedDecoding { struct User { string name; uint256 age; address wallet; }
// Внешний контракт для примера contract UserRegistry { mapping(uint256 => User) public users;
function getUser(uint256 id) public view returns (User memory) { return users[id]; }
function getUserDetails(uint256 id) public view returns ( string memory name, uint256 age, address wallet ) { User memory user = users[id]; return (user.name, user.age, user.wallet); }
function getMultipleUsers(uint256[] memory ids) public view returns (User[] memory) { User[] memory result = new User[](ids.length); for (uint i = 0; i < ids.length; i++) { result[i] = users[ids[i]]; } return result; } }
address public registryAddress;
constructor(address _registry) { registryAddress = _registry; }
// Декодирование структуры function getUserFromRegistry(uint256 userId) public view returns (User memory) { bytes memory data = abi.encodeWithSignature("getUser(uint256)", userId);
(bool success, bytes memory returnData) = registryAddress.staticcall(data); require(success, "Failed to get user");
// Декодируем структуру User memory user = abi.decode(returnData, (User)); return user; }
// Декодирование множественных возвращаемых значений function getUserDetails(uint256 userId) public view returns ( string memory name, uint256 age, address wallet ) { bytes memory data = abi.encodeWithSignature("getUserDetails(uint256)", userId);
(bool success, bytes memory returnData) = registryAddress.staticcall(data); require(success, "Failed to get user details");
// Декодируем множественные значения (name, age, wallet) = abi.decode(returnData, (string, uint256, address)); }
// Декодирование массивов function getMultipleUsers(uint256[] memory userIds) public view returns (User[] memory) { bytes memory data = abi.encodeWithSignature( "getMultipleUsers(uint256[])", userIds );
(bool success, bytes memory returnData) = registryAddress.staticcall(data); require(success, "Failed to get multiple users");
// Декодируем массив структур User[] memory users = abi.decode(returnData, (User[])); return users; }}contract AlexSafeDecoding { // Безопасное декодирование с проверкой ошибок function safeDecodeUint(address target, bytes memory callData) public view returns (bool success, uint256 result) {
(bool callSuccess, bytes memory returnData) = target.staticcall(callData);
if (!callSuccess) { return (false, 0); }
// Проверяем, что возвращенные данные не пустые if (returnData.length == 0) { return (false, 0); }
// Проверяем, что размер данных соответствует ожидаемому типу if (returnData.length != 32) { // uint256 занимает 32 байта return (false, 0); }
// Безопасно декодируем result = abi.decode(returnData, (uint256)); return (true, result); }
// Декодирование с fallback значением function decodeWithFallback( address target, bytes memory callData, uint256 fallbackValue ) public view returns (uint256) {
(bool success, bytes memory returnData) = target.staticcall(callData);
if (!success || returnData.length == 0) { return fallbackValue; }
try this.tryDecode(returnData) returns (uint256 result) { return result; } catch { return fallbackValue; } }
// Вспомогательная функция для try/catch function tryDecode(bytes memory data) external pure returns (uint256) { return abi.decode(data, (uint256)); }}// ❌ НЕПРАВИЛЬНО - несоответствие типовbytes memory data = abi.encode(uint256(42));string memory result = abi.decode(data, (string)); // Ошибка!
// ✅ ПРАВИЛЬНО - соответствующие типыbytes memory data = abi.encode(uint256(42));uint256 result = abi.decode(data, (uint256)); // Работает!
// ❌ НЕПРАВИЛЬНО - неправильный порядокbytes memory data = abi.encode("Hello", 42);(uint256 num, string memory text) = abi.decode(data, (uint256, string)); // Ошибка!
// ✅ ПРАВИЛЬНО - правильный порядокbytes memory data = abi.encode("Hello", 42);(string memory text, uint256 num) = abi.decode(data, (string, uint256)); // Работает!// Первый контракт - хранилище данныхcontract DataStorage { mapping(address => uint256) public balances;
function setBalance(address user, uint256 amount) public { balances[user] = amount; }
function getBalance(address user) public view returns (uint256) { return balances[user]; }}
// Второй контракт - использует первыйcontract AlexDataManager { address public storageContract;
constructor(address _storage) { storageContract = _storage; }
function updateUserBalance(address user, uint256 amount) public { // Кодируем вызов функции bytes memory data = abi.encodeWithSignature( "setBalance(address,uint256)", user, amount );
// Вызываем функцию через низкоуровневый call (bool success, ) = storageContract.call(data); require(success, "Call failed"); }
function getUserBalance(address user) public view returns (uint256) { // Кодируем вызов функции чтения bytes memory data = abi.encodeWithSignature( "getBalance(address)", user );
// Вызываем функцию (bool success, bytes memory result) = storageContract.staticcall(data); require(success, "Call failed");
// Декодируем результат return abi.decode(result, (uint256)); }}contract AlexEventProcessor { event UserRegistered(address indexed user, string name, uint256 age); event TokenTransfer(address indexed from, address indexed to, uint256 amount);
function registerUser(string memory name, uint256 age) public { // Эмитируем событие emit UserRegistered(msg.sender, name, age); }
function simulateTransfer(address to, uint256 amount) public { emit TokenTransfer(msg.sender, to, amount); }
// Функция для создания фильтра событий function createEventFilter(address user) public pure returns (bytes32) { // Создаем хеш для фильтрации событий конкретного пользователя return keccak256(abi.encodePacked("UserRegistered", user)); }}contract AlexFrontendBridge { struct UserProfile { string name; uint256 age; string[] interests; mapping(string => uint256) scores; }
mapping(address => UserProfile) public profiles;
function createProfile( string memory name, uint256 age, string[] memory interests ) public { UserProfile storage profile = profiles[msg.sender]; profile.name = name; profile.age = age; profile.interests = interests; }
function getProfile(address user) public view returns ( string memory name, uint256 age, string[] memory interests ) { UserProfile storage profile = profiles[user]; return (profile.name, profile.age, profile.interests); }
function setScore(string memory category, uint256 score) public { profiles[msg.sender].scores[category] = score; }
function getScore(address user, string memory category) public view returns (uint256) { return profiles[user].scores[category]; }}// Пример использования ABI во фронтендеconst contractABI = [ { inputs: [ { name: 'name', type: 'string' }, { name: 'age', type: 'uint256' }, { name: 'interests', type: 'string[]' }, ], name: 'createProfile', outputs: [], stateMutability: 'nonpayable', type: 'function', }, // ... другие функции];
// Создание экземпляра контрактаconst contract = new web3.eth.Contract(contractABI, contractAddress);
// Вызов функцииawait contract.methods .createProfile('Alex', 25, ['blockchain', 'coding', 'gaming']) .send({ from: userAddress });
// Чтение данныхconst profile = await contract.methods.getProfile(userAddress).call();console.log(profile); // {name: "Alex", age: "25", interests: ["blockchain", "coding", "gaming"]}contract DeFiDashboard { struct PortfolioInfo { address[] tokens; uint256[] balances; uint256[] prices; uint256 totalValue; }
// Получение портфолио пользователя function getUserPortfolio(address user, address[] memory tokens) external view returns (PortfolioInfo memory portfolio) {
portfolio.tokens = tokens; portfolio.balances = new uint256[](tokens.length); portfolio.prices = new uint256[](tokens.length); portfolio.totalValue = 0;
for (uint i = 0; i < tokens.length; i++) { // Получаем баланс токена bytes memory balanceData = abi.encodeWithSignature("balanceOf(address)", user); (bool success, bytes memory result) = tokens[i].staticcall(balanceData);
if (success) { portfolio.balances[i] = abi.decode(result, (uint256)); }
// Получаем цену токена (пример) portfolio.prices[i] = _getTokenPrice(tokens[i]);
// Вычисляем стоимость portfolio.totalValue += (portfolio.balances[i] * portfolio.prices[i]) / 1e18; }
return portfolio; }
function _getTokenPrice(address token) private view returns (uint256) { // Упрощенная логика получения цены return 1000e18; // $1000 за токен для примера }}// Получение портфолио пользователяasync function getUserPortfolio(userAddress, tokenAddresses) { const portfolioInfo = await contract.methods .getUserPortfolio(userAddress, tokenAddresses) .call();
return { tokens: portfolioInfo.tokens, balances: portfolioInfo.balances.map((b) => web3.utils.fromWei(b)), prices: portfolioInfo.prices.map((p) => web3.utils.fromWei(p)), totalValue: web3.utils.fromWei(portfolioInfo.totalValue), };}
// Отображение данных в интерфейсеasync function displayPortfolio() { const tokens = ['0x...', '0x...', '0x...']; const portfolio = await getUserPortfolio(userAddress, tokens);
console.log('Портфолио пользователя:'); console.log('Общая стоимость:', portfolio.totalValue, 'USD');
portfolio.tokens.forEach((token, i) => { console.log( `Токен ${token}: ${portfolio.balances[i]} (${portfolio.prices[i]} USD)`, ); });}// Межконтрактные вызовы → abi.encodeWithSignature/abi.encode (с паддингом)bytes memory data = abi.encodeWithSignature("transfer(address,uint256)", to, amount);
// Хеширование с безопасностью → abi.encode (паддинг предотвращает коллизии)bytes32 hash = keccak256(abi.encode(user, amount, nonce));
// Хеширование с экономией газа → abi.encodePacked (БЕЗ паддинга, только фиксированные типы!)bytes32 id = keccak256(abi.encodePacked(user, block.timestamp, nonce));
// Декодирование → abi.decode (работает только с данными abi.encode)(address user, uint256 amount) = abi.decode(data, (address, uint256));

