@safe-global/safe-contracts
Version:
Ethereum multisig contract
117 lines (95 loc) • 5.99 kB
text/typescript
import { BigNumber } from "ethers";
import { Contract } from "ethers";
import { parseEther } from "@ethersproject/units";
import { expect } from "chai";
import hre, { ethers, waffle } from "hardhat";
import { AddressOne } from "../../src/utils/constants";
import { buildSafeTransaction, executeContractCallWithSigners, executeTxWithSigners, MetaTransaction } from "../../src/utils/execution";
import { buildMultiSendSafeTx } from "../../src/utils/multisend";
interface TestSetup {
migratedSafe: Contract;
mock: Contract;
multiSend: Contract;
}
export const verificationTests = (setupTests: () => Promise<TestSetup>) => {
const [user1, user2, user3] = waffle.provider.getWallets();
describe("execTransaction", async () => {
it("should be able to transfer ETH", async () => {
const { migratedSafe } = await setupTests();
await user1.sendTransaction({ to: migratedSafe.address, value: parseEther("1") });
const nonce = await migratedSafe.nonce();
const tx = buildSafeTransaction({ to: user2.address, value: parseEther("1"), nonce });
const userBalance = await ethers.provider.getBalance(user2.address);
await expect(await ethers.provider.getBalance(migratedSafe.address)).to.be.deep.eq(parseEther("1"));
await executeTxWithSigners(migratedSafe, tx, [user1]);
await expect(await ethers.provider.getBalance(user2.address)).to.be.deep.eq(userBalance.add(parseEther("1")));
await expect(await ethers.provider.getBalance(migratedSafe.address)).to.be.deep.eq(parseEther("0"));
});
});
describe("addOwner", async () => {
it("should add owner and change treshold", async () => {
const { migratedSafe } = await setupTests();
await expect(executeContractCallWithSigners(migratedSafe, migratedSafe, "addOwnerWithThreshold", [user2.address, 2], [user1]))
.to.emit(migratedSafe, "AddedOwner")
.withArgs(user2.address)
.and.to.emit(migratedSafe, "ChangedThreshold");
await expect(await migratedSafe.getThreshold()).to.be.deep.eq(BigNumber.from(2));
await expect(await migratedSafe.getOwners()).to.be.deep.equal([user2.address, user1.address]);
await expect(
executeContractCallWithSigners(migratedSafe, migratedSafe, "addOwnerWithThreshold", [user3.address, 1], [user1, user2]),
)
.to.emit(migratedSafe, "AddedOwner")
.withArgs(user3.address)
.and.to.emit(migratedSafe, "ChangedThreshold");
await expect(await migratedSafe.getThreshold()).to.be.deep.eq(BigNumber.from(1));
await expect(await migratedSafe.getOwners()).to.be.deep.equal([user3.address, user2.address, user1.address]);
await expect(await migratedSafe.isOwner(user1.address)).to.be.true;
await expect(await migratedSafe.isOwner(user2.address)).to.be.true;
await expect(await migratedSafe.isOwner(user3.address)).to.be.true;
});
});
describe("enableModule", async () => {
it("should enabled module and be able to use it", async () => {
const { migratedSafe, mock } = await setupTests();
await expect(executeContractCallWithSigners(migratedSafe, migratedSafe, "enableModule", [user2.address], [user1]))
.to.emit(migratedSafe, "EnabledModule")
.withArgs(user2.address);
await expect(await migratedSafe.isModuleEnabled(user2.address)).to.be.true;
await expect(await migratedSafe.getModulesPaginated(AddressOne, 10)).to.be.deep.equal([[user2.address], AddressOne]);
const user2Safe = migratedSafe.connect(user2);
await expect(user2Safe.execTransactionFromModule(mock.address, 0, "0xbaddad", 0))
.to.emit(migratedSafe, "ExecutionFromModuleSuccess")
.withArgs(user2.address);
expect(await mock.callStatic.invocationCountForCalldata("0xbaddad")).to.be.deep.equals(BigNumber.from(1));
});
});
describe("multiSend", async () => {
it("execute multisend via delegatecall", async () => {
const { migratedSafe, mock, multiSend } = await setupTests();
await user1.sendTransaction({ to: migratedSafe.address, value: parseEther("1") });
const userBalance = await hre.ethers.provider.getBalance(user2.address);
await expect(await hre.ethers.provider.getBalance(migratedSafe.address)).to.be.deep.eq(parseEther("1"));
const txs: MetaTransaction[] = [
buildSafeTransaction({ to: user2.address, value: parseEther("1"), nonce: 0 }),
buildSafeTransaction({ to: mock.address, data: "0xbaddad", nonce: 0 }),
];
const safeTx = buildMultiSendSafeTx(multiSend, txs, await migratedSafe.nonce());
await expect(executeTxWithSigners(migratedSafe, safeTx, [user1])).to.emit(migratedSafe, "ExecutionSuccess");
await expect(await hre.ethers.provider.getBalance(migratedSafe.address)).to.be.deep.eq(parseEther("0"));
await expect(await hre.ethers.provider.getBalance(user2.address)).to.be.deep.eq(userBalance.add(parseEther("1")));
expect(await mock.callStatic.invocationCountForCalldata("0xbaddad")).to.be.deep.equals(BigNumber.from(1));
});
});
describe("fallbackHandler", async () => {
it("should be correctly set", async () => {
const { migratedSafe, mock } = await setupTests();
// Check fallback handler
await expect(
await ethers.provider.getStorageAt(
migratedSafe.address,
"0x6c9a6c4a39284e37ed1cf53d337577d14212a4870fb976a4366c693b939918d5",
),
).to.be.eq("0x" + mock.address.toLowerCase().slice(2).padStart(64, "0"));
});
});
};