DEV: Рубиновые тона – Telegram
DEV: Рубиновые тона
3.21K subscribers
145 photos
2 videos
8 files
981 links
Анонсы новых видео о программировании (Ruby/Rails, Solidity/Ethereum, Python, JS и не только), практические советы, обзор полезных инструментов и новости из мира IT
Download Telegram
Но чемоданное настроение не покидало меня долгие годы: я знал, что уеду при первой же возможности. Либо репатриация, с которой, правда были свои немалые сложности, либо другим способом. Уехать мне довелось задолго до всей нынешней ситуации... А теперь западом пугают детишек в РФ. Пугают "мной" и моими друзьями по всему миру. Вот так оно получилось.

Но не иметь возможности даже навестить немногих оставшихся родственников и знать, что ты, вероятно, не сможешь сделать этого ещё долгие годы, - это иногда тяжеловато. Что думали беженцы в 1917 году? Ещё месяцок-другой, и мы вернёмся. Но проходили годы, а вернулись единицы. Впрочем, это просто мысли вслух, ибо многим людям сейчас гораздо, гораздо хуже. До мая я всё ещё собираю пожертвования, и обязательно отправлю средства в один из выбранных благотворительных фондов - в очередной раз я могу лишь высказать восхищение Lokalise, которые собрали 600 с лишним тысяч евро на одном энтузиазме. У меня, конечно, такого охвата и таких ресурсов нет, но всё же. Своё отношение ко всему происходящему я высказывал уже много раз, да и речь сегодня не о нём.

Вероятно, вот статья по теме, хотя я никогда не интересовался, как эта комета называется. Я надеюсь, что вы в безопасности, где бы вы не находились. You are awesome. Скоро увидимся. https://ru.wikipedia.org/wiki/C/1995_O1_(%D0%A5%D0%B5%D0%B9%D0%BB%D0%B0_%E2%80%94_%D0%91%D0%BE%D0%BF%D0%BF%D0%B0)
16👍1
Для разработчиков Ruby, которые используют Lokalise API и OAuth 2, я рад представить новую библиотеку для omniauth. С её помощью запрашивать токены OAuth 2 стало ещё проще 😄 https://github.com/bodrovis/omniauth-lokalise
👍12
Не слишком весёлая история о том, как на контракте застряло почти 35 миллионов баксов. В один прекрасный день одна компания запустила аукцион по типу "голландского" (кстати, он очень похож на то, что писали мы, только посложнее). Только там можно было делать сразу несколько ставок, а проигравшим выплачивались деньги обратно , вот тут исходники, см. примерно с 500 строки, тк до этого идут всякие библиотеки https://etherscan.io/address/0xf42c318dbfbaab0eee040279c6a2588fa01a961d#code=
👍6
А суть здесь в чём. У этих ребят вышло так, что они неправильно учитывали кол-во ставок сделанных и вместо того, чтобы прибавлять общее кол-во ставок (от 1 до 3) делали всегда ++ то есть инкремент на 1. Это привело к тому, что одно условие всегда оказывалось ложным и деньги никогда нельзя было снять.

Это не говоря о том, что один умник заблочил процесс выплаты refund, тк отправил проигрышную ставку не с кошелька, а с контракта. В контракте у него функция receive, которая всегда возвращает ошибку. В итоге, так как рефанды делаются в цикле, в какой-то момент процесс застопорился из-за этой самой ошибки в receive. Вышло, что ни владельцы деньги снять не могут, ни участники, тк пока не выплачены рефанды, то и средства забрать нельзя https://twitter.com/0xInuarashi/status/1517676162138267648
😁6👍2😢1
Немного подробнее.

Если атакующий делает проигрышную ставку с контракта, а в контракте есть receive, которая всегда возвращает ошибку, то попытки возместить проигравшую ставку заведомо обречены. В коде возврат делался стандартным образом:

            if (refund > 0) {
(bool sent, ) = bidData.bidder.call{value: refund}("");
require(sent, "Failed to refund bidder");
}


А коль скоро возвратов много и их надо обрабатывать в цикле, то как только попадается адрес контракта злоумышленника, то и вся цепочка обрывается. Правда потом злоумышленник всё-таки вышел на связь и сказал, что просто хотел показать ненадёжность аукциона и этот блок убрал (у него в receive просто стояло элементарное условие вида "возвращать ошибку/не возвращать ошибку"). Если ошибку не возвращать, то просто пробрасывать принятые деньги на кошелёк атакующего, что вернуть свою ставку. Ну, либо там мог быть бесконечный цикл, вот пример https://twitter.com/0xInuarashi/status/1517677597978599425

Вроде бы, всё ок, то есть возвраты стали работать и участники аукциона свои деньги назад таки получили.

Но есть и другой неприятный момент. В коде для функции claimProjectFunds, которая выводила деньги на счёт устроителей, было условие refundProgress >= totalBids (то есть нужно, чтобы было выплачено возвратов столько, сколько было ставок, видимо) - только после этого сами владельцы контракта могут забрать вырученные средства, то есть победившие ставки.

Однако дополнительно была введена переменная bidIndex, которая тоже была связана с числом ставок. В функцию bid, приходила не только денежная сумма, а ещё и количество ставок (amount), которое могло варьироваться от 1 до 3. Но владельцы контракта это не учли и вместо того, чтобы написать bidIndex += amount написали bidIndex++ (ну, либо им надо было ещё одну переменную выделять на это).

А дальше самое интересное. В функции для обработки возвратов стояло ещё одно условие require(_refundProgress < _bidIndex, "Refunds already processed");. То есть кол-во возвратов не могло превышать кол-во bidIndex. Но если вспомнить, что bidIndex считается неправильно (а многие юзеры делали сразу много ставок), то refundProgress всегда будет меньше, чем totalBids (то есть кол-во ставок в принципе, которое как раз считалось правильно). А теперь мы вспомним условие в функции "забрать себе деньги за аукцион": require(refundProgress >= totalBids, "Refunds not yet processed");.

Фактически, это условие истинным не будет никогда, то есть устроители аукциона обманули самих себя, и деньги застряли на их же контракте.
👍9🔥4
DROP TABLE
😁8🔥1
😁202👍2
А, и кстати: сегодня же день "Звёздных войн" 😄
🔥92👍1🎉1
Я всё ещё эпизодами дочитываю в очередной раз Тэффи и нашёл такой момент:

Портрет мой, нарисованный Репиным, получился какой-то волшебно-нежный, совсем неожиданный, не похожий на могучую лепку репинской кисти.
Он обещал его мне. Но ко мне он так и не попал. Был послан на выставку в Америку и, по словам Репина, застрял в таможне.
Мне неловко было расспрашивать и настаивать. Мне говорили:
— Он не хочет признаться, что продал его.
Все равно. Он пропал бы во время революции, как пропали все мои портреты и многие любимые мною вещи, без которых, казалось бы, и жить не стоило…


Интересно, как у разных людей разнятся мысли. Я никогда не привязывался ни к вещам, ни к месту (хотя, конечно, у Тэффи "казалось бы" - тоже намёк на то, что не всё так просто).

Когда-то, в другой жизни, я уехал практически без ничего. Сумка с компьютером, который спустя год всё равно пришлось собирать заново посреди ночи из тех запчастей, что удалось купить в срочном порядке, сумка с кошкой, стойка и микрофон, какой-то минимум одежды...

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

И тут вспоминается Сапковский:

- Co ty mozesz wiedziec, Itka - miauknela cicho, zlowrogo kotka. - Zal? Moze i tak, zal mi ich. Zal mi dotyku ich rak. Zal mi szmeru ich oddechów, gdy spia. Zal mi ciepla ich kolan. Zal mi naszej muzyki, która, ledwo poznana, trace.


Действительно жаль. Когда теперь ещё увидимся?

Но остаётся работа, остаются мысли о том, что, насколько это возможно, мы можем делать мир лучше - хотя бы для кого-то. Отзывы зрителей - это лучшая награда.

А теперь почему-то вспоминается давнее турне по Италии и Франции, которое удалось устроить лет... хотел написать 5-6, но, кажется, уже 6-7 назад.

Тогда мы как раз и посетили Русское кладбище в пригороде Парижа, поклонились могиле Тэффи, Нуреева, участникам белого движения... К счастью, родственники помогли обустроиться, так что мы прожили во Франции почти неделю.

В один день зашли в какой-то бар и почему-то @ailura24 улетела с одного коктейля (алкоголя налили много?). Ходили по всему Версалю как два шатающихся дурака. Глупо ведь, а весело. Потом уже ночью гуляли все вместе, какие-то весёлые парижане кричали нам с балкона, приглашали на тусовку к ним домой.

Причём ведь сейчас тоже можно повторить что-то подобное, даже гораздо проще, но как-то душа не лежит. Тяжело. Хочется быть эдаким рубаха-парнем, а выходит мужик неопределённого возраста, который наговаривает заранее неотрепетированный текст в микрофон (впрочем, текст не репетировался никогда) скрипучим голосом, а два раза в неделю избивает грушу в зале. Да, и мучает студентов раз в неделю на семинарах. Впрочем, это ведь на пользу.

В любом случае, не нужно опускать руки. Мы живы, мы здесь. Adsumus. Adsumus in nomine tuo.
👍17🤔2👎1🤯1😢1
Друзья, возник справедливый вопрос по атаке типа reentrancy и функциям transfer/send - являются ли они гарантией безопасности?

Так вот, reentrancy в теории может быть везде, где есть вызов сторонних контрактов. Желательно априори считать вызов сторонних неизвестных контрактов небезопасным.

Функции transfer/send действительно имеют жёсткий лимит по газу (2300), но и в него тоже можно уместиться и сделать что-нибудь нехорошее. Вообще-то, раньше transfer действительно считалась безопасной функцией (её и ввели для защиты от reentrancy), но только никто не учёл, что стоимости по газу могут меняться. Если раньше "втиснуться" в лимит 2300 особо было нельзя, то теперь вполне можно (стоимости упали). Например, вот тут немного подробнее https://immunebytes.com/transfer-in-solidity-why-you-should-stop-using-it/ Короче, нужно быть осторожными
👍12
Для "развлечения" сделал скрипт, который подбирает "красивые" адреса контрактов, которые разворачиваются через create2. То есть просто подбирается соль. Код нужно сильно оптимизировать, но всё же это работает:

function stringGen(len) {
var text = "";

var charset = "abcdefghijklmnopqrstuvwxyz0123456789";

for (var i = 0; i < len; i++)
text += charset.charAt(Math.floor(Math.random() * charset.length));

return text;
}

const func = async function (hre) {
const {deployments, getNamedAccounts} = hre;
const {deploy} = deployments;

const {deployer} = await getNamedAccounts();

while(true) {
let salt = stringGen(Math.floor(Math.random() * 30))
let res = await deploy('TestContract', {
from: deployer,
log: false,
deterministicDeployment: hre.ethers.utils.solidityKeccak256(["string"], [salt]),
});

if(res.address[2] === res.address[3] && res.address[2] === res.address[4] && res.address[2] === res.address[5]) {
console.log(res.address, salt)
break;
}
}

};

export default func;

К примеру, с солью u8phmitlg9hse17xin8 и небольшим демо-контрактом выходит адрес 0x88880b14BDFF750Ce5B58d1A55fCa65403BdBaaE (четыре восьмёрки в начале). Скрипт работает с помощью hardhat-deploy
👍10🔥1😁1
"Hello world" на разных языках программирования (примеров сотни). Кстати, Solidity нет, поэтому желающие могут добавить 😄 http://helloworldcollection.de/