Skip to content

Commit

Permalink
feat: title escrow factory (Open-Attestation#84)
Browse files Browse the repository at this point in the history
* feat: composite factory

* refactor: remove TitleEscrowCloner

* chore: simplify test commands

* refactor: export TitleEscrowFactory in lib

* test: add test for TitleEscrowFactory
  • Loading branch information
superical committed Apr 11, 2022
1 parent 6551bf0 commit fb86103
Show file tree
Hide file tree
Showing 27 changed files with 290 additions and 352 deletions.
12 changes: 4 additions & 8 deletions contracts/TitleEscrowCloneable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import "@openzeppelin/contracts/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "./access/HasNamedBeneficiaryInitializable.sol";
import "./access/HasHolderInitializable.sol";
import "./interfaces/ITitleEscrowCreator.sol";
import "./interfaces/ITitleEscrow.sol";
import "./TitleEscrowFactory.sol";

contract TitleEscrowCloneable is
Context,
Expand All @@ -28,7 +28,7 @@ contract TitleEscrowCloneable is
uint256 public _tokenId;

// Factory to clone this title escrow
ITitleEscrowCreator public titleEscrowFactory;
ITitleEscrowFactory public titleEscrowFactory;

// For exiting into title escrow contracts
address public override approvedBeneficiary;
Expand All @@ -43,7 +43,7 @@ contract TitleEscrowCloneable is
__initialize__holder(_holder);
__initialize__beneficiary(_beneficiary);
tokenRegistry = ERC721(_tokenRegistry);
titleEscrowFactory = ITitleEscrowCreator(_titleEscrowFactoryAddress);
titleEscrowFactory = ITitleEscrowFactory(_titleEscrowFactoryAddress);
status = StatusTypes.Uninitialised;
}

Expand Down Expand Up @@ -115,11 +115,7 @@ contract TitleEscrowCloneable is
onlyHolder
allowTransferTitleEscrow(newBeneficiary, newHolder)
{
address newTitleEscrowAddress = titleEscrowFactory.deployNewTitleEscrow(
address(tokenRegistry),
newBeneficiary,
newHolder
);
address newTitleEscrowAddress = titleEscrowFactory.create(address(tokenRegistry), newBeneficiary, newHolder);
_transferTo(newTitleEscrowAddress);
}

Expand Down
33 changes: 0 additions & 33 deletions contracts/TitleEscrowCloner.sol

This file was deleted.

27 changes: 27 additions & 0 deletions contracts/TitleEscrowFactory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/proxy/Clones.sol";
import "./TitleEscrowCloneable.sol";
import "./interfaces/ITitleEscrowFactory.sol";

contract TitleEscrowFactory is ITitleEscrowFactory {
address public override implementation;

constructor() {
implementation = address(new TitleEscrowCloneable());
}

function create(
address tokenRegistry,
address beneficiary,
address holder
) external override returns (address) {
address clone = Clones.clone(implementation);
TitleEscrowCloneable(clone).initialize(tokenRegistry, beneficiary, holder, address(this));

emit TitleEscrowDeployed(address(clone), tokenRegistry, beneficiary, holder);

return address(clone);
}
}
23 changes: 13 additions & 10 deletions contracts/TradeTrustERC721.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,15 @@
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "./TitleEscrowCloneable.sol";
import "./TitleEscrowCloner.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "./access/RegistryAccess.sol";
import "./interfaces/ITitleEscrowCreator.sol";
import "./interfaces/ITitleEscrow.sol";
import "./interfaces/ITradeTrustERC721.sol";
import "./interfaces/ITitleEscrowFactory.sol";

contract TradeTrustERC721 is ITradeTrustERC721, RegistryAccess, TitleEscrowCloner, Pausable, ERC721 {
contract TradeTrustERC721 is ITradeTrustERC721, RegistryAccess, Pausable, ERC721 {
using Address for address;

event TokenBurnt(uint256 indexed tokenId);
Expand All @@ -21,11 +19,17 @@ contract TradeTrustERC721 is ITradeTrustERC721, RegistryAccess, TitleEscrowClone

address internal constant BURN_ADDRESS = 0x000000000000000000000000000000000000dEaD;

ITitleEscrowFactory public override titleEscrowFactory;

// Mapping from token ID to previously surrendered title escrow address
mapping(uint256 => address) internal _surrenderedOwners;

constructor(string memory name, string memory symbol) ERC721(name, symbol) {
return;
constructor(
string memory name,
string memory symbol,
address _titleEscrowFactory
) ERC721(name, symbol) {
titleEscrowFactory = ITitleEscrowFactory(_titleEscrowFactory);
}

function supportsInterface(bytes4 interfaceId)
Expand All @@ -36,7 +40,6 @@ contract TradeTrustERC721 is ITradeTrustERC721, RegistryAccess, TitleEscrowClone
returns (bool)
{
return
interfaceId == type(ITitleEscrowCreator).interfaceId ||
interfaceId == type(ITradeTrustERC721).interfaceId ||
ERC721.supportsInterface(interfaceId) ||
RegistryAccess.supportsInterface(interfaceId);
Expand Down Expand Up @@ -117,7 +120,7 @@ contract TradeTrustERC721 is ITradeTrustERC721, RegistryAccess, TitleEscrowClone
beneficiary = previousOwner;
holder = previousOwner;
}
address newTitleEscrow = _deployNewTitleEscrow(address(this), beneficiary, holder);
address newTitleEscrow = titleEscrowFactory.create(address(this), beneficiary, holder);
_registrySafeTransformFrom(address(this), newTitleEscrow, tokenId);

emit TokenRestored(tokenId, newTitleEscrow);
Expand Down Expand Up @@ -163,7 +166,7 @@ contract TradeTrustERC721 is ITradeTrustERC721, RegistryAccess, TitleEscrowClone
address holder,
uint256 tokenId
) internal virtual returns (address) {
address newTitleEscrow = _deployNewTitleEscrow(address(this), beneficiary, holder);
address newTitleEscrow = titleEscrowFactory.create(address(this), beneficiary, holder);
_safeMint(newTitleEscrow, tokenId);

return newTitleEscrow;
Expand Down
10 changes: 0 additions & 10 deletions contracts/access/IMinterRole.sol

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

/// @title Title Escrow for Transferable Records
interface ITitleEscrowCreator {
interface ITitleEscrowFactory {
event TitleEscrowDeployed(
address indexed escrowAddress,
address indexed tokenRegistry,
address beneficiary,
address holder
);

/// @notice Deploys an instance of a title escrow
function deployNewTitleEscrow(
function implementation() external view returns (address);

function create(
address tokenRegistry,
address beneficiary,
address holder
Expand Down
3 changes: 3 additions & 0 deletions contracts/interfaces/ITradeTrustERC721.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "../TitleEscrowFactory.sol";

interface ITradeTrustERC721 is IERC721Receiver, IERC721 {
function titleEscrowFactory() external view returns (ITitleEscrowFactory);

function destroyToken(uint256 tokenId) external;

function restoreTitle(uint256 tokenId) external returns (address);
Expand Down
11 changes: 0 additions & 11 deletions contracts/mocks/TitleEscrowClonerMock.sol

This file was deleted.

11 changes: 11 additions & 0 deletions contracts/mocks/TitleEscrowFactoryMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

import "./TitleEscrowCloneableMock.sol";
import "../TitleEscrowFactory.sol";

contract TitleEscrowFactoryMock is TitleEscrowFactory {
constructor() {
implementation = address(new TitleEscrowCloneableMock());
}
}
6 changes: 5 additions & 1 deletion contracts/mocks/TradeTrustERC721Mock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ pragma solidity ^0.8.0;
import "../TradeTrustERC721.sol";

contract TradeTrustERC721Mock is TradeTrustERC721 {
constructor(string memory name, string memory symbol) TradeTrustERC721(name, symbol) {}
constructor(
string memory name,
string memory symbol,
address escrowFactory
) TradeTrustERC721(name, symbol, escrowFactory) {}

function surrenderedOwnersInternal(uint256 tokenId) public view returns (address) {
return _surrenderedOwners[tokenId];
Expand Down
6 changes: 2 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,8 @@
"lint:sol:fix": "npm run lint:sol -- --fix",
"lint": "npm run lint:sol && npm run lint:js",
"lint:fix": "npm run lint:sol:fix && npm run lint:js:fix",
"test:sol": "TS_NODE_TRANSPILE_ONLY=1 hardhat test",
"test:sol:watch": "TS_NODE_TRANSPILE_ONLY=1 hardhat watch test",
"test:js": "jest --testPathPattern=src",
"test": "npm run test:sol && npm run test:js",
"test": "TS_NODE_TRANSPILE_ONLY=1 hardhat test",
"test:watch": "TS_NODE_TRANSPILE_ONLY=1 hardhat watch test",
"prepare": "npm run build",
"semantic-release": "semantic-release",
"precoverage": "npm run clean:build && npm run build:sol",
Expand Down
117 changes: 0 additions & 117 deletions src/index.test.ts

This file was deleted.

4 changes: 2 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/* eslint-disable camelcase */
export {
TitleEscrowCloneable__factory as TitleEscrowCloneableFactory,
TitleEscrowCloner__factory as TitleEscrowClonerFactory,
TitleEscrowFactory__factory as TitleEscrowFactoryFactory,
TradeTrustERC721__factory as TradeTrustERC721Factory,
TitleEscrowCloneable,
TitleEscrowCloner,
TitleEscrowFactory,
TradeTrustERC721,
} from "./contracts";

0 comments on commit fb86103

Please sign in to comment.