Skip to content

Commit 7493fdd

Browse files
authored
fix: title escrow factory create call (#153)
1 parent aba5cca commit 7493fdd

File tree

4 files changed

+77
-24
lines changed

4 files changed

+77
-24
lines changed

contracts/TitleEscrowFactory.sol

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,19 @@ pragma solidity ^0.8.0;
44
import "@openzeppelin/contracts/proxy/Clones.sol";
55
import "./TitleEscrow.sol";
66
import "./interfaces/ITitleEscrowFactory.sol";
7+
import "./interfaces/TitleEscrowFactoryErrors.sol";
78

8-
contract TitleEscrowFactory is ITitleEscrowFactory {
9+
contract TitleEscrowFactory is ITitleEscrowFactory, TitleEscrowFactoryErrors {
910
address public override implementation;
1011

1112
constructor() {
1213
implementation = address(new TitleEscrow());
1314
}
1415

1516
function create(uint256 tokenId) external override returns (address) {
17+
if (msg.sender.code.length == 0) {
18+
revert CreateCallerNotContract();
19+
}
1620
bytes32 salt = keccak256(abi.encodePacked(msg.sender, tokenId));
1721
address titleEscrow = Clones.cloneDeterministic(implementation, salt);
1822
TitleEscrow(titleEscrow).initialize(msg.sender, tokenId);
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
pragma solidity ^0.8.0;
3+
4+
interface TitleEscrowFactoryErrors {
5+
error CreateCallerNotContract();
6+
}

contracts/mocks/DummyContractMock.sol

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
pragma solidity ^0.8.0;
3+
4+
contract DummyContractMock {
5+
6+
string public name = "Dummy";
7+
8+
constructor() {}
9+
}

test/TitleEscrowFactory.test.ts

Lines changed: 57 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
import { ethers } from "hardhat";
22
import { loadFixture } from "@nomicfoundation/hardhat-network-helpers";
33
import faker from "faker";
4-
import { ContractTransaction } from "ethers";
5-
import { TitleEscrow, TitleEscrowFactory } from "@tradetrust/contracts";
4+
import { ContractTransaction, Signer } from "ethers";
5+
import { DummyContractMock, TitleEscrow, TitleEscrowFactory } from "@tradetrust/contracts";
66
import { TitleEscrowCreatedEvent } from "@tradetrust/contracts/contracts/TitleEscrowFactory";
7-
import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers";
87
import { expect } from ".";
98
import { deployEscrowFactoryFixture } from "./fixtures";
109
import { computeTitleEscrowAddress, getEventFromReceipt } from "../src/utils";
1110
import { contractInterfaceId, defaultAddress } from "../src/constants";
12-
import { createDeployFixtureRunner, getTestUsers, TestUsers } from "./helpers";
11+
import { createDeployFixtureRunner, getTestUsers, impersonateAccount, TestUsers } from "./helpers";
1312

1413
describe("TitleEscrowFactory", async () => {
1514
let users: TestUsers;
@@ -85,35 +84,70 @@ describe("TitleEscrowFactory", async () => {
8584
});
8685

8786
describe("Create Title Escrow Contract", () => {
88-
let fakeRegistrySigner: SignerWithAddress;
89-
let titleEscrowFactoryCreateTx: ContractTransaction;
90-
let titleEscrowContract: TitleEscrow;
9187
let tokenId: string;
9288

9389
beforeEach(async () => {
9490
tokenId = faker.datatype.hexaDecimal(64);
95-
fakeRegistrySigner = users.others[faker.datatype.number(users.others.length - 1)];
96-
titleEscrowFactoryCreateTx = await titleEscrowFactory.connect(fakeRegistrySigner).create(tokenId);
91+
});
9792

98-
const receipt = await titleEscrowFactoryCreateTx.wait();
99-
const titleEscrowAddress = getEventFromReceipt<TitleEscrowCreatedEvent>(
100-
receipt,
101-
titleEscrowFactory.interface.getEventTopic("TitleEscrowCreated")
102-
).args.titleEscrow;
93+
describe("Create Caller", () => {
94+
it("should revert when calls create from an EOA", async () => {
95+
const eoa = users.others[faker.datatype.number(users.others.length - 1)];
10396

104-
titleEscrowContract = (await ethers.getContractFactory("TitleEscrow")).attach(titleEscrowAddress) as TitleEscrow;
105-
});
97+
const tx = titleEscrowFactory.connect(eoa).create(tokenId);
10698

107-
it("should create with the correct token registry address", async () => {
108-
const registryAddress = await titleEscrowContract.registry();
99+
await expect(tx).to.be.revertedWithCustomError(titleEscrowFactory, "CreateCallerNotContract");
100+
});
109101

110-
expect(registryAddress).to.equal(fakeRegistrySigner.address);
102+
it("should call create successfully from a contract", async () => {
103+
const dummyContractMock = (await (
104+
await ethers.getContractFactory("DummyContractMock")
105+
).deploy()) as DummyContractMock;
106+
const mockContractSigner = await impersonateAccount({ address: dummyContractMock.address });
107+
108+
const tx = titleEscrowFactory.connect(mockContractSigner).create(tokenId);
109+
110+
await expect(tx).to.not.be.reverted;
111+
});
111112
});
112113

113-
it("should emit TitleEscrowCreated event", async () => {
114-
expect(titleEscrowFactoryCreateTx)
115-
.to.emit(titleEscrowFactory, "TitleEscrowCreated")
116-
.withArgs(titleEscrowContract.address, fakeRegistrySigner.address, tokenId);
114+
describe("Create Title Escrow Behaviours", () => {
115+
let mockContractSigner: Signer;
116+
let titleEscrowFactoryCreateTx: ContractTransaction;
117+
let titleEscrowContract: TitleEscrow;
118+
119+
beforeEach(async () => {
120+
const dummyContractMock = (await (
121+
await ethers.getContractFactory("DummyContractMock")
122+
).deploy()) as DummyContractMock;
123+
mockContractSigner = await impersonateAccount({ address: dummyContractMock.address });
124+
titleEscrowFactoryCreateTx = await titleEscrowFactory.connect(mockContractSigner).create(tokenId);
125+
126+
const receipt = await titleEscrowFactoryCreateTx.wait();
127+
const titleEscrowAddress = getEventFromReceipt<TitleEscrowCreatedEvent>(
128+
receipt,
129+
titleEscrowFactory.interface.getEventTopic("TitleEscrowCreated")
130+
).args.titleEscrow;
131+
132+
titleEscrowContract = (await ethers.getContractFactory("TitleEscrow")).attach(
133+
titleEscrowAddress
134+
) as TitleEscrow;
135+
});
136+
137+
it("should create with the correct token registry address", async () => {
138+
const registryAddress = await titleEscrowContract.registry();
139+
const signerAddress = await mockContractSigner.getAddress();
140+
141+
expect(registryAddress).to.equal(signerAddress);
142+
});
143+
144+
it("should emit TitleEscrowCreated event", async () => {
145+
const signerAddress = await mockContractSigner.getAddress();
146+
147+
expect(titleEscrowFactoryCreateTx)
148+
.to.emit(titleEscrowFactory, "TitleEscrowCreated")
149+
.withArgs(titleEscrowContract.address, signerAddress, tokenId);
150+
});
117151
});
118152
});
119153

0 commit comments

Comments
 (0)