Ethernaut. Задача 21. Shop
В этой задаче нам нужно уменьшить цену покупки.
Ссылка на задачу
В чем суть?
Похожая задача уже была ранее на канале, которая учит нас не доверять внешним контрактам. В следующей строке:
Buyer _buyer = Buyer(msg.sender);
msg.sender может быть как адрес пользователя, так и адрес чужого контракта.
Функция buy() проверяет, чтобы цена, предложенная покупателем была выше установленной и покупка еще не была совершена ранее. После вызова данной функции, isSold устанавливается как true и ЕЩЕ раз вызывается функция price, которая и устанавливает новое значение в переменной.
Решение может выглядеть так:
contract BrokenShop {
Shop iShop;
constructor (address _shop) public{
iShop = Shop(_shop);
}
function getIt() external {
iShop.buy();
}
function price () external view returns (uint) {
return iShop.isSold() ? 1 : 101;
}
}
Сначала мы инициализируем контракт Shop в конструкторе, для того чтобы функции buyer вызывались не в изначальном контракте, а в нашем.
Затем прописываем две функции. getIt() - запускает весь процесс. А вот функция price(), которая подменяет оригинальную функцию в Buyer, и делает всю работу.
Смотрите, что получается. Когда мы вызвали функцию getIt(), она обратилась к buy() в контракте Shop и прошла проверку if.
Выражение iShop.isSold() ? 1 : 101 говорит, что, если isSold=false, то значение будет равно 101, если true - то 1.
И получается, с isSold=false мы проходим проверку if. Затем isSold меняется на true. И уже после в переменную price СНОВА вызывается наша функция price(), которая отдает значение 1.
Тут надо знать, что view: не может изменять переменные, порождать события, создавать другие контракты, посылать Эфир, делать низкоуровневые вызовы и использовать inline assembly. Она лиши может возвращать значение и обращаться к другим функция view или pure. Именно этим и нужно воспользоваться в данной задаче.
#ethernaut
Post #433
181