Skip to content

Commit dec13f7

Browse files
authored
Add test for simulating selfdestruct (#359)
* Add test for simulating selfdestruct * use delegate call for selfdestruct * Check that selfdestruct works
1 parent 8c84fb3 commit dec13f7

File tree

1 file changed

+29
-13
lines changed

1 file changed

+29
-13
lines changed

test/accessors/SimulateTxAccessor.spec.ts

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,17 @@ import { expect } from "chai";
22
import hre, { deployments, waffle } from "hardhat";
33
import "@nomiclabs/hardhat-ethers";
44
import { deployContract, getSimulateTxAccessor, getSafeWithOwners, getCompatFallbackHandler } from "../utils/setup";
5-
import { buildContractCall } from "../../src/utils/execution";
5+
import { buildContractCall, executeTx, executeTxWithSigners } from "../../src/utils/execution";
66
import { parseEther } from "ethers/lib/utils";
77

88
describe("SimulateTxAccessor", async () => {
99

10+
const killLibSource = `
11+
contract Test {
12+
function killme() public {
13+
selfdestruct(payable(msg.sender));
14+
}
15+
}`
1016
const [user1, user2] = waffle.provider.getWallets();
1117

1218
const setupTests = deployments.createFixture(async ({ deployments }) => {
@@ -36,13 +42,7 @@ describe("SimulateTxAccessor", async () => {
3642

3743
it('should enforce delegatecall', async () => {
3844
const { accessor } = await setupTests()
39-
const source = `
40-
contract Test {
41-
function killme() public {
42-
selfdestruct(payable(msg.sender));
43-
}
44-
}`
45-
const killLib = await deployContract(user1, source);
45+
const killLib = await deployContract(user1, killLibSource);
4646
const tx = buildContractCall(killLib, "killme", [], 0)
4747

4848
let code = await hre.ethers.provider.getCode(accessor.address)
@@ -57,7 +57,7 @@ describe("SimulateTxAccessor", async () => {
5757
const { safe, accessor, simulator } = await setupTests()
5858
const tx = buildContractCall(safe, "getOwners", [], 0)
5959
const simulationData = accessor.interface.encodeFunctionData("simulate", [tx.to, tx.value, tx.data, tx.operation])
60-
const acccessibleData = await simulator.callStatic.simulate(accessor.address, simulationData)
60+
const acccessibleData = await simulator.callStatic.simulate(accessor.address, simulationData)
6161
const simulation = accessor.interface.decodeFunctionResult("simulate", acccessibleData)
6262
expect(
6363
safe.interface.decodeFunctionResult("getOwners", simulation.returnData)[0]
@@ -72,11 +72,11 @@ describe("SimulateTxAccessor", async () => {
7272

7373
it('simulate delegatecall', async () => {
7474
const { safe, accessor, interactor, simulator } = await setupTests()
75-
await user1.sendTransaction({to: safe.address, value: parseEther("1")})
75+
await user1.sendTransaction({ to: safe.address, value: parseEther("1") })
7676
const userBalance = await hre.ethers.provider.getBalance(user2.address)
7777
const tx = buildContractCall(interactor, "sendAndReturnBalance", [user2.address, parseEther("1")], 0, true)
7878
const simulationData = accessor.interface.encodeFunctionData("simulate", [tx.to, tx.value, tx.data, tx.operation])
79-
const acccessibleData = await simulator.callStatic.simulate(accessor.address, simulationData)
79+
const acccessibleData = await simulator.callStatic.simulate(accessor.address, simulationData)
8080
const simulation = accessor.interface.decodeFunctionResult("simulate", acccessibleData)
8181
expect(
8282
interactor.interface.decodeFunctionResult("sendAndReturnBalance", simulation.returnData)[0]
@@ -89,11 +89,27 @@ describe("SimulateTxAccessor", async () => {
8989
).to.be.lte(15000)
9090
})
9191

92-
it('simulate revert', async () => {
92+
it('simulate selfdestruct', async () => {
9393
const { safe, accessor, interactor, simulator } = await setupTests()
94+
const expectedCode = await hre.ethers.provider.getCode(safe.address)
95+
await user1.sendTransaction({ to: safe.address, value: parseEther("1") })
96+
const killLib = await deployContract(user1, killLibSource);
97+
const tx = buildContractCall(killLib, "killme", [], 0, true)
98+
const simulationData = accessor.interface.encodeFunctionData("simulate", [tx.to, tx.value, tx.data, tx.operation])
99+
await simulator.simulate(accessor.address, simulationData);
100+
const code = await hre.ethers.provider.getCode(safe.address)
101+
expect(code).to.be.eq(expectedCode)
102+
expect(code).to.be.not.eq("0x")
103+
// Selfdestruct Safe (to be sure that this test works)
104+
await executeTxWithSigners(safe, tx, [user1])
105+
expect(await hre.ethers.provider.getCode(safe.address)).to.be.eq("0x")
106+
})
107+
108+
it('simulate revert', async () => {
109+
const { accessor, interactor, simulator } = await setupTests()
94110
const tx = buildContractCall(interactor, "sendAndReturnBalance", [user2.address, parseEther("1")], 0, true)
95111
const simulationData = accessor.interface.encodeFunctionData("simulate", [tx.to, tx.value, tx.data, tx.operation])
96-
const acccessibleData = await simulator.callStatic.simulate(accessor.address, simulationData)
112+
const acccessibleData = await simulator.callStatic.simulate(accessor.address, simulationData)
97113
const simulation = accessor.interface.decodeFunctionResult("simulate", acccessibleData)
98114
expect(simulation.returnData).to.be.deep.eq("0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000f5472616e73666572206661696c65640000000000000000000000000000000000")
99115
expect(

0 commit comments

Comments
 (0)