Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add Vietnamese translation #680

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 37 additions & 30 deletions client/src/containers/Header.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from "react";
import onClickOutside from 'react-onclickoutside'
import onClickOutside from "react-onclickoutside";
import { connect } from "react-redux";
import { withRouter } from "../hoc/withRouter";
import { Link } from "react-router-dom";
Expand Down Expand Up @@ -223,7 +223,7 @@ class Header extends React.Component {

handleClickOutside = () => {
this.closeDropdown();
}
};

render() {
let strings = loadTranslations(this.state.lang);
Expand All @@ -239,8 +239,9 @@ class Header extends React.Component {
ru: strings.russian,
ar: strings.arabic,
tr: strings.turkish,
vi: strings.vietnamese,
};

const ddOpen = Boolean(this.state.multiDDOpen);
return (
<div onClick={() => this.closeDropdown()}>
Expand Down Expand Up @@ -316,14 +317,14 @@ class Header extends React.Component {
</div>
{window.location.pathname === constants.PATH_ROOT &&
!!this.props.web3 && (
<Link onClick={() => this.toggleDropdownState()}
to={constants.PATH_LEADERBOARD}>
<div
className="element-in-row filled-icon">
<LeaderIcon />
<Link
onClick={() => this.toggleDropdownState()}
to={constants.PATH_LEADERBOARD}
>
<div className="element-in-row filled-icon">
<LeaderIcon />
</div>
</Link>

)}
<input
onClick={() => {
Expand All @@ -345,26 +346,29 @@ class Header extends React.Component {
<span>{strings.Networks}</span>
</p>
<div className={this.getDDClassName(2)}>
{Object.values(constants.NETWORKS_INGAME).map((network, index) => {
if (network && network.name !== "local") {
if (Number(network.id) === this.state.chainId)
return false; // filter out current network
return (
<div key={index}
onClick={(e) => {
e.preventDefault();
this.changeNetwork(network);
}}
className="dropdown-pill"
>
<a id={network.name} key={network.name} href="/">
{network.name}
</a>
</div>
);
{Object.values(constants.NETWORKS_INGAME).map(
(network, index) => {
if (network && network.name !== "local") {
if (Number(network.id) === this.state.chainId)
return false; // filter out current network
return (
<div
key={index}
onClick={(e) => {
e.preventDefault();
this.changeNetwork(network);
}}
className="dropdown-pill"
>
<a id={network.name} key={network.name} href="/">
{network.name}
</a>
</div>
);
}
return null;
}
return null;
})}
)}
</div>
</div>

Expand All @@ -375,7 +379,8 @@ class Header extends React.Component {
</p>
<div className={this.getDDClassName(1)}>
{Object.keys(LANGUAGES_MAP).map((languageString, index) => (
<div key={index}
<div
key={index}
onClick={(e) => {
this.changeLanguage(e, languageString);
}}
Expand Down Expand Up @@ -455,4 +460,6 @@ function mapDispatchToProps(dispatch) {
);
}

export default withRouter(connect(mapStateToProps, mapDispatchToProps)(onClickOutside(Header)));
export default withRouter(
connect(mapStateToProps, mapDispatchToProps)(onClickOutside(Header))
);
2 changes: 1 addition & 1 deletion client/src/gamedata/ar/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"chinese_traditional": "正體中文",
"french": "Français",
"russian": "Русский",
"vietnamese": "Vietnamese",
"playNow": "العب الان!",
"toggleNavigation": "تصفح",
"levelCompleted": "انتهي المستوى!",
Expand Down Expand Up @@ -110,5 +111,4 @@
"Languages": "اللغات",
"PageNotFoundTitle": "خطأ 404 - الصفحة غير موجودة",
"PageNotFoundText": "عفوًا! لا يمكن العثور على الصفحة التي تبحث عنها."

}
1 change: 1 addition & 0 deletions client/src/gamedata/en/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"chinese_traditional": "正體中文",
"french": "Français",
"russian": "Русский",
"vietnamese": "Vietnamese",
"playNow": "Play now!",
"toggleNavigation": "Toggle navigation",
"levelCompleted": "Level completed!",
Expand Down
1 change: 1 addition & 0 deletions client/src/gamedata/es/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"chinese_traditional": "正體中文",
"french": "Français",
"russian": "Русский",
"vietnamese": "Vietnamese",
"playNow": "Juega ahora!",
"toggleNavigation": "Despliega la navegación",
"levelCompleted": "Nivel completado!",
Expand Down
1 change: 1 addition & 0 deletions client/src/gamedata/fr/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"chinese_traditional": "正體中文",
"french": "Français",
"russian": "Русский",
"vietnamese": "Vietnamese",
"playNow": "Jouer maintenant!",
"toggleNavigation": "Basculer la navigation",
"levelCompleted": "Niveau terminé!",
Expand Down
1 change: 1 addition & 0 deletions client/src/gamedata/ja/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"chinese_traditional": "正體中文",
"french": "Français",
"russian": "Русский",
"vietnamese": "Vietnamese",
"playNow": "プレイ!",
"toggleNavigation": "トグルナビゲーション",
"levelCompleted": "レベル クリア!",
Expand Down
1 change: 1 addition & 0 deletions client/src/gamedata/pt_br/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"chinese_traditional": "正體中文",
"french": "Français",
"russian": "Русский",
"vietnamese": "Vietnamese",
"playNow": "Jogue agora!",
"toggleNavigation": "Exibir a navegação",
"levelCompleted": "Nível completado!",
Expand Down
1 change: 1 addition & 0 deletions client/src/gamedata/ru/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"french": "Français",
"russian": "Русский",
"playNow": "Играть!",
"vietnamese": "Vietnamese",
"toggleNavigation": "Показать или скрыть панель навигации",
"levelCompleted": "Уровень пройден!",
"sources": "Исходный код",
Expand Down
1 change: 1 addition & 0 deletions client/src/gamedata/tr/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"chinese_traditional": "正體中文",
"french": "Français",
"russian": "Русский",
"vietnamese": "Vietnamese",
"playNow": "Şimdi oyna!",
"toggleNavigation": "Gezinmeyi Aç/Kapa",
"levelCompleted": "Seviye tamamlandı!",
Expand Down
7 changes: 7 additions & 0 deletions client/src/gamedata/vi/descriptions/levels/aliencodex.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
You've uncovered an Alien contract. Claim ownership to complete the level.

&nbsp;
Things that might help
* Understanding how array storage works
* Understanding [ABI specifications](https://solidity.readthedocs.io/en/v0.4.21/abi-spec.html)
* Using a very `underhanded` approach
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
This level exploits the fact that the EVM doesn't validate an array's ABI-encoded length vs its actual payload.

Additionally, it exploits the arithmetic underflow of array length, by expanding the array's bounds to the entire storage area of `2^256`. The user is then able to modify all contract storage.

Both vulnerabilities are inspired by 2017's [Underhanded coding contest](https://medium.com/@weka/announcing-the-winners-of-the-first-underhanded-solidity-coding-contest-282563a87079)
5 changes: 5 additions & 0 deletions client/src/gamedata/vi/descriptions/levels/coinflip.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
This is a coin flipping game where you need to build up your winning streak by guessing the outcome of a coin flip. To complete this level you'll need to use your psychic abilities to guess the correct outcome 10 times in a row.

&nbsp;
Things that might help
* See the ["?"](https://ethernaut.openzeppelin.com/help) page above in the top right corner menu, section "Beyond the console"
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Generating random numbers in solidity can be tricky. There currently isn't a native way to generate them, and everything you use in smart contracts is publicly visible, including the local variables and state variables marked as private. Miners also have control over things like blockhashes, timestamps, and whether to include certain transactions - which allows them to bias these values in their favor.

To get cryptographically proven random numbers, you can use [Chainlink VRF](https://docs.chain.link/docs/get-a-random-number), which uses an oracle, the LINK token, and an on-chain contract to verify that the number is truly random.

Some other options include using Bitcoin block headers (verified through [BTC Relay](http://btcrelay.org)), [RANDAO](https://github.com/randao/randao), or [Oraclize](http://www.oraclize.it/)).

7 changes: 7 additions & 0 deletions client/src/gamedata/vi/descriptions/levels/delegate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
The goal of this level is for you to claim ownership of the instance you are given.

&nbsp;
Things that might help
* Look into Solidity's documentation on the `delegatecall` low level function, how it works, how it can be used to delegate operations to on-chain libraries, and what implications it has on execution scope.
* Fallback methods
* Method ids
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Usage of `delegatecall` is particularly risky and has been used as an attack vector on multiple historic hacks. With it, your contract is practically saying "here, -other contract- or -other library-, do whatever you want with my state". Delegates have complete access to your contract's state. The `delegatecall` function is a powerful feature, but a dangerous one, and must be used with extreme care.


Please refer to the [The Parity Wallet Hack Explained](https://blog.openzeppelin.com/on-the-parity-wallet-multisig-hack-405a8c12e8f7) article for an accurate explanation of how this idea was used to steal 30M USD.

5 changes: 5 additions & 0 deletions client/src/gamedata/vi/descriptions/levels/denial.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
This is a simple wallet that drips funds over time. You can withdraw the funds
slowly by becoming a withdrawing partner.

If you can deny the owner from withdrawing funds when they call `withdraw()`
(whilst the contract still has funds, and the transaction is of 1M gas or less) you will win this level.
12 changes: 12 additions & 0 deletions client/src/gamedata/vi/descriptions/levels/denial_complete.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
This level demonstrates that external calls to unknown contracts can still
create denial of service attack vectors if a fixed amount of gas is not
specified.

If you are using a low level `call` to continue executing in the event an external call reverts, ensure that you specify a fixed gas stipend. For example `call.gas(100000).value()`.

Typically one should follow the [checks-effects-interactions](http://solidity.readthedocs.io/en/latest/security-considerations.html#use-the-checks-effects-interactions-pattern) pattern to avoid reentrancy attacks, there can be other circumstances (such as multiple external calls at the end of a function) where issues such as this can arise.

*Note*: An external `CALL` can use at most 63/64 of the gas currently available
at the time of the `CALL`. Thus, depending on how much gas is required to
complete a transaction, a transaction of sufficiently high gas (i.e. one such
that 1/64 of the gas is capable of completing the remaining opcodes in the parent call) can be used to mitigate this particular attack.
18 changes: 18 additions & 0 deletions client/src/gamedata/vi/descriptions/levels/dex.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
The goal of this level is for you to hack the basic [DEX](https://en.wikipedia.org/wiki/Decentralized_exchange) contract below and steal the funds by price manipulation.

You will start with 10 tokens of `token1` and 10 of `token2`. The DEX contract starts with 100 of each token.

You will be successful in this level if you manage to drain all of at least 1 of the 2 tokens from the contract, and allow the contract to report a "bad" price of the assets.

&nbsp;
### Quick note
Normally, when you make a swap with an ERC20 token, you have to `approve` the contract to spend your tokens for you. To keep with the syntax of the game, we've just added the `approve` method to the contract itself. So feel free to use `contract.approve(contract.address, <uint amount>)` instead of calling the tokens directly, and it will automatically approve spending the two tokens by the desired amount. Feel free to ignore the `SwappableToken` contract otherwise.

&nbsp;
Things that might help:
* How is the price of the token calculated?
* How does the `swap` method work?
* How do you `approve` a transaction of an ERC20?
* Theres more than one way to interact with a contract!
* Remix might help
* What does "At Address" do?
9 changes: 9 additions & 0 deletions client/src/gamedata/vi/descriptions/levels/dex2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
This level will ask you to break `DexTwo`, a subtlely modified `Dex` contract from the previous level, in a different way.

You need to drain all balances of token1 and token2 from the `DexTwo` contract to succeed in this level.

You will still start with 10 tokens of `token1` and 10 of `token2`. The DEX contract still starts with 100 of each token.

&nbsp;
Things that might help:
* How has the `swap` method been modified?
9 changes: 9 additions & 0 deletions client/src/gamedata/vi/descriptions/levels/dex2_complete.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
As we've repeatedly seen, interaction between contracts can be a source of unexpected behavior.

Just because a contract claims to implement the [ERC20 spec](https://eips.ethereum.org/EIPS/eip-20) does not mean it's trust worthy.

Some tokens deviate from the ERC20 spec by not returning a boolean value from their `transfer` methods. See [Missing return value bug - At least 130 tokens affected](https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca).

Other ERC20 tokens, especially those designed by adversaries could behave more maliciously.

If you design a DEX where anyone could list their own tokens without the permission of a central authority, then the correctness of the DEX could depend on the interaction of the DEX contract and the token contracts being traded.
58 changes: 58 additions & 0 deletions client/src/gamedata/vi/descriptions/levels/dex_complete.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
The integer math portion aside, getting prices or any sort of data from any single source is a massive attack vector in smart contracts.

You can clearly see from this example, that someone with a lot of capital could manipulate the price in one fell swoop, and cause any applications relying on it to use the the wrong price.

The exchange itself is decentralized, but the price of the asset is centralized, since it comes from 1 dex. However, if we were to consider tokens that represent actual assets rather than fictitious ones, most of them would have exchange pairs in several dexes and networks. This would decrease the effect on the asset's price in case a specific dex is targeted by an attack like this.

[Oracles](https://betterprogramming.pub/what-is-a-blockchain-oracle-f5ccab8dbd72?source=friends_link&sk=d921a38466df8a9176ed8dd767d8c77d) are used to get data into and out of smart contracts.

[Chainlink Data Feeds](https://docs.chain.link/docs/get-the-latest-price) are a secure, reliable, way to get decentralized data into your smart contracts. They have a vast library of many different sources, and also offer [secure randomness](https://docs.chain.link/docs/chainlink-vrf), ability to make [any API call](https://docs.chain.link/docs/make-a-http-get-request), [modular oracle network creation](https://docs.chain.link/docs/architecture-decentralized-model), [upkeep, actions, and maintainance](https://docs.chain.link/docs/kovan-keeper-network-beta), and unlimited customization.

[Uniswap TWAP Oracles](https://docs.uniswap.org/contracts/v2/concepts/core-concepts/oracles) relies on a time weighted price model called [TWAP](https://en.wikipedia.org/wiki/Time-weighted_average_price#). While the design can be attractive, this protocol heavily depends on the liquidity of the DEX protocol, and if this is too low, prices can be easily manipulated.


Here is an example of getting the price of Bitcoin in USD from a Chainlink data feed (on the Sepolia testnet):

```
// 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: 0x1b44F3514812d835EB1BDB0acB33d3fA3351Ee43
*/
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;
}
}

```
[Try it on Remix](https://remix.ethereum.org/#url=https://docs.chain.link/samples/PriceFeeds/PriceConsumerV3.sol)

Check the Chainlink feed [page](https://data.chain.link/ethereum/mainnet/crypto-usd/btc-usd) to see that the price of Bitcoin is queried from up to 31 different sources.

You can check also, the [list](https://docs.chain.link/data-feeds/price-feeds/addresses/) all Chainlink price feeds addresses.

10 changes: 10 additions & 0 deletions client/src/gamedata/vi/descriptions/levels/doubleentrypoint.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
This level features a `CryptoVault` with special functionality, the `sweepToken` function. This is a common function used to retrieve tokens stuck in a contract. The `CryptoVault` operates with an `underlying` token that can't be swept, as it is an important core logic component of the `CryptoVault`. Any other tokens can be swept.

The underlying token is an instance of the DET token implemented in the `DoubleEntryPoint` contract definition and the `CryptoVault` holds 100 units of it. Additionally the `CryptoVault` also holds 100 of `LegacyToken LGT`.

In this level you should figure out where the bug is in `CryptoVault` and protect it from being drained out of tokens.

The contract features a `Forta` contract where any user can register its own `detection bot` contract. Forta is a decentralized, community-based monitoring network to detect threats and anomalies on DeFi, NFT, governance, bridges and other Web3 systems as quickly as possible. Your job is to implement a `detection bot` and register it in the `Forta` contract. The bot's implementation will need to raise correct alerts to prevent potential attacks or bug exploits.

Things that might help:
- How does a double entry point work for a token contract?
Loading