diff --git a/client/src/constants.js b/client/src/constants.js index 1ee464d11..d2f2db26f 100644 --- a/client/src/constants.js +++ b/client/src/constants.js @@ -216,4 +216,4 @@ export const ALIAS_PATH = "https://raw.githubusercontent.com/OpenZeppelin/ethern export const getLeaderboardPath = (network) => { return `https://raw.githubusercontent.com/OpenZeppelin/ethernaut-leaderboard/update/boards/networkleaderboards/${network}LeaderBoard.json` -} \ No newline at end of file +} diff --git a/client/src/containers/Header.js b/client/src/containers/Header.js index f9b94e192..882812252 100644 --- a/client/src/containers/Header.js +++ b/client/src/containers/Header.js @@ -232,6 +232,7 @@ class Header extends React.Component { en: strings.english, es: strings.spanish, pt_br: strings.portuguese, + ua: strings.ukrainian, ja: strings.japanese, zh_cn: strings.chinese_simplified, zh_tw: strings.chinese_traditional, @@ -240,7 +241,7 @@ class Header extends React.Component { ar: strings.arabic, tr: strings.turkish, }; - + const ddOpen = Boolean(this.state.multiDDOpen); return (
this.closeDropdown()}> @@ -319,11 +320,11 @@ class Header extends React.Component { this.toggleDropdownState()} to={constants.PATH_LEADERBOARD}>
+ className="element-in-row filled-icon">
- + )} { diff --git a/client/src/gamedata/ar/strings.json b/client/src/gamedata/ar/strings.json index ad27ead90..f84a56b50 100644 --- a/client/src/gamedata/ar/strings.json +++ b/client/src/gamedata/ar/strings.json @@ -11,6 +11,7 @@ "english": "English", "arabic": "عربي", "spanish": "Español", + "ukrainian": "Українська", "portuguese": "Português", "japanese": "日本語", "turkish": "Türkçe", diff --git a/client/src/gamedata/en/strings.json b/client/src/gamedata/en/strings.json index 9e88ffc24..856cdeef0 100644 --- a/client/src/gamedata/en/strings.json +++ b/client/src/gamedata/en/strings.json @@ -11,6 +11,7 @@ "english": "English", "arabic": "عربي", "spanish": "Español", + "ukrainian": "Українська", "portuguese": "Português", "japanese": "日本語", "turkish": "Türkçe", diff --git a/client/src/gamedata/es/strings.json b/client/src/gamedata/es/strings.json index d4a9ac7c0..0693ab1c1 100644 --- a/client/src/gamedata/es/strings.json +++ b/client/src/gamedata/es/strings.json @@ -11,6 +11,7 @@ "english": "English", "arabic": "عربي", "spanish": "Español", + "ukrainian": "Українська", "portuguese": "Português", "japanese": "日本語", "turkish": "Türkçe", diff --git a/client/src/gamedata/fr/strings.json b/client/src/gamedata/fr/strings.json index 46dd98165..8d04183ba 100644 --- a/client/src/gamedata/fr/strings.json +++ b/client/src/gamedata/fr/strings.json @@ -11,6 +11,7 @@ "english": "English", "arabic": "عربي", "spanish": "Español", + "ukrainian": "Українська", "portuguese": "Português", "japanese": "日本語", "turkish": "Türkçe", diff --git a/client/src/gamedata/ja/strings.json b/client/src/gamedata/ja/strings.json index d27e5030a..20859fabc 100644 --- a/client/src/gamedata/ja/strings.json +++ b/client/src/gamedata/ja/strings.json @@ -11,6 +11,7 @@ "english": "English", "arabic": "عربي", "spanish": "Español", + "ukrainian": "Українська", "portuguese": "Português", "japanese": "日本語", "turkish": "Türkçe", diff --git a/client/src/gamedata/pt_br/strings.json b/client/src/gamedata/pt_br/strings.json index 8ee16baa9..4634d6263 100644 --- a/client/src/gamedata/pt_br/strings.json +++ b/client/src/gamedata/pt_br/strings.json @@ -11,6 +11,7 @@ "english": "English", "arabic": "عربي", "spanish": "Español", + "ukrainian": "Українська", "portuguese": "Português", "japanese": "日本語", "turkish": "Türkçe", diff --git a/client/src/gamedata/ru/strings.json b/client/src/gamedata/ru/strings.json index 6d5090516..f434dc06b 100644 --- a/client/src/gamedata/ru/strings.json +++ b/client/src/gamedata/ru/strings.json @@ -11,6 +11,7 @@ "english": "English", "arabic": "عربي", "spanish": "Español", + "ukrainian": "Українська", "portuguese": "Português", "japanese": "日本語", "turkish": "Türkçe", diff --git a/client/src/gamedata/tr/strings.json b/client/src/gamedata/tr/strings.json index c36356f29..2ee37d7d7 100644 --- a/client/src/gamedata/tr/strings.json +++ b/client/src/gamedata/tr/strings.json @@ -11,6 +11,7 @@ "english": "English", "arabic": "عربي", "spanish": "Español", + "ukrainian": "Українська", "portuguese": "Português", "japanese": "日本語", "turkish": "Türkçe", diff --git a/client/src/gamedata/ua/descriptions/levels/aliencodex.md b/client/src/gamedata/ua/descriptions/levels/aliencodex.md new file mode 100644 index 000000000..b6163400c --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/aliencodex.md @@ -0,0 +1,7 @@ +Захопіть власність (ownership), щоб завершити рівень. + +  +Речі, які можуть допомогти +* Розуміння, як працює зберігання масивів +* Розуміння [специфікацій ABI](https://solidity.readthedocs.io/en/v0.4.21/abi-spec.html) +* Використання дуже `підступного` підходу diff --git a/client/src/gamedata/ua/descriptions/levels/aliencodex_complete.md b/client/src/gamedata/ua/descriptions/levels/aliencodex_complete.md new file mode 100644 index 000000000..06721adfa --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/aliencodex_complete.md @@ -0,0 +1,5 @@ +Цей рівень використовує той факт, що EVM не перевіряє довжину масиву, кодовану ABI, відносно його реального вмісту. + +Додатково, він використовує антипереповнення довжини масиву, шляхом збільшення розміру масиву до всього storage `2^256`, що дозволяє користувачу змінювати весь storage контракту. + +Обидві вразливості надихнуті [конкурсом підступного кодування 2017 року](https://medium.com/@weka/announcing-the-winners-of-the-first-underhanded-solidity-coding-contest-282563a87079) diff --git a/client/src/gamedata/ua/descriptions/levels/coinflip.md b/client/src/gamedata/ua/descriptions/levels/coinflip.md new file mode 100644 index 000000000..387d1ce05 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/coinflip.md @@ -0,0 +1,5 @@ +Це гра в підкидання монети, де вам потрібно збільшувати вашу переможну серію, вгадуючи результат підкидання монети. Щоб завершити цей рівень, вам потрібно використовувати свої екстрасенсорні здібності, щоб вгадати правильний результат 10 разів поспіль. + +  +Речі, які можуть допомогти +* Перегляньте сторінку ["?"](https://ethernaut.openzeppelin.com/help) в меню в правому верхньому куті, розділ "По ту сторону консолі" diff --git a/client/src/gamedata/ua/descriptions/levels/coinflip_complete.md b/client/src/gamedata/ua/descriptions/levels/coinflip_complete.md new file mode 100644 index 000000000..9f51b560b --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/coinflip_complete.md @@ -0,0 +1,5 @@ +Генерація випадкових чисел у Solidity є складною. Наразі не існує нативного способу їх генерації, і все, що ви використовуєте в смартконтрактах, є публічно видимим, включаючи локальні змінні та змінні стану, позначені як приватні. Також майнери мають контроль над такими речами, як блокхеши, часові мітки, та включення певних транзакцій - що дозволяє їм змінювати ці значення на свою користь. + +Щоб отримати криптографічно стійкі випадкові числа, ви можете використовувати [Chainlink VRF](https://docs.chain.link/docs/get-a-random-number), який використовує оракул, токен LINK, та контракт на блокчейні для перевірки того, що число дійсно випадкове. + +Деякі інші варіанти включають використання заголовків блоків Bitcoin (перевірених через [BTC Relay](http://btcrelay.org)), [RANDAO](https://github.com/randao/randao), або [Oraclize](http://www.oraclize.it/)). diff --git a/client/src/gamedata/ua/descriptions/levels/delegate.md b/client/src/gamedata/ua/descriptions/levels/delegate.md new file mode 100644 index 000000000..96bd57ed3 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/delegate.md @@ -0,0 +1,7 @@ +Метою цього рівня є те, щоб вам заявити про власність над екземпляром, який вам дано. + +  +Речі, які можуть допомогти +* Загляньте в документацію Solidity про функцію низького рівня `delegatecall`, як вона працює, як вона може використовуватися для делегування операцій до бібліотек на блокчейні, і які вона має наслідки для області виконання. +* Запасні методи +* Ідентифікатори методів diff --git a/client/src/gamedata/ua/descriptions/levels/delegate_complete.md b/client/src/gamedata/ua/descriptions/levels/delegate_complete.md new file mode 100644 index 000000000..275e84999 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/delegate_complete.md @@ -0,0 +1,3 @@ +Використання `delegatecall` є особливо ризикованим і було використано як вектор атаки в декількох історичних хаках. З його допомогою ваш контракт фактично говорить: "ось, -інший контракт- або -інша бібліотека-, робіть з моїм станом все, що вам заманеться". Делегати мають повний доступ до стану вашого контракту. Функція `delegatecall` - це потужна особливість, але небезпечна, і її треба використовувати з крайньою обережністю. + +Будь ласка, зверніться до статті [The Parity Wallet Hack Explained](https://blog.openzeppelin.com/on-the-parity-wallet-multisig-hack-405a8c12e8f7) для точного пояснення, як ця ідея була використана для крадіжки 30 млн доларів США. diff --git a/client/src/gamedata/ua/descriptions/levels/denial.md b/client/src/gamedata/ua/descriptions/levels/denial.md new file mode 100644 index 000000000..dabcbf7d7 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/denial.md @@ -0,0 +1,3 @@ +Це простий гаманець, який випускає кошти з часом. Ви можете повільно знімати кошти, ставши партнером по зняттю. + +Якщо ви зможете заборонити власнику знімати кошти, коли він викликає `withdraw()` (поки у контракті ще є кошти, і транзакція становить 1М газу або менше), ви виграєте цей рівень. diff --git a/client/src/gamedata/ua/descriptions/levels/denial_complete.md b/client/src/gamedata/ua/descriptions/levels/denial_complete.md new file mode 100644 index 000000000..c3d3f6eed --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/denial_complete.md @@ -0,0 +1,7 @@ +Цей рівень демонструє, що зовнішні виклики до невідомих контрактів все ще можуть створювати вектори атаки на відмову у обслуговуванні, якщо не вказано фіксовану кількість газу. + +Якщо ви використовуєте низькорівневий `call` для продовження виконання у разі відкату зовнішнього виклику, переконайтеся, що ви вказали фіксовану кількість газу. Наприклад, `call.gas(100000).value()`. + +Зазвичай слід дотримуватися шаблону [checks-effects-interactions](http://solidity.readthedocs.io/en/latest/security-considerations.html#use-the-checks-effects-interactions-pattern), щоб уникнути атак на повторний вхід, але можуть виникнути інші обставини (наприклад, кілька зовнішніх викликів в кінці функції), де можуть виникнути такі проблеми. + +*Примітка*: Зовнішній `CALL` може використовувати не більше 63/64 від поточно доступного газу на момент `CALL`. Таким чином, залежно від того, скільки газу потрібно для завершення транзакції, можна використовувати транзакцію з достатньо високим газом (тобто таку, що 1/64 газу здатна завершити залишкові опкоди в батьківському виклику), щоб зменшити цю конкретну атаку. diff --git a/client/src/gamedata/ua/descriptions/levels/dex.md b/client/src/gamedata/ua/descriptions/levels/dex.md new file mode 100644 index 000000000..3b4dc2f19 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/dex.md @@ -0,0 +1,18 @@ +Мета цього рівня полягає в тому, щоб ви зламали базовий контракт [DEX](https://en.wikipedia.org/wiki/Decentralized_exchange), що наведений нижче, та вкрали кошти, маніпулюючи ціною. + +Ви починаєте з 10 токенами `token1` та 10 токенами `token2`. У контракті DEX початково є 100 кожного токена. + +Цей рівень буде успішно пройдено, якщо вам вдасться вичерпати всі токени одного з двох видів від контракту та змусити контракт повідомити "некоректну" ціну активів. + +  +### Коротке зауваження +Зазвичай, коли ви робите обмін з токеном ERC20, вам потрібно `approve` контракту витратити ваші токени за вас. Щоб зберегти синтаксис гри, ми просто додали метод `approve` до самого контракту. Тому не соромтеся використовувати `contract.approve(contract.address, )` замість безпосереднього виклику токенів, і він автоматично схвалить витрату обох токенів на бажану суму. Будь ласка, ігноруйте контракт `SwappableToken`. + +  +Речі, які можуть допомогти: +* Як розраховується ціна токена? +* Як працює метод `swap`? +* Як ви `approve` транзакцію з ERC20? +* Існує більше ніж один спосіб взаємодії з контрактом! +* Remix може допомогти +* Що робить "At Address"? diff --git a/client/src/gamedata/ua/descriptions/levels/dex2.md b/client/src/gamedata/ua/descriptions/levels/dex2.md new file mode 100644 index 000000000..dbbc2d98c --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/dex2.md @@ -0,0 +1,9 @@ +Цей рівень попросить вас зламати `DexTwo`, контракт `Dex`, що був дещо змінений відносно попереднього рівня, іншим способом. + +Вам потрібно вичерпати всі баланси token1 та token2 з контракту `DexTwo`, щоб пройти цей рівень. + +Ви все ще починаєте з 10 токенами `token1` та 10 токенами `token2`. У контракті DEX досі є 100 кожного токена. + +  +Речі, які можуть допомогти: +* Як було змінено метод `swap`? diff --git a/client/src/gamedata/ua/descriptions/levels/dex2_complete.md b/client/src/gamedata/ua/descriptions/levels/dex2_complete.md new file mode 100644 index 000000000..a54d1ec61 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/dex2_complete.md @@ -0,0 +1,9 @@ +Як ми неодноразово бачили, взаємодія між контрактами може бути джерелом несподіваної поведінки. + +Те, що контракт претендує на реалізацію [специфікації ERC20](https://eips.ethereum.org/EIPS/eip-20), не означає, що йому можна довіряти. + +Деякі токени відхиляються від специфікації ERC20, не повертаючи булеве значення зі своїх методів `transfer`. Дивіться [Missing return value bug - At least 130 tokens affected](https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca). + +Інші токени ERC20, особливо ті, що були розроблені ворогами, можуть поводитися більш зловмисно. + +Якщо ви створюєте DEX, де будь-хто може вивести свої токени без дозволу центральної влади, то правильність DEX може залежати від взаємодії контракту DEX і контрактів токенів, що обмінюються. diff --git a/client/src/gamedata/ua/descriptions/levels/dex_complete.md b/client/src/gamedata/ua/descriptions/levels/dex_complete.md new file mode 100644 index 000000000..e210a5c81 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/dex_complete.md @@ -0,0 +1,59 @@ +За виключенням частини, що стосується цілочисельної математики, отримання цін або будь-яких даних від будь-якого єдиного джерела є великим вектором атаки в розумних контрактах. + +Ви ясно бачите з цього прикладу, що людина з великим капіталом може маніпулювати ціною одним рухом, що призведе до того, що всі застосунки, що використовують ціну, будуть використовувати неправильну ціну. + +Обмін сам по собі є децентралізованим, але ціна активу є централізованою, оскільки вона походить з одного dex. Однак, якщо ми розглядатимемо токени, що представляють справжні активи, а не вигадані, більшість з них матимуть пари обміну на декількох dexes і мережах. Це зменшить вплив на ціну активу у разі специфічного dex, який став мішенню для такої атаки. + +[Оракули](https://betterprogramming.pub/what-is-a-blockchain-oracle-f5ccab8dbd72?source=friends_link&sk=d921a38466df8a9176ed8dd767d8c77d) використовуються для отримання даних в розумні контракти і з них. + +[Chainlink Data Feeds](https://docs.chain.link/docs/get-the-latest-price) - це безпечний, надійний спосіб отримати децентралізовані дані в ваших розумних контрактах. Вони мають велику бібліотеку з багатьма різними джерелами, а також пропонують [безпечний випадковий](https://docs.chain.link/docs/chainlink-vrf), можливість робити [будь-який API виклик](https://docs.chain.link/docs/make-a-http-get-request), [створення модульної мережі оракулів](https://docs.chain.link/docs/architecture-decentralized-model), [технічне обслуговування, дії та обслуговування](https://docs.chain.link/docs/kovan-keeper-network-beta), та необмежене налаштування. + +[Uniswap TWAP Oracles](https://docs.uniswap.org/contracts/v2/concepts/core-concepts/oracles) покладаються на модель вагової ціни в часі, відому як [TWAP](https://en.wikipedia.org/wiki/Time-weighted_average_price#). Хоча дизайн може бути привабливим, цей протокол сильно залежить від ліквідності протоколу DEX, і якщо вона дуже низька, ціни можна легко маніпулювати. + + +Ось приклад отримання ціни на Bitcoin в USD з каналу даних Chainlink (на тестовій мережі Sepolia): + +``` +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.7; + +import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol"; + +contract PriceConsumerV3 { + AggregatorV3Interface internal priceFeed; + + /** + * Network: Sepolia + * Aggregator: BTC/USD + * Address: 0 + +x1b44F3514812d835EB1BDB0acB33d3fA3351Ee43 + */ + constructor() { + priceFeed = AggregatorV3Interface( + 0x1b44F3514812d835EB1BDB0acB33d3fA3351Ee43 + ); + } + + /** + * Returns the latest price. + */ + function getLatestPrice() public view returns (int) { + // prettier-ignore + ( + /* uint80 roundID */, + int price, + /*uint startedAt*/, + /*uint timeStamp*/, + /*uint80 answeredInRound*/ + ) = priceFeed.latestRoundData(); + return price; + } +} + +``` +[Спробуйте на Remix](https://remix.ethereum.org/#url=https://docs.chain.link/samples/PriceFeeds/PriceConsumerV3.sol) + +Перевірте сторінку з каналом даних Chainlink [тут](https://data.chain.link/ethereum/mainnet/crypto-usd/btc-usd), щоб побачити, що ціна на Bitcoin запитується з до 31 різного джерела. + +Ви також можете перевірити [список](https://docs.chain.link/data-feeds/price-feeds/addresses/) всіх адрес каналів даних Chainlink. diff --git a/client/src/gamedata/ua/descriptions/levels/doubleentrypoint.md b/client/src/gamedata/ua/descriptions/levels/doubleentrypoint.md new file mode 100644 index 000000000..b27972a57 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/doubleentrypoint.md @@ -0,0 +1,10 @@ +Цей рівень представляє `CryptoVault` з особливою функціональністю - функцією `sweepToken`. Це звичайна функція, що використовується для отримання токенів, які застрягли в контракті. `CryptoVault` працює з `underlying` токеном, який не можна "замести", оскільки він є важливим компонентом ядра `CryptoVault`. Будь-які інші токени можна "замести". + +Основний токен - це екземпляр токена DET, реалізований у визначенні контракту `DoubleEntryPoint`, і в `CryptoVault` зберігається 100 одиниць цього токена. Крім того, `CryptoVault` також містить 100 `LegacyToken LGT`. + +На цьому рівні вам слід виявити, де в `CryptoVault` помилка, і захистити його від витікання токенів. + +Контракт містить контракт `Forta`, де будь-який користувач може зареєструвати свій власний контракт `detection bot`. Forta - це децентралізована, заснована на спільноті мережа моніторингу, яка виявляє загрози та аномалії в DeFi, NFT, управлінні, мостах та інших системах Web3 якомога швидше. Ваше завдання - реалізувати `detection bot` і зареєструвати його в контракті `Forta`. Реалізація бота повинна викликати відповідні сповіщення, щоб запобігти потенційним атакам або експлуатації помилок. + +Речі, які можуть допомогти: +- Як працює подвійна точка входу для контракту токена? diff --git a/client/src/gamedata/ua/descriptions/levels/doubleentrypoint_complete.md b/client/src/gamedata/ua/descriptions/levels/doubleentrypoint_complete.md new file mode 100644 index 000000000..a2b683e04 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/doubleentrypoint_complete.md @@ -0,0 +1,13 @@ +Вітаємо! + +Це ваш перший досвід роботи з [ботом Forta](https://docs.forta.network/en/latest/). + +Forta включає в себе децентралізовану мережу незалежних операторів вузлів, які сканують усі транзакції та зміни стану блок за блоком для виявлення викидів транзакцій та загроз. Коли виявляється проблема, оператори вузлів надсилають попередження передплатникам про потенційні ризики, що дозволяє їм вжити заходів. + +Представлений приклад призначений лише для навчальних цілей, оскільки бот Forta не моделюється у розумних контрактах. У Forta бот - це скрипт коду для виявлення специфічних умов або подій, але коли випускається сповіщення, воно не запускає автоматичні дії - принаймні, поки що. На цьому рівні сповіщення бота ефективно викликає відкат транзакції, відхиляючись від призначеного дизайну бота Forta. + +Боти для виявлення сильно залежать від остаточних реалізацій контрактів, і деякі з них можуть бути оновлюваними та ламати інтеграції ботів, але для зменшення цього ви можете навіть створити специфічного бота для пошуку оновлень контрактів і реагування на них. Дізнайтеся, як це зробити [тут](https://docs.forta.network/en/latest/quickstart/). + +Ви також пройшли через недавній проблему безпеки, яка була виявлена під час останньої [співпраці OpenZeppelin з протоколом Compound](https://compound.finance/governance/proposals/76). + +Наявність токенів, які представляють подвійну точку входу, є нетривіальним шаблоном, який може вплинути на багато протоколів. Це тому, що зазвичай припускається, що на один токен припадає один контракт. Але цього разу це було не так :) Ви можете прочитати всі деталі того, що сталося, [тут](https://blog.openzeppelin.com/compound-tusd-integration-issue-retrospective/). diff --git a/client/src/gamedata/ua/descriptions/levels/elevator.md b/client/src/gamedata/ua/descriptions/levels/elevator.md new file mode 100644 index 000000000..ea7c74855 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/elevator.md @@ -0,0 +1,5 @@ +Цей ліфт не дозволить вам дістатися верхнього поверху вашого будинку. Правильно? + +##### Речі, які можуть допомогти: +* Інколи solidity не дуже добре дотримується обіцянок. +* Цей `Elevator` очікує, що його буде використовувати `Building`. diff --git a/client/src/gamedata/ua/descriptions/levels/elevator_complete.md b/client/src/gamedata/ua/descriptions/levels/elevator_complete.md new file mode 100644 index 000000000..1c0ecfe62 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/elevator_complete.md @@ -0,0 +1,4 @@ +Ви можете використовувати модифікатор `view` у інтерфейсі, щоб запобігти змінам стану. Модифікатор `pure` також запобігає змінам стану функціями. +Переконайтеся, що ви прочитали [документацію Solidity](http://solidity.readthedocs.io/en/develop/contracts.html#view-functions) та зрозуміли її нюанси. + +Альтернативний спосіб вирішення цього рівня полягає у створенні view-функції, яка повертає різні результати залежно від вхідних даних, але не змінює стан, наприклад, `gasleft()`. diff --git a/client/src/gamedata/ua/descriptions/levels/fallback.md b/client/src/gamedata/ua/descriptions/levels/fallback.md new file mode 100644 index 000000000..182231749 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/fallback.md @@ -0,0 +1,12 @@ +Уважно подивіться на код контракту нижче. + +Ви пройдете цей рівень, якщо +1) ви претендуєте на власність контракту +2) ви зменшите його баланс до 0 + +  +Речі, які можуть допомогти +* Як відправити ефір, взаємодіючи з ABI +* Як відправити ефір за межами ABI +* Конвертація в одиниці wei/ether та навпаки (див. команду `help()`) +* Запасні методи diff --git a/client/src/gamedata/ua/descriptions/levels/fallback_complete.md b/client/src/gamedata/ua/descriptions/levels/fallback_complete.md new file mode 100644 index 000000000..1fdb45fe3 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/fallback_complete.md @@ -0,0 +1,5 @@ +Ви знаєте основи того, як ефір потрапляє до контрактів і виходить з них, включаючи використання запасного методу. + +Ви також дізналися про контракт Ownable від OpenZeppelin і як він може бути використаний для обмеження використання деяких методів для привілейованої адреси. + +Переходьте на наступний рівень, коли будете готові! diff --git a/client/src/gamedata/ua/descriptions/levels/fallout.md b/client/src/gamedata/ua/descriptions/levels/fallout.md new file mode 100644 index 000000000..10c4c0aea --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/fallout.md @@ -0,0 +1,5 @@ +Заявіть про власність контракту нижче, щоб завершити цей рівень. + +  +Речі, які можуть допомогти +* Solidity Remix IDE diff --git a/client/src/gamedata/ua/descriptions/levels/fallout_complete.md b/client/src/gamedata/ua/descriptions/levels/fallout_complete.md new file mode 100644 index 000000000..d21129e14 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/fallout_complete.md @@ -0,0 +1,15 @@ +Це було дурнувато, чи не так? Контракти у реальному світі повинні бути набагато безпечнішими, і тому їх має бути набагато важче взламати, чи не так? + +Ну... Не зовсім. + +Історія з Rubixi - це дуже відомий випадок в екосистемі Ethereum. Компанія змінила свою назву з 'Dynamic Pyramid' на 'Rubixi', але якось вони не перейменували метод конструктора свого контракту: + +``` +contract Rubixi { + address private owner; + function DynamicPyramid() { owner = msg.sender; } + function collectAllFees() { owner.transfer(this.balance) } + ... +``` + +Це дало змогу атакуючому викликати старий конструктор та претендувати на власність контракту, а також вкрасти деякі кошти. Так. У світі розумних контрактів можуть статися великі помилки. diff --git a/client/src/gamedata/ua/descriptions/levels/force.md b/client/src/gamedata/ua/descriptions/levels/force.md new file mode 100644 index 000000000..3c1dd7155 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/force.md @@ -0,0 +1,9 @@ +Деякі контракти просто не приймуть ваші гроші `¯\_(ツ)_/¯` + +Метою цього рівня є зробити баланс контракту більше нуля. + +  +Речі, які можуть допомогти: +* Запасні методи +* Іноді найкращий спосіб атакувати контракт - це використовувати інший контракт. +* Дивіться сторінку ["?"](https://ethernaut.openzeppelin.com/help) вище, розділ "За рамками консолі" diff --git a/client/src/gamedata/ua/descriptions/levels/force_complete.md b/client/src/gamedata/ua/descriptions/levels/force_complete.md new file mode 100644 index 000000000..5115c1533 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/force_complete.md @@ -0,0 +1,3 @@ +У Solidity, щоб контракт міг отримувати ефір, запасний метод повинен бути позначений як `payable`. + +Однак, немає способу зупинити атакувача від надсилання ефіру до контракту шляхом самознищення. Тому важливо не розраховувати на інваріант `address(this).balance == 0` для будь-якої логіки контракту. diff --git a/client/src/gamedata/ua/descriptions/levels/gatekeeper1.md b/client/src/gamedata/ua/descriptions/levels/gatekeeper1.md new file mode 100644 index 000000000..71d2a2da6 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/gatekeeper1.md @@ -0,0 +1,5 @@ +Пройдіть повз вартового та зареєструйтеся як учасник, щоб пройти цей рівень. + +##### Що може допомогти: +* Пам'ятайте, що ви навчилися на рівнях Telephone та Token. +* Ви можете дізнатися більше про спеціальну функцію `gasleft()`, в документації Solidity (див. [тут](https://docs.soliditylang.org/en/v0.8.3/units-and-global-variables.html) та [тут](https://docs.soliditylang.org/en/v0.8.3/control-structures.html#external-function-calls)). diff --git a/client/src/gamedata/ua/descriptions/levels/gatekeeper1_complete.md b/client/src/gamedata/ua/descriptions/levels/gatekeeper1_complete.md new file mode 100644 index 000000000..9da8edda9 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/gatekeeper1_complete.md @@ -0,0 +1 @@ +Молодець! Тепер спробуйте свої сили з другим вартовим... diff --git a/client/src/gamedata/ua/descriptions/levels/gatekeeper2.md b/client/src/gamedata/ua/descriptions/levels/gatekeeper2.md new file mode 100644 index 000000000..374057430 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/gatekeeper2.md @@ -0,0 +1,6 @@ +Цей вартовий представляє декілька нових викликів. Зареєструйтеся як учасник, щоб пройти цей рівень. + +##### Що може допомогти: +* Пам'ятайте, чого ви навчилися, обходячи першого вартового - перший шлюз залишився тим самим. +* Ключове слово `assembly` у другому шлюзі дозволяє контракту отримувати доступ до функціональності, яка не є рідною для чистого Solidity. Дивіться [тут](http://solidity.readthedocs.io/en/v0.4.23/assembly.html) для отримання додаткової інформації. Виклик `extcodesize` в цьому шлюзі отримує розмір коду контракту за заданою адресою - ви можете дізнатися більше про те, як і коли він встановлюється, у розділі 7 [жовтої брошури](https://ethereum.github.io/yellowpaper/paper.pdf). +* Символ `^` у третьому шлюзі - це операція з бітовими масками (XOR), і вона використовується тут для застосування іншої поширеної бітової операції (дивіться [тут](http://solidity.readthedocs.io/en/v0.4.23/miscellaneous.html#cheatsheet)). Рівень Coin Flip також є хорошим початком при підході до цього виклику. diff --git a/client/src/gamedata/ua/descriptions/levels/gatekeeper2_complete.md b/client/src/gamedata/ua/descriptions/levels/gatekeeper2_complete.md new file mode 100644 index 000000000..d3db92fbd --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/gatekeeper2_complete.md @@ -0,0 +1 @@ +Чудова робота! Тепер, коли ви можете обійти вартового, у вас є те, що потрібно, щоб приєднатися до [theCyber](https://etherscan.io/address/thecyber.eth#code), децентралізованого клубу в основній мережі Ethereum. Отримайте пароль, зв'язавшись зі створювачем на [reddit](https://www.reddit.com/user/0age) або через [email](mailto:0age@protonmail.com) та використайте його для реєстрації з контрактом на [gatekeepertwo.thecyber.eth](https://etherscan.io/address/gatekeepertwo.thecyber.eth#code) (майте на увазі, що контракт прийме лише перших 128 учасників). diff --git a/client/src/gamedata/ua/descriptions/levels/gatekeeper3.md b/client/src/gamedata/ua/descriptions/levels/gatekeeper3.md new file mode 100644 index 000000000..7616a6fea --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/gatekeeper3.md @@ -0,0 +1,6 @@ +Впорайтеся з воротами та станьте учасником. + +##### Що може допомогти: +* Пригадайте значення, що повертають низькорівневі функції. +* Будьте уважні до семантики. +* Оновіть свої знання про те, як працює зберігання в Ethereum. diff --git a/client/src/gamedata/ua/descriptions/levels/gatekeeper3_complete.md b/client/src/gamedata/ua/descriptions/levels/gatekeeper3_complete.md new file mode 100644 index 000000000..c11c2664e --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/gatekeeper3_complete.md @@ -0,0 +1 @@ +Добра робота! Для отримання більш детальної інформації прочитайте [це](https://web3js.readthedocs.io/en/v1.2.9/web3-eth.html?highlight=getStorageAt#getstorageat) та [це](https://medium.com/loom-network/ethereum-solidity-memory-vs-storage-how-to-initialize-an-array-inside-a-struct-184baf6aa2eb). diff --git a/client/src/gamedata/ua/descriptions/levels/goodsamaritan.md b/client/src/gamedata/ua/descriptions/levels/goodsamaritan.md new file mode 100644 index 000000000..bfa924337 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/goodsamaritan.md @@ -0,0 +1,7 @@ +Цей екземпляр представляє доброго самарянина, який є багатим і готовим пожертвувати кілька монет будь-кому, хто цього запросить. + +Чи змогли б ви спустошити всю його гаманець? + +Речі, які можуть допомогти: + +- [Користувацькі помилки Solidity](https://blog.soliditylang.org/2021/04/21/custom-errors/) diff --git a/client/src/gamedata/ua/descriptions/levels/goodsamaritan_complete.md b/client/src/gamedata/ua/descriptions/levels/goodsamaritan_complete.md new file mode 100644 index 000000000..7797ca580 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/goodsamaritan_complete.md @@ -0,0 +1,3 @@ +Вітаємо! + +Користувацькі помилки в Solidity ідентифікуються за їх 4-байтовим 'селектором', таким же як і виклик функції. Вони піднімаються вгору по ланцюжку викликів, доки їх не зловить оператор catch в блоку try-catch, як це бачимо в функції `requestDonation()` у GoodSamaritan. З цих причин, не безпечно припускати, що помилка була викинута безпосередньо ціллю виклику контракту (тобто Wallet в цьому випадку). Будь-який інший контракт далі по ланцюжку викликів може оголосити ту саму помилку і викинути її в непередбачуваному місці, такому як функція `notify(uint256 amount)` у вашому контракті-атакувачі. diff --git a/client/src/gamedata/ua/descriptions/levels/instances.md b/client/src/gamedata/ua/descriptions/levels/instances.md new file mode 100644 index 000000000..cd4ce7413 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/instances.md @@ -0,0 +1,69 @@ +Цей рівень проводить вас через основи того, як грати в гру. + +  +#### 1. Налаштування MetaMask +Якщо у вас його ще немає, встановіть [розширення MetaMask для браузера](https://metamask.io/) (в Chrome, Firefox, Brave або Opera на вашому настільному комп'ютері). +Налаштуйте гаманець розширення і використовуйте вибір мережі, щоб вказати бажану мережу в верхньому лівому куті інтерфейсу розширення. Або ви можете використовувати кнопку UI для перемикання між мережами. Якщо ви виберете непідтримувану мережу, гра повідомить вас і переведе вас на тестову мережу Sepolia за замовчуванням. + +#### 2. Відкриття консолі браузера +Відкрийте консоль вашого браузера: `Інструменти > Інструменти розробника`. + +Ви повинні побачити кілька повідомлень від гри. Одне з них повинно вказувати адресу вашого гравця. Це буде важливо під час гри! Ви завжди можете побачити адресу вашого гравця, введіть наступну команду: + +`player` + +Слідкуйте за попередженнями та помилками, оскільки вони можуть надати важливу інформацію під час гри. + +#### 3. Використання помічників консолі + +Ви також можете побачити ваш поточний баланс ether, набравши: + +`getBalance(player)` + +###### ЗАМІТКА: Розгорніть обіцянку, щоб побачити реальне значення, навіть якщо воно відображається як "очікується". Якщо ви використовуєте Chrome v62, ви можете використовувати `await getBalance(player)` для більш комфортного використання консолі. + +Чудово! Щоб побачити, які інші службові функції у вас є в консолі, наберіть: + +`help()` + +Вони будуть надзвичайно корисними під час гри. + +#### 4. Контракт ethernaut +Введіть наступну команду в консоль: + +`ethernaut` + +Це основний розумний контракт гри. Вам не потрібно взаємодіяти з ним безпосередньо через консоль (оскільки цей додаток зробить це за вас), але ви можете, якщо хочете. Гратися з цим об'єктом зараз - чудовий спосіб дізнатися, як взаємодіяти з іншими розумними контрактами гри. + +Продовжуйте і розгорніть об'єкт ethernaut, щоб побачити, що всередині. + +#### 5. Взаємодія з ABI +`ethernaut` - це об'єкт `TruffleContract`, який обгортає контракт `Ethernaut.sol`, який був розгорнутий на блокчейні. + +Між іншим, ABI контракту відкриває всі публічні методи `Ethernaut.sol`, такі як `owner`. Наприклад, введіть наступну команду: + +`ethernaut.owner()` або `await ethernaut.owner()`, якщо ви використовуєте Chrome v62. + +Ви можете побачити, хто є власником контракту ethernaut. + +#### 6. Отримання тестового ether +Щоб грати в гру, вам потрібен тестовий ether. Найпростіший спосіб отримати деякий тестовий ether - це через діючий кран для вашої вибраної мережі. + +Як тільки ви побачите деякі монети на своєму балансі, перейдіть до наступного кроку. + +#### 7. Отримання екземпляру рівня +Коли ви граєте на рівні, ви не взаємодієте безпосередньо з контрактом ethernaut. Замість цього, ви просите його створити для вас **екземпляр рівня**. Щоб це зробити, натисніть кнопку "Отримати новий екземпляр" внизу сторінки. Зробіть це зараз та поверніться! + +Вам має бути запропоновано MetaMask авторизувати транзакцію. Зробіть це, і ви повинні побачити деякі повідомлення в консолі. Зверніть увагу, що це впроваджує новий контракт у блокчейн і може зайняти декілька секунд, тому будьте терплячими, коли запитуєте нові екземпляри рівня! + +#### 8. Інспектування контракту +Так само, як ви це зробили з контрактом ethernaut, ви можете інспектувати ABI цього контракту через консоль, використовуючи змінну `contract`. + +#### 9. Взаємодія з контрактом для завершення рівня +Ознайомтеся з методом info рівня `contract.info()` або `await contract.info()`, якщо ви використовуєте Chrome v62. +Ви повинні мати все, що вам потрібно, для завершення рівня в контракті. +Коли ви знаєте, що ви завершили рівень, надішліть контракт, використовуючи кнопку подачі внизу сторінки. +Це відправляє ваш екземпляр назад до ethernaut, який визначить, чи ви його завершили. + + +##### Порада: не забувайте, що ви завжди можете подивитися в ABI контракту! diff --git a/client/src/gamedata/ua/descriptions/levels/instances_complete.md b/client/src/gamedata/ua/descriptions/levels/instances_complete.md new file mode 100644 index 000000000..e5f5e7b36 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/instances_complete.md @@ -0,0 +1,6 @@ +Вітаємо! Ви завершили навчання. +Подивіться на код Solidity для контракту, з яким ви щойно взаємодіяли, нижче. + +Тепер ви готові пройти всі рівні гри, і з цього моменту ви самостійні. + +Швидкого вам просування!! diff --git a/client/src/gamedata/ua/descriptions/levels/king.md b/client/src/gamedata/ua/descriptions/levels/king.md new file mode 100644 index 000000000..e52ba06a7 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/king.md @@ -0,0 +1,5 @@ +Контракт нижче представляє дуже просту гру: той, хто надсилає йому суму ефіру, що більша за поточний приз, стає новим королем. При такій події, звергнутий король отримує новий приз, заробляючи трохи ефіру в процесі! Це чистий понзі xD + +Така весела гра. Ваша мета - зламати її. + +Коли ви подаєте екземпляр назад на рівень, рівень знову проголошує королівство. Ви пройдете рівень, якщо зможете уникнути такого самопроголошення. diff --git a/client/src/gamedata/ua/descriptions/levels/king_complete.md b/client/src/gamedata/ua/descriptions/levels/king_complete.md new file mode 100644 index 000000000..0564a3316 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/king_complete.md @@ -0,0 +1,3 @@ +Більшість рівнів Ethernaut намагається викрити (звичайно, у спрощеній формі) щось, що насправді сталося - реальний хак або реальний баг. + +У цьому випадку, див.: [King of the Ether](https://www.kingoftheether.com/thrones/kingoftheether/index.html) та [King of the Ether Postmortem](http://www.kingoftheether.com/postmortem.html). diff --git a/client/src/gamedata/ua/descriptions/levels/magicnum.md b/client/src/gamedata/ua/descriptions/levels/magicnum.md new file mode 100644 index 000000000..7841954f6 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/magicnum.md @@ -0,0 +1,11 @@ +Щоб вирішити цей рівень, вам потрібно лише надати Ethernaut `Solver`, контракту, який відповідає на `whatIsTheMeaningOfLife()` з правильним числом. + +Легко, правда? +Ну... є одне "але". + +Код вирішувача повинен бути дуже маленьким. Дійсно дууууже маленьким. Як справді дуже, дуже мініатюрний: максимум 10 опкодів. + +Підказка: Можливо, настав час на мить покинути комфорт компілятора Solidity і скласти цей один вручну O_o. +Так, ми говоримо про сиру EVM байт-коду. + +Удачі! diff --git a/client/src/gamedata/ua/descriptions/levels/magicnum_complete.md b/client/src/gamedata/ua/descriptions/levels/magicnum_complete.md new file mode 100644 index 000000000..2ddfb65c3 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/magicnum_complete.md @@ -0,0 +1,3 @@ +Вітаємо! Якщо ви вирішили цей рівень, вважайте себе Володарем Всесвіту. + +Тепер ви можете пронизати своїм взором будь-який предмет у кімнаті. Спробуйте перемістити його здалеку; можливо, у вас щойно почали працювати здібності телекінезу. diff --git a/client/src/gamedata/ua/descriptions/levels/motorbike.md b/client/src/gamedata/ua/descriptions/levels/motorbike.md new file mode 100644 index 000000000..8bff70b3c --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/motorbike.md @@ -0,0 +1,9 @@ +Мотоцикл Ethernaut має новий двигун з можливістю модернізації. + +Чи зможете ви `selfdestruct` його двигун і зробити мотоцикл непридатним для використання? + +Речі, які можуть допомогти: + +- [EIP-1967](https://eips.ethereum.org/EIPS/eip-1967) +- Шаблон модернізації [UUPS](https://forum.openzeppelin.com/t/uups-proxies-tutorial-solidity-javascript/7786) +- Контракт [Initializable](https://github.com/OpenZeppelin/openzeppelin-upgrades/blob/master/packages/core/contracts/Initializable.sol) diff --git a/client/src/gamedata/ua/descriptions/levels/motorbike_complete.md b/client/src/gamedata/ua/descriptions/levels/motorbike_complete.md new file mode 100644 index 000000000..a59840466 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/motorbike_complete.md @@ -0,0 +1,9 @@ +Перевагою використання шаблону UUPS є мінімальний проксі, який потрібно розгорнути. Проксі виступає як шар зберігання, тому будь-яка модифікація стану в контракті-реалізації зазвичай не викликає побічних ефектів для систем, що використовують його, оскільки через delegatecall використовується тільки логіка. + +Це не означає, що вам не слід бути обережними з вразливостями, які можуть бути експлуатовані, якщо ми залишимо контракт-реалізацію неініціалізованим. + +Це була трохи спрощена версія того, що насправді було виявлено через кілька місяців після випуску шаблону UUPS. + +Висновки: ніколи не залишайте контракти-реалізації неініціалізованими ;) + +Якщо ви зацікавлені в тому, що сталося, дізнайтеся більше [тут](https://forum.openzeppelin.com/t/uupsupgradeable-vulnerability-post-mortem/15680). diff --git a/client/src/gamedata/ua/descriptions/levels/naughtcoin.md b/client/src/gamedata/ua/descriptions/levels/naughtcoin.md new file mode 100644 index 000000000..5c7fd068b --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/naughtcoin.md @@ -0,0 +1,6 @@ +NaughtCoin є токеном ERC20 і ви вже володієте всіма їхніми копіями. Але існує певне "але" - ви зможете переказати їх тільки після 10-річного періоду блокування. Ви зможете знайти спосіб вивести їх на іншу адресу, щоб ви могли переказувати їх вільно? Завершіть цей рівень, знизивши баланс своїх токенів до 0. + +  +Може бути корисним: +* Специфікація [ERC20](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md) +* База коду [OpenZeppelin](https://github.com/OpenZeppelin/zeppelin-solidity/tree/master/contracts) diff --git a/client/src/gamedata/ua/descriptions/levels/naughtcoin_complete.md b/client/src/gamedata/ua/descriptions/levels/naughtcoin_complete.md new file mode 100644 index 000000000..a4c797006 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/naughtcoin_complete.md @@ -0,0 +1 @@ +Коли ви використовуєте код, який не є вашим власним, гарною ідеєю буде ознайомитись з ним, щоб добре зрозуміти, як все співпрацює. Це може бути особливо важливим, коли є кілька рівнів імпорту (ваши імпорти мають імпорти) або коли ви впроваджуєте контроль за доступом, наприклад, коли ви дозволяєте або забороняєте людям щось робити. У цьому прикладі розробник може просканувати код і подумати, що `transfer` - це єдиний спосіб переміщення токенів, але виявляється, існують інші способи виконання тієї самої операції з іншою реалізацією. diff --git a/client/src/gamedata/ua/descriptions/levels/preservation.md b/client/src/gamedata/ua/descriptions/levels/preservation.md new file mode 100644 index 000000000..ab3b7ca52 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/preservation.md @@ -0,0 +1,11 @@ +Цей контракт використовує бібліотеку для зберігання двох різних часів для двох різних часових поясів. Конструктор створює два екземпляри бібліотеки для кожного часу, який потрібно зберегти. + +Мета цього рівня - претендувати на власність над екземпляром, який вам надано. + +  Речі, які можуть допомогти +* Перегляньте документацію Solidity про функцію низького рівня `delegatecall`, + як вона працює, як вона може бути використана для делегування операцій до бібліотек на ланцюгу, + і які наслідки вона має для контексту виконання. +* Розуміння того, що означає "зберігання контексту" для `delegatecall`. +* Розуміння того, як змінні зберігаються та доступні. +* Розуміння того, як працює приведення типів між різними типами даних. diff --git a/client/src/gamedata/ua/descriptions/levels/preservation_complete.md b/client/src/gamedata/ua/descriptions/levels/preservation_complete.md new file mode 100644 index 000000000..b388076dc --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/preservation_complete.md @@ -0,0 +1,5 @@ +Як згадує попередній рівень `delegate`, використання `delegatecall` для виклику +бібліотек може бути ризикованим. Це особливо стосується контрактних бібліотек, які +мають свій власний стан. Цей приклад демонструє, чому слід використовувати ключове слово `library` +для створення бібліотек, оскільки воно перешкоджає бібліотекам +зберігання та доступ до змінних стану. diff --git a/client/src/gamedata/ua/descriptions/levels/privacy.md b/client/src/gamedata/ua/descriptions/levels/privacy.md new file mode 100644 index 000000000..7d80f2bd6 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/privacy.md @@ -0,0 +1,11 @@ +Творець цього контракту був достатньо обережний, щоб захистити чутливі області свого зберігання. + +Розблокуйте цей контракт, щоб пройти рівень. + +Що може допомогти: +* Розуміння того, як працює зберігання +* Розуміння того, як працює парсинг параметрів +* Розуміння того, як працює приведення типів + +Поради: +* Пам'ятайте, що metamask - це лише зручність. Використовуйте інший інструмент, якщо виникають проблеми. Просунута гра може включати використання remix або вашого власного провайдера web3. diff --git a/client/src/gamedata/ua/descriptions/levels/privacy_complete.md b/client/src/gamedata/ua/descriptions/levels/privacy_complete.md new file mode 100644 index 000000000..8f642db5e --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/privacy_complete.md @@ -0,0 +1,3 @@ +Ніщо в блокчейні Ethereum не є приватним. Ключове слово private - це лише штучна конструкція мови Solidity. `getStorageAt(...)` від Web3 можна використовувати для читання будь-чого зі зберігання. Однак, може бути складно прочитати те, що вам потрібно, оскільки використовуються декілька правил оптимізації та технік для максимального стиснення зберігання. + +Не можна ускладнити ситуацію більше, ніж те, що було виявлено на цьому рівні. Для отримання додаткової інформації перегляньте цю чудову статтю від "Darius": [Як читати зберігання контракту Ethereum](https://medium.com/aigang-network/how-to-read-ethereum-contract-storage-44252c8af925) diff --git a/client/src/gamedata/ua/descriptions/levels/puzzle_wallet.md b/client/src/gamedata/ua/descriptions/levels/puzzle_wallet.md new file mode 100644 index 000000000..d5b8b8661 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/puzzle_wallet.md @@ -0,0 +1,18 @@ +В наш час, оплата за операції DeFi є неможливою, факт. + +Група друзів виявила спосіб трохи зменшити вартість виконання кількох транзакцій, об'єднавши їх в одну транзакцію, тому вони розробили смарт-контракт для цього. + +Вони потребували, щоб цей контракт міг бути модернізований у випадку, якщо код містить помилку, і вони також хотіли запобігти використанню контракту людьми, що не належать до групи. Щоб цього досягти, вони проголосували та призначили двох людей з особливими ролями в системі: +Адміністратор, який має право оновлювати логіку смарт-контракту. +Власник, який контролює білий список адрес, дозволених для використання контрактом. +Контракти були розгорнуті, і група була внесена до білого списку. Всі віталися з їхніми досягненнями проти злих майнерів. + +Вони мало знали, що їх гроші на обід були під загрозою... + +  +Вам потрібно буде перехопити цей гаманець, щоб стати адміністратором проксі. + +  +Речі, які можуть допомогти: +* Розуміння того, як працює `delegatecall` та як поводиться `msg.sender` та `msg.value` при його виконанні. +* Знання про шаблони проксі та спосіб їх обробки змінних зберігання. diff --git a/client/src/gamedata/ua/descriptions/levels/puzzle_wallet_complete.md b/client/src/gamedata/ua/descriptions/levels/puzzle_wallet_complete.md new file mode 100644 index 000000000..3f1622587 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/puzzle_wallet_complete.md @@ -0,0 +1,7 @@ +На наступний раз ці друзі запросять аудиторську перевірку, перш ніж внести гроші в контракт. Вітаємо! + +Часто рекомендується використовувати проксі-контракти, щоб забезпечити можливість модернізації та зменшити витрати газу на розгортання. Проте розробники повинні бути обережні, щоб не виникло зіткнень у зберіганні, як це було в цьому рівні. + +Додатково, ітерування над операціями, що споживають ETH, може призвести до проблем, якщо це не контролюється відповідним чином. Навіть якщо ETH витрачено, `msg.value` залишиться таким же, тому розробник повинен самостійно відстежувати фактичну залишкову кількість при кожній ітерації. Це також може призвести до проблем при використанні мульти-виклику, оскільки виконання кількох `delegatecall` до функції, яка виглядає безпечною сама по собі, може призвести до небажаних переказів ETH, оскільки `delegatecall` зберігає оригінальний `msg.value`, відправлений контракту. + +Перейдіть на наступний рівень, коли будете готові! diff --git a/client/src/gamedata/ua/descriptions/levels/recovery.md b/client/src/gamedata/ua/descriptions/levels/recovery.md new file mode 100644 index 000000000..98c68d161 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/recovery.md @@ -0,0 +1,3 @@ +Створювач контракту розробив дуже простий контракт-фабрику токенів. Будь-хто може з легкістю створювати нові токени. Після розгортання першого контракту токену, створювач відправив `0.001` ефіра, щоб отримати більше токенів. З того часу вони втратили адресу контракту. + +Цей рівень буде завершено, якщо ви зможете відновити (або видалити) `0.001` ефіра з втраченої адреси контракту. diff --git a/client/src/gamedata/ua/descriptions/levels/recovery_complete.md b/client/src/gamedata/ua/descriptions/levels/recovery_complete.md new file mode 100644 index 000000000..74529fee4 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/recovery_complete.md @@ -0,0 +1,7 @@ +Ці адреси контрактів є детермінованими і обчислюються за допомогою `keccak256(address, nonce)`, де `address` - це адреса контракту (або ефірна адреса, яка створила транзакцію), а `nonce` - це кількість контрактів, які створив породжуючий контракт (або нонс транзакції, для звичайних транзакцій). + +Через це, можна відправити ефір на попередньо визначену адресу (яка не має приватного ключа) і пізніше створити контракт за цією адресою, який відновить ефір. Це неінтуїтивний та дещо таємничий спосіб (небезпечно) зберігати ефір без приватного ключа. + +Цікава [стаття в блозі](https://swende.se/blog/Ethereum_quirks_and_vulns.html) Мартіна Свенде деталізує потенційні сценарії використання цього. + +Якщо ви збираєтеся впроваджувати цю техніку, переконайтеся, що ви не пропустили нонс, інакше ваші кошти будуть втрачені назавжди. diff --git a/client/src/gamedata/ua/descriptions/levels/reentrancy.md b/client/src/gamedata/ua/descriptions/levels/reentrancy.md new file mode 100644 index 000000000..c5345960c --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/reentrancy.md @@ -0,0 +1,9 @@ +Мета цього рівня - вкрасти всі кошти з контракту. + +  +Речі, які можуть допомогти: +* Ненадійні контракти можуть виконувати код там, де ви цього найменше очікуєте. +* Запасні методи +* Викидання/відміна бульбашки +* Іноді найкращий спосіб атакувати контракт - це використовувати інший контракт. +* Дивіться сторінку ["?"](https://ethernaut.openzeppelin.com/help) вище, розділ "За консоллю" diff --git a/client/src/gamedata/ua/descriptions/levels/reentrancy_complete.md b/client/src/gamedata/ua/descriptions/levels/reentrancy_complete.md new file mode 100644 index 000000000..1b5cb2744 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/reentrancy_complete.md @@ -0,0 +1,12 @@ +Для того, щоб запобігти атакам реентрантности при виведенні коштів з вашого контракту, використовуйте [паттерн Перевірка-Ефекти-Взаємодії](https://solidity.readthedocs.io/en/develop/security-considerations.html#use-the-checks-effects-interactions-pattern), пам'ятаючи, що `call` лише поверне false, не перериваючи потік виконання. Можна також використовувати рішення, такі як [ReentrancyGuard](https://docs.openzeppelin.com/contracts/2.x/api/utils#ReentrancyGuard) або [PullPayment](https://docs.openzeppelin.com/contracts/2.x/api/payment#PullPayment). + +`transfer` та `send` вже не рекомендуються, оскільки вони можуть потенційно зламати контракти після хардфорку Istanbul [Джерело 1](https://diligence.consensys.net/blog/2019/09/stop-using-soliditys-transfer-now/) [Джерело 2](https://forum.openzeppelin.com/t/reentrancy-after-istanbul/1742). + +Завжди враховуйте, що одержувач коштів, які ви відправляєте, може бути іншим контрактом, а не просто звичайною адресою. Отже, він може виконувати код у своєму оплачуваному методі запасу і *повторно увійти* у ваш контракт, можливо, зіпсувавши ваш стан/логіку. + +Реентрантність - це поширена атака. Ви повинні завжди бути до неї готові! + +  +#### Хак DAO + +У знаменитій атакі DAO було використано реентрантність для виведення великої суми ефіру з потерпілого контракту. Дивіться [15 рядків коду, які могли б виключити можливість атаки на TheDAO](https://blog.openzeppelin.com/15-lines-of-code-that-could-have-prevented-thedao-hack-782499e00942). diff --git a/client/src/gamedata/ua/descriptions/levels/shop.md b/client/src/gamedata/ua/descriptions/levels/shop.md new file mode 100644 index 000000000..81a0905cf --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/shop.md @@ -0,0 +1,5 @@ +Чи можете ви отримати товар з магазину за ціну, яка нижча за запитану? + +##### Речі, які можуть допомогти: +* `Shop` очікує використання від `Buyer` +* Розуміння обмежень функцій перегляду diff --git a/client/src/gamedata/ua/descriptions/levels/shop_complete.md b/client/src/gamedata/ua/descriptions/levels/shop_complete.md new file mode 100644 index 000000000..1be26f5c4 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/shop_complete.md @@ -0,0 +1,3 @@ +Договори можуть маніпулювати даними, які бачать інші договори, як їм заманеться. + +Це небезпечно змінювати стан на основі логіки зовнішніх та недовірених договорів. diff --git a/client/src/gamedata/ua/descriptions/levels/switch.md b/client/src/gamedata/ua/descriptions/levels/switch.md new file mode 100644 index 000000000..859c9ced8 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/switch.md @@ -0,0 +1,4 @@ +Просто потрібно перевести перемикач. Не може бути так важко, правда? + +##### Що може допомогти: +Розуміння того, як кодується `CALLDATA`. diff --git a/client/src/gamedata/ua/descriptions/levels/switch_complete.md b/client/src/gamedata/ua/descriptions/levels/switch_complete.md new file mode 100644 index 000000000..b05bdc1ca --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/switch_complete.md @@ -0,0 +1 @@ +Припущення позицій в `CALLDATA` з динамічними типами може бути помилковим, особливо при використанні жорстко закодованих позицій `CALLDATA`. diff --git a/client/src/gamedata/ua/descriptions/levels/telephone.md b/client/src/gamedata/ua/descriptions/levels/telephone.md new file mode 100644 index 000000000..1b7332fe0 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/telephone.md @@ -0,0 +1,5 @@ +Заявіть про власність контракту нижче, щоб завершити цей рівень. + +  +Речі, які можуть допомогти +* Див. сторінку ["?"](https://ethernaut.openzeppelin.com/help) вище, розділ "За рамками консолі" diff --git a/client/src/gamedata/ua/descriptions/levels/telephone_complete.md b/client/src/gamedata/ua/descriptions/levels/telephone_complete.md new file mode 100644 index 000000000..6f2faace1 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/telephone_complete.md @@ -0,0 +1,21 @@ +Хоча цей приклад може бути простим, плутанина з `tx.origin` та `msg.sender` може призвести до атак типу "фішинг", таких як [ця](https://blog.ethereum.org/2016/06/24/security-alert-smart-contract-wallets-created-in-frontier-are-vulnerable-to-phishing-attacks/). + +Приклад можливої атаки наведено нижче. + +1) Використовуйте `tx.origin` для визначення, чиї токени перевести, наприклад: + +``` +function transfer(address _to, uint _value) { + tokens[tx.origin] -= _value; + tokens[_to] += _value; +} +``` +2) Атакуючий змушує жертву надіслати кошти зловмисному контракту, який викликає функцію переводу контракту токенів, наприклад: + +``` +function () payable { + token.transfer(attackerAddress, 10000); +} +``` + +3) У цьому сценарії `tx.origin` буде адресою жертви (поки `msg.sender` буде адресою зловмисного контракту), що призведе до переказу коштів від жертви до атакуючого. diff --git a/client/src/gamedata/ua/descriptions/levels/token.md b/client/src/gamedata/ua/descriptions/levels/token.md new file mode 100644 index 000000000..f897e97d9 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/token.md @@ -0,0 +1,7 @@ +Метою цього рівня є те, щоб вам взламати основний контракт токену нижче. + +Вам дається 20 токенів на початку, і ви пройдете рівень, якщо якимось чином зумієте заволодіти будь-якими додатковими токенами. Бажано дуже великою кількістю токенів. + +  +Речі, які можуть допомогти: +* Що таке одометр? diff --git a/client/src/gamedata/ua/descriptions/levels/token_complete.md b/client/src/gamedata/ua/descriptions/levels/token_complete.md new file mode 100644 index 000000000..eec73360d --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/token_complete.md @@ -0,0 +1,12 @@ +Переповнення дуже поширені в Solidity і їх потрібно перевіряти за допомогою контрольних операторів, таких як: +``` +if(a + c > a) { + a = a + c; +} +``` + +Легшою альтернативою є використання бібліотеки SafeMath від OpenZeppelin, яка автоматично перевіряє переповнення у всіх математичних операторах. Вихідний код виглядає так: +``` +a = a.add(c); +``` +Якщо стається переповнення, код відкочується. diff --git a/client/src/gamedata/ua/descriptions/levels/unstoppable.md b/client/src/gamedata/ua/descriptions/levels/unstoppable.md new file mode 100644 index 000000000..b04cb7b59 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/unstoppable.md @@ -0,0 +1,5 @@ +Є пул з позик, що має мільйон токенів на балансі, що пропонує миттєві позики безкоштовно. + +Якби тільки був спосіб атакувати та зупинити пул від пропозиції миттєвих позик ... + +Ви починаєте з балансом 100 токенів. diff --git a/client/src/gamedata/ua/descriptions/levels/vault.md b/client/src/gamedata/ua/descriptions/levels/vault.md new file mode 100644 index 000000000..371e34871 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/vault.md @@ -0,0 +1 @@ +Відкрийте сховище, щоб пройти рівень! diff --git a/client/src/gamedata/ua/descriptions/levels/vault_complete.md b/client/src/gamedata/ua/descriptions/levels/vault_complete.md new file mode 100644 index 000000000..be17ca758 --- /dev/null +++ b/client/src/gamedata/ua/descriptions/levels/vault_complete.md @@ -0,0 +1,3 @@ +Важливо пам'ятати, що позначення змінної як приватної лише перешкоджає доступу до неї інших контрактів. Змінні стану, позначені як приватні, та локальні змінні все ще доступні публічно. + +Щоб гарантувати, що дані є приватними, їх потрібно шифрувати перед тим, як вносити на блокчейн. У цьому сценарії ключ розшифровки ніколи не повинен надсилатися в блокчейн, оскільки тоді він буде видимий для всіх, хто його шукає. [zk-SNARKs](https://blog.ethereum.org/2016/12/05/zksnarks-in-a-nutshell/) надають спосіб визначити, чи має хтось секретний параметр, не розкриваючи ніколи цей параметр. diff --git a/client/src/gamedata/ua/strings.json b/client/src/gamedata/ua/strings.json new file mode 100644 index 000000000..72b6060a2 --- /dev/null +++ b/client/src/gamedata/ua/strings.json @@ -0,0 +1,114 @@ +{ + "ethernaut": "Ethernaut", + "title": "Ethernaut", + "hiring": "Ми наймаємо", + "info": "

Ethernaut це Web3/Solidity варгейм на базі Ethereum Virtual Machine, натхненний overthewire.org. Кожен рівень є смарт-контрактом, який потрібно 'зламати'. Вихідний код гри повністю відкритий, а всі рівні створені іншими гравцями. У тебе є цікава ідея для нового рівня?

", + "home": "Назад", + "help": "Допомога", + "stats": "Статистика", + "ethernautHelp": "Правила гри", + "footer": "розроблено з та командою OpenZeppelin", + "english": "English", + "arabic": "عربي", + "spanish": "Español", + "ukrainian": "Українська", + "portuguese": "Português", + "japanese": "日本語", + "turkish": "Türkçe", + "chinese_simplified": "簡體中文", + "chinese_traditional": "正體中文", + "french": "Français", + "russian": "Русский", + "playNow": "Грати!", + "toggleNavigation": "Показати або приховати панель навігації", + "levelCompleted": "Рівень пройдено!", + "sources": "Вихідний код", + "submitInstance": "Надіслати інстанс на перевірку", + "getNewInstance": "Створити новий інстанс", + "deployMessageTitle": "Гра не розгорнута", + "deployMessage": "На даний момент гра підтримує тільки ці мережі:", + "deployConfirmation": "Ви хочете розгорнути контракти в цій мережі або переключитись на мережу Sepolia??", + "deployNote": "Примітка. Якщо ви розгорнете всі рівні, ми порадимо вам відправити всю розгорнуту гру в цю мережу.", + "deployGame": "Розгорнути гру", + "switchToSepolia": "Переключитись на Sepolia", + "deployLevel": "Рівень розгортання", + "helperDeployAllContracts": "Розгорніть всі залишені контракти в поточній мережі.", + "confirmMainnetDeploy": "Ви перебуваєте в основній мережі, гра не має грошової вартості, вам не слід розгортати її в цій мережі.", + "submitLevelFooter": "Розгорніть всі рівні (deployAllContracts() в консолі), щоб додати поточну мережу в наш репозиторій Github як нову підтримувану мережу.", + "submitGameFooter": "Чудово! Вся гра розгорнута в цій мережі. Натисніть тут, щоб висунути питання на GitHub і відправити його нам :)", + "nextLevel": "Наступний рівень", + "uLevels": "Рівні", + "lLevels": "рівні", + "refresh": "Оновити", + "uCompleted": "Пройдено", + "lCompleted": "пройдено", + "players": "Гравці", + "player": "Гравець", + "levelName": "Назва рівня", + "levelAddress": "Адреса рівня", + "blockNum": "Номер блоку", + "uCreated": "Створено", + "lCreated": "створено", + "instance": "Інстанс", + "numberOf": "Кількість", + "warning": "Попередження", + "warningMessage": "Провайдер web3 відсутній, і гра знаходиться в режимі тільки для читання", + "levelAuthor": "Автор(и) рівня:", + "pleaseWait": "БУДЬ ЛАСКА, ЗАЧЕКАЙТЕ", + "donate": "Рівень допоміг вам дізнатись щось нове? У вас є можливість підтримати автора(ів) цього рівня (на мейннеті):", + "openConsole": "ВІДКРИЙТЕ КОНСОЛЬ БРАУЗЕРА (More Tools - Developer Tools - Console), ЩОБ РОЗПОЧАТИ ГРУ", + "difficulty": "Складність", + "error": "Помилка", + "retrying": "повторюю запит...", + "typeHelpMessage": "Введи help() щоб отримати список об'єктів і функцій, які допоможуть тобі в процесі гри", + "slowNetworkMessage": "Повідомлення 'Slow network detected' можна приховати за допомогою пункту 'Показувати тільки користувацькі повідомлення' в інструментах розробника або флага 'chrome://flags/#enable-webfonts-intervention-v2'", + "notContractSetMessage": "Інстанс не знайдено, натисни 'Створити новий інстанс' на сторінці з рівнем, щоб створити новий інстанс", + "levelAddressMessage": "Адреса рівня", + "instanceAddressMessage": "Адреса інстанса", + "playerAddressMessage": "Адреса гравця", + "selectedNetworkMessage": "Поточна мережа: ", + "ethernautAddressMessage": "Адреса Ethernaut-а", + "noLevelsDataMessage": "Дані рівнів не знайдено", + "ethernautNotFoundMessage": "Контракт Ethernaut не знайдено в поточній мережі. Будь ласка, переконайтеся, що (1) ви використовуєте MetaMask, (2) воно працює в підтримуваній мережі, (3) воно розблоковано, (4, необов'язково) з 2 листопада ви можете увімкнути приватний режим (вимкнений за замовчуванням) в налаштуваннях MetaMask, якщо не хочете відкривати свою інформацію за замовчуванням. (5, необов'язково) Якщо приватний режим увімкнено, ви повинні дозволити MetaMask використовувати цю сторінку. І (6) потім оновіть сторінку.", + "requestingNewInstanceMessage": "Запитую новий інстанс...", + "unableToRetrieveLevelMessage": "Не вдалося отримати інстанс! Перевірте параметри газу і спробуйте запросити інстанс знову.", + "transactionNoLogsMessage": "Транзакція не містить журналів", + "noPlayerAddressMessage": "Адресу гравця не виявлено! Переконайтеся, що MetaMask плагін (1) встановлено і (2) розблоковано. Якщо в MetaMask увімкнено приватний режим, то в налаштуваннях MetaMask вам необхідно авторизувати поточну сторінку. Оновіть сторінку після виконання вищезазначених дій.", + "noEthersMessage": "Ой, у вас немає ефіру! Отримайте його в дійсному крані для вашої обраної мережі", + "submitLevelMessage": "Інстанс перевіряється...", + "wellDoneMessage": "Чудово", + "completedLevelMessage": "Рівень пройдено!", + "uncompletedLevelMessage": "Ой! Здається, ви ще не взломали цей рівень", + "metamaskKnownIssue": "Ой! Ймовірно, виникла проблема з MetaMask. Спробуйте вимкнути та увімкнути плагін MetaMask. Якщо це не вирішило проблему, то перезавантажте браузер.", + "eventsCompletionMessage": "Під час обробки подій сталася помилка:", + "unexpectedAddressMessage": "Неочікувана адреса в події LevelCompletedLog:", + "helperPlayer": "адреса гравця", + "helperEthernaut": "адреса Ethernaut-а", + "helperLevel": "адреса поточного рівня", + "helperContract": "об'єкт поточного рівня (якщо створено)", + "helperInstance": "об'єкт поточного інстансу (якщо створено)", + "helperVersion": "версія гри", + "helperGetBalance": "отримати баланс адреси (одиниця вимірювання: ефір)", + "helperGetBlockNumber": "отримати номер останнього блоку", + "helperSendTransaction": "надіслати транзакцію", + "helperGetNetworkId": "отримати ідентифікатор мережі", + "helperToWei": "конвертувати число з ефіру в вей", + "helperFromWei": "конвертувати число з вей в ефір", + "levelNotTranslated": "Цей рівень не перекладено українською мовою або переклад не завершено. ", + "contributeTranslation": "Вдосконалити переклад", + "usingConsole": "Взаємодія з грою відбувається через консоль браузера. Щоб отримати список об'єктів та функцій, які допоможуть вам у грі, введіть у консолі браузера команду:\n\nhelp()\n\n Більшість функцій асинхронні, тому вам знадобиться ключове слово await. Наприклад, замість:\n\ngetBalance(player)\n> PROMISE\n\nкраще використовувати:\n\nawait getBalance(player)\n> '1.11002387'\n\n", + "gameMechanics": "За допомогою веб-інтерфейсу гравець запитує створення нового інстансу. Запит направляється в контракт Ethernaut.sol, який, у свою чергу, делегує запит відповідному рівню, кожен з яких успадковується від контракта Level.sol та створює новий інстанс. Після цього гравець взаємодіє з інстансом до тих пір, поки не 'зламає' його, після чого надсилає інстанс на перевірку за допомогою веб-інтерфейса.\n\nЗ кожним інстансом можна взаємодіяти через консоль браузера як з об'єктом типу TruffleContract. Більше інформації про механіку гри можна знайти в описі першого рівня.", + "beyondConsole": "Для проходження деяких рівнів вам знадобиться написати код на мові Solidity, скомпілювати його в байткод і викласти байткод в мережу. Ці кроки можна виконати за допомогою різних інструментів, наприклад:\n\n1) Remix Solidity IDE\n\n2) Hardhat\n\n3) Truffle Framework", + "troubleshooting": "При виникненні проблем спробуйте: (1) оновити сторінку, (2) вимкнути та увімкнути MetaMask, (3) перезавантажити браузер, (4) очистити куки та інші дані сторінки.\n\nЯкщо після виконання цих кроків проблема не вирішена, повідомити про проблему можна за адресою ethernaut@zeppelin.solutions.", + "poweredBy": "підтримується", + "setupMetamask": "Якщо у вас ще немає, встановіть розширення браузера MetaMask (в Chrome, Firefox, Brave або Opera на вашому настільному комп'ютері). \n\n Налаштуйте гаманець розширення та використайте вибір мережі, щоб вказати бажану мережу у верхній лівій частині інтерфейсу розширення. Ви також можете використовувати кнопку користувацького інтерфейсу для перемикання між мережами. Якщо ви виберете непідтримувану мережу, гра повідомить вас і перенесе вас до тестової мережі Sepolia за замовчуванням. \n\nПісля завершення поверніться сюди та перезавантажте веб-сторінку", + "FifthyPercentMessage": "Чудова робота! Ви вже на півдорозі до Ethernaut і досить добре вправляєтеся в ламанні речей. Працювати дослідником безпеки блокчейну в OpenZeppelin могло б бути весело... https://grnh.se/fdbf1c043us", + "SeventyFivePercentMessage": "75%: Добра робота... ви вже глибоко в кроличій норі.... хто знає, куди вона вас приведе... https://grnh.se/d4a786e43us", + "NinetyPercentMessage": "90%: Ви майже там! Лишилося лише кілька викликів, поки ви не завершите Ethernaut! Чи розглядали ви кар'єру в області безпеки блокчейну?https://grnh.se/cfcca8c83us", + "HundredPercentMessage": "100%: Вітаємо! Ваша подорож по кроличій норі web3 вражає і заслуговує на святкування! Тепер у вас є навички ламати розумні контракти! Що далі звідси? Подайте заявку на посаду дослідника безпеки блокчейну в OpenZeppelin і долучіться до захисту провідних протоколів у web3! https://grnh.se/26c05aac3us", + "Menu": "Меню", + "Networks": "Мережі", + "Languages": "Мови", + "PageNotFoundTitle": "Помилка 404 - Сторінку не знайдено", + "PageNotFoundText": "Ой! Сторінка, яку ви шукаєте, не може бути знайдена." +} diff --git a/client/src/gamedata/zh_cn/strings.json b/client/src/gamedata/zh_cn/strings.json index cff160734..a4bc26518 100644 --- a/client/src/gamedata/zh_cn/strings.json +++ b/client/src/gamedata/zh_cn/strings.json @@ -11,6 +11,7 @@ "english": "English", "arabic": "عربي", "spanish": "Español", + "ukrainian": "Українська", "portuguese": "Português", "japanese": "日本語", "turkish": "Türkçe", diff --git a/client/src/gamedata/zh_tw/strings.json b/client/src/gamedata/zh_tw/strings.json index d7e3f36ec..c2c197001 100644 --- a/client/src/gamedata/zh_tw/strings.json +++ b/client/src/gamedata/zh_tw/strings.json @@ -11,6 +11,7 @@ "english": "English", "arabic": "عربي", "spanish": "Español", + "ukrainian": "Українська", "portuguese": "Português", "japanese": "日本語", "turkish": "Türkçe", diff --git a/package.json b/package.json index 114594912..3cf7dc40a 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "compile:contracts": "cd contracts && hardhat clean && hardhat compile", "deploy:contracts": "yarn compile:contracts && node --experimental-json-modules client/scripts/deploy_contracts.mjs", "upgrade:proxy": "yarn compile:contracts && node --experimental-json-modules client/scripts/upgrade_proxy.mjs", - "supersede:level": "yarn compile:contracts && node --experimental-json-modules client/scripts/supersede_level.mjs", + "supersede:level": "yarn compile:contracts && node --experimental-json-modules client/scripts/supersede_level.mjs", "network": "cd contracts && hardhat node", "build:ethernaut": "yarn compile:contracts && yarn --cwd client build", "start:ethernaut": "cd client && yarn start", @@ -28,4 +28,4 @@ "leaderboard:newCrawler": "node client/leaderboard/scripts/crawlers/crawlNewData/index.cjs", "leaderboard:triggerNextCrawl": "node client/leaderboard/scripts/actuate/index.cjs" } -} \ No newline at end of file +}