From e029153586bc1b260e8628cd37fedc729a2d391d Mon Sep 17 00:00:00 2001 From: Ahmad Alfawwaz Date: Sat, 21 May 2022 01:01:33 +0100 Subject: [PATCH 1/7] Create level 'Switch' --- .../gamedata/en/descriptions/levels/switch.md | 5 ++ .../en/descriptions/levels/switch_complete.md | 6 ++ contracts/contracts/attacks/SwitchAttack.sol | 13 +++++ contracts/contracts/levels/Switch.sol | 35 ++++++++++++ contracts/contracts/levels/SwitchFactory.sol | 17 ++++++ contracts/test/levels/Switch.test.js | 57 +++++++++++++++++++ yarn.lock | 13 +++-- 7 files changed, 142 insertions(+), 4 deletions(-) create mode 100644 client/src/gamedata/en/descriptions/levels/switch.md create mode 100644 client/src/gamedata/en/descriptions/levels/switch_complete.md create mode 100644 contracts/contracts/attacks/SwitchAttack.sol create mode 100644 contracts/contracts/levels/Switch.sol create mode 100644 contracts/contracts/levels/SwitchFactory.sol create mode 100644 contracts/test/levels/Switch.test.js diff --git a/client/src/gamedata/en/descriptions/levels/switch.md b/client/src/gamedata/en/descriptions/levels/switch.md new file mode 100644 index 000000000..7f4392099 --- /dev/null +++ b/client/src/gamedata/en/descriptions/levels/switch.md @@ -0,0 +1,5 @@ +Claim ownership of the contract below to complete this level. + +  +Things that might help +* See the Help page above, section "Beyond the console" diff --git a/client/src/gamedata/en/descriptions/levels/switch_complete.md b/client/src/gamedata/en/descriptions/levels/switch_complete.md new file mode 100644 index 000000000..e2e3b5419 --- /dev/null +++ b/client/src/gamedata/en/descriptions/levels/switch_complete.md @@ -0,0 +1,6 @@ +Signature verification is a sensitive operation and improper use can lead to impersonation attacks. +The resulting vulnerability is made more significant when impersonation can lead to privilege escalation +or unauthorized access to funds. This level demonstrates why it is important to understand signature +generation and validation. Refer to the +[signature verification page](https://docs.openzeppelin.com/contracts/2.x/utilities#checking_signatures_on_chain) +on OpenZeppelin contracts to learn more. \ No newline at end of file diff --git a/contracts/contracts/attacks/SwitchAttack.sol b/contracts/contracts/attacks/SwitchAttack.sol new file mode 100644 index 000000000..d745eabf1 --- /dev/null +++ b/contracts/contracts/attacks/SwitchAttack.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.6.0; + +import '../levels/Switch.sol'; + +contract SwitchAttack { + function attack(address _target, address _player, uint8 v, bytes32 r, bytes32 s) public { + Switch target = Switch(_target); + target.changeOwnership(v, r, s); + target.changeOwnership(_player); + } +} \ No newline at end of file diff --git a/contracts/contracts/levels/Switch.sol b/contracts/contracts/levels/Switch.sol new file mode 100644 index 000000000..6050ec822 --- /dev/null +++ b/contracts/contracts/levels/Switch.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +contract Switch { + address public owner; + + modifier onlyOwner { + require( + msg.sender == owner, + "caller is not the owner" + ); + _; + } + + constructor() public { + owner = msg.sender; + } + + // Changes the ownership of the contract. Can only be called by the owner. + function changeOwnership(address _owner) public onlyOwner { + owner = _owner; + } + + // Changes the ownership of the contract to the sender provided the signature is created by the owner + function changeOwnership(uint8 v, bytes32 r, bytes32 s) public { + require(ecrecover(generateHash(owner), v, r, s) != address(0), "signer is not the owner"); + owner = msg.sender; + } + + // Generates a hash compatible with EIP-191 signatures + function generateHash(address _addr) private pure returns (bytes32) { + bytes32 addressHash = keccak256(abi.encodePacked(_addr)); + return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", addressHash)); + } +} diff --git a/contracts/contracts/levels/SwitchFactory.sol b/contracts/contracts/levels/SwitchFactory.sol new file mode 100644 index 000000000..8e6a0c834 --- /dev/null +++ b/contracts/contracts/levels/SwitchFactory.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import './base/Level.sol'; +import './Switch.sol'; + +contract SwitchFactory is Level { + function createInstance(address) override public payable returns (address) { + Switch instance = new Switch(); + return address(instance); + } + + function validateInstance(address payable _instance, address _player) override public returns (bool) { + Switch instance = Switch(_instance); + return instance.owner() == _player; + } +} diff --git a/contracts/test/levels/Switch.test.js b/contracts/test/levels/Switch.test.js new file mode 100644 index 000000000..4767e6e0d --- /dev/null +++ b/contracts/test/levels/Switch.test.js @@ -0,0 +1,57 @@ +const Switch = artifacts.require('./levels/Switch.sol') +const SwitchFactory = artifacts.require('./levels/SwitchFactory.sol') +const SwitchAttack = artifacts.require('./attacks/SwitchAttack.sol') + +const Ethernaut = artifacts.require('./Ethernaut.sol') +const utils = require('../utils/TestUtils') + +contract('Switch', function (accounts) { + + let ethernaut + let level + let owner = accounts[1] + let player = accounts[0] + + before(async function () { + ethernaut = await Ethernaut.new(); + level = await SwitchFactory.new() + await ethernaut.registerLevel(level.address) + }); + + it('should fail if the player did not solve the level', async function () { + const instance = await utils.createLevelInstance(ethernaut, level.address, player, Switch) + + const completed = await utils.submitLevelInstance( + ethernaut, + level.address, + instance.address, + player + ) + + assert.isFalse(completed) + }); + + + it('should allow the player to solve the level', async function () { + const instance = await utils.createLevelInstance(ethernaut, level.address, player, Switch) + + const attacker = await SwitchAttack.new() + const signature = await web3.eth.sign(web3.utils.keccak256(owner), player) + await attacker.attack( + instance.address, + player, + `0x${signature.slice(130, 132)}`, + signature.slice(0, 66), + `0x${signature.slice(66, 130)}` + ) + + const completed = await utils.submitLevelInstance( + ethernaut, + level.address, + instance.address, + player + ) + + assert.isTrue(completed) + }); +}); diff --git a/yarn.lock b/yarn.lock index db4a3e9f0..d556540d9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7238,10 +7238,15 @@ hex-color-regex@^1.1.0: resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ== -highlight.js@^10.4.0, highlight.js@^10.4.1: - version "10.7.3" - resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" - integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A== +highlight.js@^10.4.0: + version "10.7.2-local" + dependencies: + highlight.js "^10.7.2" + +highlight.js@^10.4.1: + version "10.7.2-local" + dependencies: + highlight.js "^10.7.2" highlight.js@^10.7.2: version "10.7.2" From 675d9487785afd393c6d71c7bdb4e8039ec41f4f Mon Sep 17 00:00:00 2001 From: Ahmad Alfawwaz Date: Sat, 21 May 2022 01:49:42 +0100 Subject: [PATCH 2/7] Add author and gamedata entries --- client/src/gamedata/authors.json | 6 ++++++ client/src/gamedata/gamedata.json | 15 +++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/client/src/gamedata/authors.json b/client/src/gamedata/authors.json index c25e0700d..ac4887f49 100644 --- a/client/src/gamedata/authors.json +++ b/client/src/gamedata/authors.json @@ -58,6 +58,12 @@ "name": "OpenZeppelin in collaboration with Forta", "emails": ["ethernaut@zeppelin.solutions", "info@forta.org"], "websites": ["https://openzeppelin.com", "https://forta.org"] + }, + "staa99": { + "name": "Ahmad Alfawwaz Timehin", + "emails": ["ahmadulfawwaz@gmail.com"], + "websites": ["https://github.com/staa99"], + "donate": "0x534DBE4e23E48faC59847F120a80A83F764a381F" } } } diff --git a/client/src/gamedata/gamedata.json b/client/src/gamedata/gamedata.json index 9c7dacf9d..e38cf1a1d 100644 --- a/client/src/gamedata/gamedata.json +++ b/client/src/gamedata/gamedata.json @@ -405,6 +405,21 @@ "instanceGas": 5000000, "poweredBy": {"src": "../../imgs/forta_black.svg", "href": "https://forta.org"}, "author": "openzeppelin&forta" + }, + { + "name": "Switch", + "created": "2022-05-21", + "difficulty": "2", + "description": "switch.md", + "completedDescription": "switch_complete.md", + "levelContract": "SwitchFactory.sol", + "instanceContract": "Switch.sol", + "revealCode": true, + "deployParams": [], + "deployFunds": 0, + "deployId": "27", + "instanceGas": 250000, + "author": "staa99" } ] } From 0ec3e20854a8dba76e0e5968f894fd77b5338d08 Mon Sep 17 00:00:00 2001 From: Ahmad Alfawwaz Date: Sat, 21 May 2022 02:15:34 +0100 Subject: [PATCH 3/7] Update gas requirement for 'Switch' --- client/src/gamedata/gamedata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/gamedata/gamedata.json b/client/src/gamedata/gamedata.json index e38cf1a1d..1ebaebd5a 100644 --- a/client/src/gamedata/gamedata.json +++ b/client/src/gamedata/gamedata.json @@ -418,7 +418,7 @@ "deployParams": [], "deployFunds": 0, "deployId": "27", - "instanceGas": 250000, + "instanceGas": 300000, "author": "staa99" } ] From 7f0c2a580b3c0c53376e097f64e3c7dc3afcfe69 Mon Sep 17 00:00:00 2001 From: Ahmad Alfawwaz Date: Sat, 21 May 2022 02:18:21 +0100 Subject: [PATCH 4/7] Add blank line to SwitchAttack.sol --- contracts/contracts/attacks/SwitchAttack.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/contracts/attacks/SwitchAttack.sol b/contracts/contracts/attacks/SwitchAttack.sol index d745eabf1..17296b058 100644 --- a/contracts/contracts/attacks/SwitchAttack.sol +++ b/contracts/contracts/attacks/SwitchAttack.sol @@ -10,4 +10,4 @@ contract SwitchAttack { target.changeOwnership(v, r, s); target.changeOwnership(_player); } -} \ No newline at end of file +} From 5bd87c92fd4d5d48dac76e674171513c6edebbdd Mon Sep 17 00:00:00 2001 From: Ahmad Alfawwaz Date: Sat, 21 May 2022 02:22:07 +0100 Subject: [PATCH 5/7] Reset lock file --- yarn.lock | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/yarn.lock b/yarn.lock index d556540d9..db4a3e9f0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7238,15 +7238,10 @@ hex-color-regex@^1.1.0: resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ== -highlight.js@^10.4.0: - version "10.7.2-local" - dependencies: - highlight.js "^10.7.2" - -highlight.js@^10.4.1: - version "10.7.2-local" - dependencies: - highlight.js "^10.7.2" +highlight.js@^10.4.0, highlight.js@^10.4.1: + version "10.7.3" + resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" + integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A== highlight.js@^10.7.2: version "10.7.2" From cd3e33aad9786998bc3e55c53d60c1c9261c1f3b Mon Sep 17 00:00:00 2001 From: CeliktepeMurat Date: Fri, 13 Jan 2023 14:35:06 +0300 Subject: [PATCH 6/7] feat: rebase PR --- .../contracts/attacks/SwitchAttack-2.sol | 19 ++++++ contracts/contracts/attacks/SwitchAttack.sol | 13 ---- contracts/contracts/levels/Switch.sol | 35 ---------- contracts/contracts/levels/Switch2.sol | 45 +++++++++++++ contracts/contracts/levels/SwitchFactory.sol | 17 ----- contracts/contracts/levels/SwitchFactory2.sol | 22 +++++++ contracts/test/levels/Switch.test.js | 57 ---------------- contracts/test/levels/Switch2.test.js | 65 +++++++++++++++++++ 8 files changed, 151 insertions(+), 122 deletions(-) create mode 100644 contracts/contracts/attacks/SwitchAttack-2.sol delete mode 100644 contracts/contracts/attacks/SwitchAttack.sol delete mode 100644 contracts/contracts/levels/Switch.sol create mode 100644 contracts/contracts/levels/Switch2.sol delete mode 100644 contracts/contracts/levels/SwitchFactory.sol create mode 100644 contracts/contracts/levels/SwitchFactory2.sol delete mode 100644 contracts/test/levels/Switch.test.js create mode 100644 contracts/test/levels/Switch2.test.js diff --git a/contracts/contracts/attacks/SwitchAttack-2.sol b/contracts/contracts/attacks/SwitchAttack-2.sol new file mode 100644 index 000000000..da5dc386d --- /dev/null +++ b/contracts/contracts/attacks/SwitchAttack-2.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../levels/Switch2.sol"; + +contract SwitchAttack2 { + function attack( + address _target, + address _player, + uint8 v, + bytes32 r, + bytes32 s + ) public { + Switch2 target = Switch2(_target); + target.changeOwnership(v, r, s); + target.changeOwnership(_player); + } +} diff --git a/contracts/contracts/attacks/SwitchAttack.sol b/contracts/contracts/attacks/SwitchAttack.sol deleted file mode 100644 index 17296b058..000000000 --- a/contracts/contracts/attacks/SwitchAttack.sol +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.6.0; - -import '../levels/Switch.sol'; - -contract SwitchAttack { - function attack(address _target, address _player, uint8 v, bytes32 r, bytes32 s) public { - Switch target = Switch(_target); - target.changeOwnership(v, r, s); - target.changeOwnership(_player); - } -} diff --git a/contracts/contracts/levels/Switch.sol b/contracts/contracts/levels/Switch.sol deleted file mode 100644 index 6050ec822..000000000 --- a/contracts/contracts/levels/Switch.sol +++ /dev/null @@ -1,35 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -contract Switch { - address public owner; - - modifier onlyOwner { - require( - msg.sender == owner, - "caller is not the owner" - ); - _; - } - - constructor() public { - owner = msg.sender; - } - - // Changes the ownership of the contract. Can only be called by the owner. - function changeOwnership(address _owner) public onlyOwner { - owner = _owner; - } - - // Changes the ownership of the contract to the sender provided the signature is created by the owner - function changeOwnership(uint8 v, bytes32 r, bytes32 s) public { - require(ecrecover(generateHash(owner), v, r, s) != address(0), "signer is not the owner"); - owner = msg.sender; - } - - // Generates a hash compatible with EIP-191 signatures - function generateHash(address _addr) private pure returns (bytes32) { - bytes32 addressHash = keccak256(abi.encodePacked(_addr)); - return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", addressHash)); - } -} diff --git a/contracts/contracts/levels/Switch2.sol b/contracts/contracts/levels/Switch2.sol new file mode 100644 index 000000000..bdd81d1bc --- /dev/null +++ b/contracts/contracts/levels/Switch2.sol @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract Switch2 { + address public owner; + + modifier onlyOwner() { + require(msg.sender == owner, "caller is not the owner"); + _; + } + + constructor() { + owner = msg.sender; + } + + // Changes the ownership of the contract. Can only be called by the owner. + function changeOwnership(address _owner) public onlyOwner { + owner = _owner; + } + + // Changes the ownership of the contract to the sender provided the signature is created by the owner + function changeOwnership( + uint8 v, + bytes32 r, + bytes32 s + ) public { + require( + ecrecover(generateHash(owner), v, r, s) != address(0), + "signer is not the owner" + ); + owner = msg.sender; + } + + // Generates a hash compatible with EIP-191 signatures + function generateHash(address _addr) private pure returns (bytes32) { + bytes32 addressHash = keccak256(abi.encodePacked(_addr)); + return + keccak256( + abi.encodePacked( + "\x19Ethereum Signed Message:\n32", + addressHash + ) + ); + } +} diff --git a/contracts/contracts/levels/SwitchFactory.sol b/contracts/contracts/levels/SwitchFactory.sol deleted file mode 100644 index 8e6a0c834..000000000 --- a/contracts/contracts/levels/SwitchFactory.sol +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -import './base/Level.sol'; -import './Switch.sol'; - -contract SwitchFactory is Level { - function createInstance(address) override public payable returns (address) { - Switch instance = new Switch(); - return address(instance); - } - - function validateInstance(address payable _instance, address _player) override public returns (bool) { - Switch instance = Switch(_instance); - return instance.owner() == _player; - } -} diff --git a/contracts/contracts/levels/SwitchFactory2.sol b/contracts/contracts/levels/SwitchFactory2.sol new file mode 100644 index 000000000..5d6b615dd --- /dev/null +++ b/contracts/contracts/levels/SwitchFactory2.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./base/Level.sol"; +import "./Switch2.sol"; + +contract SwitchFactory2 is Level { + function createInstance(address) public payable override returns (address) { + Switch2 instance = new Switch2(); + return address(instance); + } + + function validateInstance(address payable _instance, address _player) + public + view + override + returns (bool) + { + Switch2 instance = Switch2(_instance); + return instance.owner() == _player; + } +} diff --git a/contracts/test/levels/Switch.test.js b/contracts/test/levels/Switch.test.js deleted file mode 100644 index 4767e6e0d..000000000 --- a/contracts/test/levels/Switch.test.js +++ /dev/null @@ -1,57 +0,0 @@ -const Switch = artifacts.require('./levels/Switch.sol') -const SwitchFactory = artifacts.require('./levels/SwitchFactory.sol') -const SwitchAttack = artifacts.require('./attacks/SwitchAttack.sol') - -const Ethernaut = artifacts.require('./Ethernaut.sol') -const utils = require('../utils/TestUtils') - -contract('Switch', function (accounts) { - - let ethernaut - let level - let owner = accounts[1] - let player = accounts[0] - - before(async function () { - ethernaut = await Ethernaut.new(); - level = await SwitchFactory.new() - await ethernaut.registerLevel(level.address) - }); - - it('should fail if the player did not solve the level', async function () { - const instance = await utils.createLevelInstance(ethernaut, level.address, player, Switch) - - const completed = await utils.submitLevelInstance( - ethernaut, - level.address, - instance.address, - player - ) - - assert.isFalse(completed) - }); - - - it('should allow the player to solve the level', async function () { - const instance = await utils.createLevelInstance(ethernaut, level.address, player, Switch) - - const attacker = await SwitchAttack.new() - const signature = await web3.eth.sign(web3.utils.keccak256(owner), player) - await attacker.attack( - instance.address, - player, - `0x${signature.slice(130, 132)}`, - signature.slice(0, 66), - `0x${signature.slice(66, 130)}` - ) - - const completed = await utils.submitLevelInstance( - ethernaut, - level.address, - instance.address, - player - ) - - assert.isTrue(completed) - }); -}); diff --git a/contracts/test/levels/Switch2.test.js b/contracts/test/levels/Switch2.test.js new file mode 100644 index 000000000..29c21cb16 --- /dev/null +++ b/contracts/test/levels/Switch2.test.js @@ -0,0 +1,65 @@ +/*eslint no-undef: "off"*/ +const Switch = artifacts.require('./levels/Switch2.sol'); +const SwitchFactory = artifacts.require('./levels/SwitchFactory2.sol'); +const SwitchAttack = artifacts.require('./attacks/SwitchAttack2.sol'); + +const utils = require('../utils/TestUtils'); + +contract('Switch-2', function (accounts) { + let ethernaut; + let level; + let owner = accounts[1]; + let player = accounts[0]; + + before(async function () { + ethernaut = await utils.getEthernautWithStatsProxy(); + level = await SwitchFactory.new(); + await ethernaut.registerLevel(level.address); + }); + + it('should fail if the player did not solve the level', async function () { + const instance = await utils.createLevelInstance( + ethernaut, + level.address, + player, + Switch + ); + + const completed = await utils.submitLevelInstance( + ethernaut, + level.address, + instance.address, + player + ); + + assert.isFalse(completed); + }); + + it('should allow the player to solve the level', async function () { + const instance = await utils.createLevelInstance( + ethernaut, + level.address, + player, + Switch + ); + + const attacker = await SwitchAttack.new(); + const signature = await web3.eth.sign(web3.utils.keccak256(owner), player); + await attacker.attack( + instance.address, + player, + `0x${signature.slice(130, 132)}`, + signature.slice(0, 66), + `0x${signature.slice(66, 130)}` + ); + + const completed = await utils.submitLevelInstance( + ethernaut, + level.address, + instance.address, + player + ); + + assert.isTrue(completed); + }); +}); From 692177b94ca388ab79ec571c4b30f0f07bce11da Mon Sep 17 00:00:00 2001 From: CeliktepeMurat Date: Fri, 13 Jan 2023 14:37:47 +0300 Subject: [PATCH 7/7] feat: add authors info --- client/src/gamedata/authors.json | 163 +++++++++--------------------- client/src/gamedata/gamedata.json | 17 +++- 2 files changed, 61 insertions(+), 119 deletions(-) diff --git a/client/src/gamedata/authors.json b/client/src/gamedata/authors.json index 4f5795c0e..9e8abf0f8 100644 --- a/client/src/gamedata/authors.json +++ b/client/src/gamedata/authors.json @@ -1,152 +1,79 @@ { "authors": { "ajsantander": { - "name": [ - "Alejandro Santander" - ], - "emails": [ - "palebluedot@gmail.com" - ], - "websites": [ - "https://github.com/ajsantander" - ], + "name": ["Alejandro Santander"], + "emails": ["palebluedot@gmail.com"], + "websites": ["https://github.com/ajsantander"], "donate": "0x31a3801499618d3c4b0225b9e06e228d4795b55d" }, "martriay": { - "name": [ - "Martin Triay" - ], - "emails": [ - "martriay@gmail.com" - ], - "websites": [ - "https://github.com/martriay" - ] + "name": ["Martin Triay"], + "emails": ["martriay@gmail.com"], + "websites": ["https://github.com/martriay"] }, "AgeManning": { - "name": [ - "Adrian Manning" - ], - "emails": [ - "age@agemanning.com" - ], - "websites": [ - "https://github.com/AgeManning" - ], + "name": ["Adrian Manning"], + "emails": ["age@agemanning.com"], + "websites": ["https://github.com/AgeManning"], "donate": "0x0f44CD2Ca92645Ada2E47155e4dFC0025c3E9EEc" }, "syncikin": { - "name": [ - "Kyle Riley" - ], - "emails": [ - "kyle@iosiro.com" - ], - "websites": [ - "https://github.com/syncikin" - ] + "name": ["Kyle Riley"], + "emails": ["kyle@iosiro.com"], + "websites": ["https://github.com/syncikin"] }, "34x4p08": { - "name": [ - "Ivan Zakharov" - ], - "emails": [ - "34x4p08@gmail.com" - ], - "websites": [ - "https://github.com/34x4p08" - ] + "name": ["Ivan Zakharov"], + "emails": ["34x4p08@gmail.com"], + "websites": ["https://github.com/34x4p08"] }, "0age": { - "name": [ - "0age" - ], - "emails": [ - "0age@protonmail.com" - ], - "websites": [ - "https://github.com/0age" - ] + "name": ["0age"], + "emails": ["0age@protonmail.com"], + "websites": ["https://github.com/0age"] }, "nczhu": { - "name": [ - "Nicole Zhu" - ], - "emails": [ - "n@nicole.ai" - ], - "websites": [ - "https://github.com/nczhu" - ] + "name": ["Nicole Zhu"], + "emails": ["n@nicole.ai"], + "websites": ["https://github.com/nczhu"] }, "patrickalphac": { - "name": [ - "Patrick Collins" - ], - "emails": [ - "patrick@alphachain.io" - ], - "websites": [ - "http://alphachain.io/blogs/" - ], + "name": ["Patrick Collins"], + "emails": ["patrick@alphachain.io"], + "websites": ["http://alphachain.io/blogs/"], "donate": "0x874437B5a42aA6E6419eC2447C9e36c278c46532" }, "scottt": { - "name": [ - "Scott Tsai" - ], - "emails": [ - "scottt.tw@gmail.com" - ], - "websites": [ - "http://scottt.tw" - ], + "name": ["Scott Tsai"], + "emails": ["scottt.tw@gmail.com"], + "websites": ["http://scottt.tw"], "donate": "scottt.eth" }, "openzeppelin": { - "name": [ - "OpenZeppelin" - ], - "emails": [ - "ethernaut@zeppelin.solutions" - ], - "websites": [ - "https://openzeppelin.com" - ] + "name": ["OpenZeppelin"], + "emails": ["ethernaut@zeppelin.solutions"], + "websites": ["https://openzeppelin.com"] }, "openzeppelin&forta": { - "name": [ - "OpenZeppelin", - "Forta" - ], - "emails": [ - "ethernaut@zeppelin.solutions", - "info@forta.org" - ], - "websites": [ - "https://openzeppelin.com", - "https://forta.org" - ] + "name": ["OpenZeppelin", "Forta"], + "emails": ["ethernaut@zeppelin.solutions", "info@forta.org"], + "websites": ["https://openzeppelin.com", "https://forta.org"] }, "ericnordelo": { - "name": [ - "Eric Nordelo" - ], - "emails": [ - "eric.nordelo39@gmail.com" - ], - "websites": [ - "https://www.ericnordelo.com/" - ] + "name": ["Eric Nordelo"], + "emails": ["eric.nordelo39@gmail.com"], + "websites": ["https://www.ericnordelo.com/"] }, "KStasi": { - "name": [ - "Anastasiia Kondaurova" - ], + "name": ["Anastasiia Kondaurova"], "emails": [], - "websites": [ - "https://www.linkedin.com/in/kstasi/" - ] + "websites": ["https://www.linkedin.com/in/kstasi/"] + }, + "staa99": { + "name": "Ahmad Alfawwaz Timehin", + "emails": ["ahmadulfawwaz@gmail.com"], + "websites": ["https://github.com/staa99"], + "donate": "0x534DBE4e23E48faC59847F120a80A83F764a381F" } } -} \ No newline at end of file +} diff --git a/client/src/gamedata/gamedata.json b/client/src/gamedata/gamedata.json index 68cb63f39..149bfccac 100644 --- a/client/src/gamedata/gamedata.json +++ b/client/src/gamedata/gamedata.json @@ -446,6 +446,21 @@ "deployId": "28", "instanceGas": 1000000, "author": "KStasi" + }, + { + "name": "Switch-2", + "created": "2022-05-21", + "difficulty": "2", + "description": "switch2.md", + "completedDescription": "switch_complete2.md", + "levelContract": "SwitchFactory2.sol", + "instanceContract": "Switch2.sol", + "revealCode": true, + "deployParams": [], + "deployFunds": 0, + "deployId": "32", + "instanceGas": 300000, + "author": "staa99" } ] -} \ No newline at end of file +}