Standalone

Price Oracle Attack

close button

Vulnerable Price Oracles

Download quests in Questplay

View the contracts and any other additional content from your IDE.

As you might know, automated market makers can be used as on-chain price oracles. Due to arbitrage activity on the network, we can assume that, in general, token balances in liquidity pools reflect their relative prices.

For example, GoudaGoblin uses UniswapV2 as a price oracle. UniswapV2 uses the constant product formula to maintain an equal value of 2 different tokens. For example, if 1 GOUDA costs 100 GLD, then the GOUDA:GLD liquidity pool should have a ratio of 1 GOUDA : 100 GLD.

The UniswapV2 Factory address to use on Sepolia is 0x7E0987E5b3a30e3f2828572Bb659A548460a3003

Can GoudaGoblin be exploited?

Your Task

Trick the goblins into giving their gouda away.

Contract Code

// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol"; contract GoudaGoblin { IERC20 public gold; IERC20 public gouda; address public liquidityPool; uint256 public lockedGouda = 10000 ether; constructor( IERC20 _gouda, IERC20 _gold, IUniswapV2Factory _uniswap ) { gouda = _gouda; gold = _gold; liquidityPool = _uniswap.getPair(address(_gouda), address(_gold)); } function giveGouda() external { require( fetchGoudaPrice() <= 10 gwei, "The goblins will not give away expensive gouda!" ); gouda.transfer(msg.sender, lockedGouda); lockedGouda = 0; } /// @dev Fetches the current gouda price (in gold) from uniswap, with 9 decimals of precision. function fetchGoudaPrice() public view returns (uint goudaPrice) { uint goldBalance = gold.balanceOf(liquidityPool); uint goudaBalance = gouda.balanceOf(liquidityPool); goudaPrice = goldBalance * 1 gwei / goudaBalance; } }

The goblins are guarding the gouda closely, but they’ll lose interest if it costs 10 gold or less.