Skip to content

Instantly share code, notes, and snippets.

@k1rill-fedoseev
Created March 8, 2023 05:31
Show Gist options
  • Save k1rill-fedoseev/c7ca38a4a0a1d1980c905e430fa86685 to your computer and use it in GitHub Desktop.
Save k1rill-fedoseev/c7ca38a4a0a1d1980c905e430fa86685 to your computer and use it in GitHub Desktop.
// SPDX-License-Identifier: CC0-1.0
pragma solidity 0.8.15;
import "forge-std/Test.sol";
import "../../src/interfaces/ILegacyERC20.sol";
import "../../src/BobVault.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
contract VerifyGnosisSafeTx is Test {
address constant bob = address(0xB0B195aEFA3650A6908f15CdaC7D92F8a5791B0B);
address constant usdcMainnet = address(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48);
address constant usdtMainnet = address(0xdAC17F958D2ee523a2206206994597C13D831ec7);
address constant usdcOptimism = address(0x7F5c764cBc14f9669B88837ca1490cCa17c31607);
address constant usdtOptimism = address(0x94b008aA00579c1307B0EF2c499aD98a8ce58e58);
address constant usdcBNB = address(0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d);
address constant usdtBNB = address(0x55d398326f99059fF775485246999027B3197955);
address constant usdcArbitrum = address(0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8);
address constant usdtArbitrum = address(0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9);
address constant uniswapRouter = address(0xE592427A0AEce92De3Edee1F18E0157C05861564);
address constant kyberswapRouter = address(0xC1e7dFE73E1598E3910EF4C7845B68A9Ab6F4c83);
address constant bobVaultMainnet = address(0x15729Ac1795Fa02448a55D206005dC1914144a9F);
address constant bobVaultOptimism = address(0x8aEb89D5C689C2cf373Fe8b56c7A0cD5BDc74CE6);
address constant bobVaultBNB = address(0x61a57F1C82DA40e632C075D7812Af375Db23367c);
address constant bobVaultArbitrum = address(0x72e6B59D4a90ab232e55D4BB7ed2dD17494D62fB);
function testMainnet() external {
vm.createSelectFork("https://rpc.ankr.com/eth");
address from = address(0xd4a3D9Ca00fa1fD8833D560F9217458E61c446d8);
address to = address(0x40A2aCCbd92BCA938b02010E17A5b8929b49130D);
bytes memory data = hex"8d80ff0a000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000008a100b0b195aefa3650a6908f15cdac7d92f8a5791b0b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004440c10f1900000000000000000000000015729ac1795fa02448a55d206005dc1914144a9f000000000000000000000000000000000000000000027b46536c66c8e300000000b0b195aefa3650a6908f15cdac7d92f8a5791b0b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004440c10f19000000000000000000000000d4a3d9ca00fa1fd8833d560f9217458e61c446d8000000000000000000000000000000000000000000034f086f3b33b683290c2a00b0b195aefa3650a6908f15cdac7d92f8a5791b0b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044095ea7b30000000000000000000000002b1c7b41f6a8f2b2bc45c3233a5d5fb3cd6dc9a8ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044095ea7b30000000000000000000000002b1c7b41f6a8f2b2bc45c3233a5d5fb3cd6dc9a8000000000000000000000000000000000000000000000000000000000000000100a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044095ea7b30000000000000000000000002b1c7b41f6a8f2b2bc45c3233a5d5fb3cd6dc9a80000000000000000000000000000000000000000000000000000000000000001002b1c7b41f6a8f2b2bc45c3233a5d5fb3cd6dc9a8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000841c49584a000000000000000000000000b0b195aefa3650a6908f15cdac7d92f8a5791b0b000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000010c6c21c15a4936b7e64002b1c7b41f6a8f2b2bc45c3233a5d5fb3cd6dc9a8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a4ea540632000000000000000000000000b0b195aefa3650a6908f15cdac7d92f8a5791b0b000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec70000000000000000000000000000000000000000000000000000000000000008fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc89bfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc89dfffffffffffffffffffffffffffffffffffffffffffffffffffffffffff27618fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2761800000000000000000000000000000000000000000001a784379d99c3f93ed1a2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d4a3d9ca00fa1fd8833d560f9217458e61c446d8000000000000000000000000000000000000000000000000000000006553f100002b1c7b41f6a8f2b2bc45c3233a5d5fb3cd6dc9a8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000841c49584a000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000b0b195aefa3650a6908f15cdac7d92f8a5791b0b000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000f4270ad40df2b08be65608f4517e8002b1c7b41f6a8f2b2bc45c3233a5d5fb3cd6dc9a8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a4ea540632000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000b0b195aefa3650a6908f15cdac7d92f8a5791b0b000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000437630000000000000000000000000000000000000000000000000000000000043765fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff27618fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff27618000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a784379d99c3f93ed1a200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d4a3d9ca00fa1fd8833d560f9217458e61c446d8000000000000000000000000000000000000000000000000000000006553f10000000000000000000000000000000000000000000000000000000000000000";
uint256 supply = IERC20(bob).totalSupply();
uint256 govBalance = IERC20(bob).balanceOf(from);
prankDelegate(from).delegatecall(to, data);
assertApproxEqAbs(IERC20(bob).totalSupply(), supply + 3_000_000 ether + 4_000_000 ether, 1 gwei);
assertEq(IERC20(bob).balanceOf(from), govBalance);
checkUniswapInventory(usdcMainnet, 100);
checkUniswapInventory(usdcMainnet, 500);
checkKyberswapInventory(usdcMainnet, 8);
checkKyberswapInventory(usdtMainnet, 8);
checkBobVaultInventory(bobVaultMainnet, usdcMainnet);
checkBobVaultInventory(bobVaultMainnet, usdtMainnet);
}
function testOptimism() external {
vm.createSelectFork("https://rpc.ankr.com/optimism");
address from = address(0x14fc6a1a996A2EB889cF86e5c8cD17323bC85290);
address to = address(0xA1dabEF33b3B82c7814B6D82A79e50F4AC44102B);
bytes memory data = hex"8d80ff0a000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000003c400b0b195aefa3650a6908f15cdac7d92f8a5791b0b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004440c10f190000000000000000000000008aeb89d5c689c2cf373fe8b56c7a0cd5bdc74ce60000000000000000000000000000000000000000000422ca8b0a00a42500000000b0b195aefa3650a6908f15cdac7d92f8a5791b0b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004440c10f1900000000000000000000000014fc6a1a996a2eb889cf86e5c8cd17323bc8529000000000000000000000000000000000000000000001a784379d99db41ffffaf00c36442b4a4522e871399cd717abdd847ab11fe880000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008413ead5620000000000000000000000007f5c764cbc14f9669b88837ca1490cca17c31607000000000000000000000000b0b195aefa3650a6908f15cdac7d92f8a5791b0b000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000f4270ad40df2b08be65608f4517e800c36442b4a4522e871399cd717abdd847ab11fe8800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000164883164560000000000000000000000007f5c764cbc14f9669b88837ca1490cca17c31607000000000000000000000000b0b195aefa3650a6908f15cdac7d92f8a5791b0b000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000437630000000000000000000000000000000000000000000000000000000000043765000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a784379d99db420000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014fc6a1a996a2eb889cf86e5c8cd17323bc85290000000000000000000000000000000000000000000000000000000006553f10000000000000000000000000000000000000000000000000000000000";
uint256 supply = IERC20(bob).totalSupply();
uint256 govBalance = IERC20(bob).balanceOf(from);
prankDelegate(from).delegatecall(to, data);
assertApproxEqAbs(IERC20(bob).totalSupply(), supply + 5_000_000 ether + 2_000_000 ether, 1 gwei);
assertEq(IERC20(bob).balanceOf(from), govBalance);
checkUniswapInventory(usdcOptimism, 100);
checkUniswapInventory(usdcOptimism, 500);
checkBobVaultInventory(bobVaultOptimism, usdcOptimism);
checkBobVaultInventory(bobVaultOptimism, usdtOptimism);
}
function testBNB() external {
vm.createSelectFork("https://rpc.ankr.com/bsc");
address from = address(0xd4a3D9Ca00fa1fD8833D560F9217458E61c446d8);
address to = address(0x40A2aCCbd92BCA938b02010E17A5b8929b49130D);
bytes memory data = hex"8d80ff0a0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000080800b0b195aefa3650a6908f15cdac7d92f8a5791b0b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004440c10f1900000000000000000000000061a57f1c82da40e632c075d7812af375db23367c0000000000000000000000000000000000000000000422ca8b0a00a42500000000b0b195aefa3650a6908f15cdac7d92f8a5791b0b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004440c10f19000000000000000000000000d4a3d9ca00fa1fd8833d560f9217458e61c446d8000000000000000000000000000000000000000000034f086f3b33b6840000000055d398326f99059ff775485246999027b319795500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044095ea7b30000000000000000000000002b1c7b41f6a8f2b2bc45c3233a5d5fb3cd6dc9a8000000000000000000000000000000000000000000000000000000000001869c008ac76a51cc950d9822d68b83fe1ad97b32cd580d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044095ea7b30000000000000000000000002b1c7b41f6a8f2b2bc45c3233a5d5fb3cd6dc9a8000000000000000000000000000000000000000000000000000000000001869c002b1c7b41f6a8f2b2bc45c3233a5d5fb3cd6dc9a8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000841c49584a00000000000000000000000055d398326f99059ff775485246999027b3197955000000000000000000000000b0b195aefa3650a6908f15cdac7d92f8a5791b0b00000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000001000346d6ff11672ae55ad010002b1c7b41f6a8f2b2bc45c3233a5d5fb3cd6dc9a8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a4ea54063200000000000000000000000055d398326f99059ff775485246999027b3197955000000000000000000000000b0b195aefa3650a6908f15cdac7d92f8a5791b0b0000000000000000000000000000000000000000000000000000000000000008ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000001fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff27618fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff27618000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a784379d99db41fe795b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d4a3d9ca00fa1fd8833d560f9217458e61c446d8000000000000000000000000000000000000000000000000000000006553f100002b1c7b41f6a8f2b2bc45c3233a5d5fb3cd6dc9a8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000841c49584a0000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d000000000000000000000000b0b195aefa3650a6908f15cdac7d92f8a5791b0b00000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000001000346d6ff11672ae55ad010002b1c7b41f6a8f2b2bc45c3233a5d5fb3cd6dc9a8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a4ea5406320000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d000000000000000000000000b0b195aefa3650a6908f15cdac7d92f8a5791b0b0000000000000000000000000000000000000000000000000000000000000008ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000001fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff27618fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff27618000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a784379d99db41fe795b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d4a3d9ca00fa1fd8833d560f9217458e61c446d8000000000000000000000000000000000000000000000000000000006553f100000000000000000000000000000000000000000000000000";
uint256 supply = IERC20(bob).totalSupply();
uint256 govBalance = IERC20(bob).balanceOf(from);
prankDelegate(from).delegatecall(to, data);
assertApproxEqAbs(IERC20(bob).totalSupply(), supply + 5_000_000 ether + 4_000_000 ether, 1 gwei);
assertEq(IERC20(bob).balanceOf(from), govBalance);
checkKyberswapInventory(usdcBNB, 8);
checkKyberswapInventory(usdtBNB, 8);
checkBobVaultInventory(bobVaultBNB, usdcBNB);
checkBobVaultInventory(bobVaultBNB, usdtBNB);
}
function testArbitrum() external {
vm.createSelectFork("https://rpc.ankr.com/arbitrum");
address from = address(0xd4a3D9Ca00fa1fD8833D560F9217458E61c446d8);
address to = address(0x40A2aCCbd92BCA938b02010E17A5b8929b49130D);
bytes memory data = hex"8d80ff0a0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000045d00b0b195aefa3650a6908f15cdac7d92f8a5791b0b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004440c10f1900000000000000000000000072e6b59d4a90ab232e55d4bb7ed2dd17494d62fb0000000000000000000000000000000000000000000422ca8b0a00a42500000000b0b195aefa3650a6908f15cdac7d92f8a5791b0b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004440c10f19000000000000000000000000d4a3d9ca00fa1fd8833d560f9217458e61c446d800000000000000000000000000000000000000000001a784379d99db41290c7900b0b195aefa3650a6908f15cdac7d92f8a5791b0b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044095ea7b3000000000000000000000000c36442b4a4522e871399cd717abdd847ab11fe88ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00c36442b4a4522e871399cd717abdd847ab11fe880000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008413ead562000000000000000000000000b0b195aefa3650a6908f15cdac7d92f8a5791b0b000000000000000000000000ff970a61a04b1ca14834a43f5de4533ebddb5cc800000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000010c6c21c15a4936b7e6400c36442b4a4522e871399cd717abdd847ab11fe880000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016488316456000000000000000000000000b0b195aefa3650a6908f15cdac7d92f8a5791b0b000000000000000000000000ff970a61a04b1ca14834a43f5de4533ebddb5cc80000000000000000000000000000000000000000000000000000000000000064fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc89bfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc89d00000000000000000000000000000000000000000001a784379d99db42000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d4a3d9ca00fa1fd8833d560f9217458e61c446d8000000000000000000000000000000000000000000000000000000006553f100000000";
uint256 supply = IERC20(bob).totalSupply();
uint256 govBalance = IERC20(bob).balanceOf(from);
prankDelegate(from).delegatecall(to, data);
assertApproxEqAbs(IERC20(bob).totalSupply(), supply + 5_000_000 ether + 2_000_000 ether, 1 gwei);
assertEq(IERC20(bob).balanceOf(from), govBalance);
checkUniswapInventory(usdcArbitrum, 100);
checkBobVaultInventory(bobVaultArbitrum, usdcArbitrum);
checkBobVaultInventory(bobVaultArbitrum, usdtArbitrum);
}
function prankDelegate(address _target) internal returns (Delegator) {
vm.etch(_target, type(Delegator).runtimeCode);
return Delegator(payable(_target));
}
function checkUniswapInventory(address _token, uint24 _fee) internal {
uint256 amountIn = 10_000 * 10 ** IERC20Metadata(_token).decimals();
uint256 amountOut = 10_000 ether;
deal(_token, address(this), amountIn);
ILegacyERC20(_token).approve(address(uniswapRouter), amountIn);
uint256 realAmountOut = ISwapRouter(uniswapRouter).exactInput(
ISwapRouter.ExactInputParams({
path: abi.encodePacked(_token, _fee, bob),
recipient: address(this),
deadline: block.timestamp,
amountIn: amountIn,
amountOutMinimum: 0
})
);
assertApproxEqAbs(realAmountOut, amountOut, 10 ether);
}
function checkKyberswapInventory(address _token, uint24 _fee) internal {
uint256 amountIn = 10_000 * 10 ** IERC20Metadata(_token).decimals();
uint256 amountOut = 10_000 ether;
deal(_token, address(this), amountIn);
ILegacyERC20(_token).approve(address(kyberswapRouter), amountIn);
uint256 realAmountOut = IKyberSwapRouter(kyberswapRouter).swapExactInput(
ISwapRouter.ExactInputParams({
path: abi.encodePacked(_token, _fee, bob),
recipient: address(this),
deadline: block.timestamp,
amountIn: amountIn,
amountOutMinimum: 0
})
);
assertApproxEqAbs(realAmountOut, amountOut, 10 ether);
}
function checkBobVaultInventory(address _vault, address _token) internal {
uint256 amountIn = 10_000 * 10 ** IERC20Metadata(_token).decimals();
uint256 amountOut = 10_000 ether;
deal(_token, address(this), amountIn);
ILegacyERC20(_token).approve(address(_vault), amountIn);
uint256 realAmountOut = BobVault(_vault).buy(_token, amountIn);
assertApproxEqAbs(realAmountOut, amountOut, 10 ether);
}
}
interface IKyberSwapRouter {
function swapExactInput(ISwapRouter.ExactInputParams memory params) external returns (uint256 amountOut);
}
contract Delegator {
function delegatecall(address dest, bytes memory cd) external payable virtual {
assembly {
let result := delegatecall(gas(), dest, add(cd, 32), mload(cd), 0, 0)
returndatacopy(0, 0, returndatasize())
switch result
case 0 { revert(0, returndatasize()) }
default { return(0, returndatasize()) }
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment