Code
BridgeBase.sol
// SPDX-License-Identifier: UNLICENSEDpragma solidity ^0.8.13;
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";import { console } from "forge-std/console.sol";import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
interface IBUSDT is IERC20 { function mint(address _to, uint256 _amount) external; function burn(address _from, uint256 _amount) external;}
contract BridgeETH is Ownable { uint256 public balance; address public tokenAddress;
event Burn(address indexed burner, uint amount);
mapping(address => uint256) public pendingBalance;
constructor(address _tokenAddress) Ownable(msg.sender) { tokenAddress = _tokenAddress; }
function burn(IBUSDT _tokenAddress, uint256 _amount) public { require(address(_tokenAddress) == tokenAddress); _tokenAddress.burn(msg.sender, _amount); emit Burn(msg.sender, _amount); }
function withdraw(IBUSDT _tokenAddress, uint256 _amount) public { require(pendingBalance[msg.sender] >= _amount); pendingBalance[msg.sender] -= _amount; _tokenAddress.mint(msg.sender, _amount); }
function burnedOnOppositeChain(address userAccount, uint256 _amount) public onlyOwner { pendingBalance[userAccount] += _amount; }}
BridgeETH.sol
// SPDX-License-Identifier: UNLICENSEDpragma solidity ^0.8.13;
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";import { console } from "forge-std/console.sol";import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
contract BridgeETH is Ownable { uint256 public balance; address public tokenAddress;
event Deposit(address indexed depositor, uint amount);
mapping(address => uint256) public pendingBalance;
constructor(address _tokenAddress) Ownable(msg.sender) { tokenAddress = _tokenAddress; }
function deposit(IERC20 _tokenAddress, uint256 _amount) public { require(address(_tokenAddress) == tokenAddress); require(_tokenAddress.allowance(msg.sender, address(this)) >= _amount); require(_tokenAddress.transferFrom(msg.sender, address(this), _amount)); emit Deposit(msg.sender, _amount); }
function withdraw(IERC20 _tokenAddress, uint256 _amount) public { require(pendingBalance[msg.sender] >= _amount); pendingBalance[msg.sender] -= _amount; _tokenAddress.transfer(msg.sender, _amount); }
function burnedOnOppositeChain(address userAccount, uint256 _amount) public onlyOwner { pendingBalance[userAccount] += _amount; }}
BUSDT.sol
// SPDX-License-Identifier: UNLICENSEDpragma solidity ^0.8.13;
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";import { console } from "forge-std/console.sol";import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
contract BUSDT is ERC20, Ownable { constructor() ERC20("USDT", "USDT") Ownable(msg.sender) {
}
function mint(address _to, uint256 _amount) public onlyOwner { _mint(_to, _amount); }
function burn(address _from, uint256 _amount) public onlyOwner { _burn(_from, _amount); }
}
USDT.sol
// SPDX-License-Identifier: UNLICENSEDpragma solidity ^0.8.13;
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";import { console } from "forge-std/console.sol";import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
contract USDT is ERC20, Ownable { constructor() ERC20("USDT", "USDT") Ownable(msg.sender) {
}
function mint(address _to, uint256 _amount) public onlyOwner { _mint(_to, _amount); }}
Assignment
Find the vulnerability in here