Skip to content

Commit

Permalink
feat: refactor codebase (#144)
Browse files Browse the repository at this point in the history
* refactor: rename TradeTrustTokenImpl to TradeTrustTokenStandard

* refactor: rename test files token names

* refactor: rename init function to token name

* refactor: move pausable and registry access into base

* feat: restructure the codebase

fix: remove extensions

* test: separate mint, burn and restore tests

* test: remove mint, burn and restore tests from TradeTrustToken.test.ts

* test: refactor deployTokenFixtureRunner

* test: add interface support test in all extension bases

* test: update tests

* feat: update contract testnet addresses

* feat: add mainnet contract addresses

* fix: gap
  • Loading branch information
superical committed Nov 28, 2022
1 parent ce9c8c0 commit a4865e8
Show file tree
Hide file tree
Showing 33 changed files with 1,007 additions and 577 deletions.
2 changes: 1 addition & 1 deletion contracts/TradeTrustToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ contract TradeTrustToken is TradeTrustTokenBase {
string memory symbol,
address admin
) internal initializer {
__TradeTrustERC721Base_init(name, symbol, admin);
__TradeTrustTokenBase_init(name, symbol, admin);
}

function titleEscrowFactory() public view override returns (ITitleEscrowFactory) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pragma solidity ^0.8.0;
import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import "../interfaces/RegistryAccessErrors.sol";

abstract contract RegistryAccess is RegistryAccessErrors, AccessControlUpgradeable {
abstract contract RegistryAccess is AccessControlUpgradeable, RegistryAccessErrors {
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
bytes32 public constant RESTORER_ROLE = keccak256("RESTORER_ROLE");
bytes32 public constant ACCEPTER_ROLE = keccak256("ACCEPTER_ROLE");
Expand All @@ -19,7 +19,7 @@ abstract contract RegistryAccess is RegistryAccessErrors, AccessControlUpgradeab
_setupRole(ACCEPTER_ROLE, admin);
}

function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
function supportsInterface(bytes4 interfaceId) public view virtual override(AccessControlUpgradeable) returns (bool) {
return super.supportsInterface(interfaceId);
}

Expand Down
2 changes: 1 addition & 1 deletion contracts/base/SBTUpgradeable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -366,5 +366,5 @@ contract SBTUpgradeable is
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[44] private __gap;
uint256[46] private __gap;
}
51 changes: 51 additions & 0 deletions contracts/base/TradeTrustSBT.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import "./SBTUpgradeable.sol";
import "../interfaces/ITitleEscrow.sol";
import "../interfaces/ITitleEscrowFactory.sol";
import "../interfaces/TradeTrustTokenErrors.sol";
import "../interfaces/ITradeTrustSBT.sol";

abstract contract TradeTrustSBT is SBTUpgradeable, PausableUpgradeable, TradeTrustTokenErrors, ITradeTrustSBT {
function __TradeTrustSBT_init(string memory name, string memory symbol) internal onlyInitializing {
__SBT_init(name, symbol);
__Pausable_init();
}

function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(SBTUpgradeable, IERC165Upgradeable)
returns (bool)
{
return interfaceId == type(ITradeTrustSBT).interfaceId || SBTUpgradeable.supportsInterface(interfaceId);
}

function onERC721Received(
address, /* _operator */
address, /* _from */
uint256, /* _tokenId */
bytes memory /* _data */
) public pure override returns (bytes4) {
return IERC721Receiver.onERC721Received.selector;
}

function _registryTransferTo(address to, uint256 tokenId) internal {
this.transferFrom(address(this), to, tokenId);
}

function _beforeTokenTransfer(
address from,
address to,
uint256 tokenId
) internal virtual override whenNotPaused {
super._beforeTokenTransfer(from, to, tokenId);
}

function genesis() public view virtual override returns (uint256);

function titleEscrowFactory() public view virtual override returns (ITitleEscrowFactory);
}
108 changes: 23 additions & 85 deletions contracts/base/TradeTrustTokenBase.sol
Original file line number Diff line number Diff line change
@@ -1,87 +1,42 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import "./SBTUpgradeable.sol";
import "../access/RegistryAccess.sol";
import "./RegistryAccess.sol";
import "./TradeTrustTokenBurnable.sol";
import "./TradeTrustTokenMintable.sol";
import "./TradeTrustTokenRestorable.sol";
import "../interfaces/ITradeTrustToken.sol";
import "../interfaces/ITitleEscrow.sol";
import "../interfaces/ITitleEscrowFactory.sol";
import "../interfaces/TradeTrustTokenErrors.sol";

abstract contract TradeTrustTokenBase is
TradeTrustSBT,
RegistryAccess,
PausableUpgradeable,
SBTUpgradeable,
TradeTrustTokenErrors,
ITradeTrustToken
TradeTrustTokenBurnable,
TradeTrustTokenMintable,
TradeTrustTokenRestorable
{
address internal constant BURN_ADDRESS = 0x000000000000000000000000000000000000dEaD;

function __TradeTrustERC721Base_init(
function __TradeTrustTokenBase_init(
string memory name,
string memory symbol,
address admin
) internal onlyInitializing {
__SBT_init(name, symbol);
__Pausable_init();
__TradeTrustSBT_init(name, symbol);
__RegistryAccess_init(admin);
}

function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(SBTUpgradeable, IERC165Upgradeable, RegistryAccess)
override(
TradeTrustSBT,
RegistryAccess,
TradeTrustTokenRestorable,
TradeTrustTokenMintable,
TradeTrustTokenBurnable
)
returns (bool)
{
return
interfaceId == type(ITradeTrustToken).interfaceId ||
SBTUpgradeable.supportsInterface(interfaceId) ||
RegistryAccess.supportsInterface(interfaceId);
}

function onERC721Received(
address, /* _operator */
address, /* _from */
uint256, /* _tokenId */
bytes memory /* _data */
) public pure override returns (bytes4) {
return IERC721Receiver.onERC721Received.selector;
}

function burn(uint256 tokenId) external override whenNotPaused onlyRole(ACCEPTER_ROLE) {
address titleEscrow = titleEscrowFactory().getAddress(address(this), tokenId);
ITitleEscrow(titleEscrow).shred();

// Burning token to 0xdead instead to show a differentiate state as address(0) is used for unminted tokens
_registryTransferTo(BURN_ADDRESS, tokenId);
}

function mint(
address beneficiary,
address holder,
uint256 tokenId
) public virtual override whenNotPaused onlyRole(MINTER_ROLE) returns (address) {
if (_exists(tokenId)) {
revert TokenExists();
}

return _mintTitle(beneficiary, holder, tokenId);
}

function restore(uint256 tokenId) external override whenNotPaused onlyRole(RESTORER_ROLE) returns (address) {
if (!_exists(tokenId)) {
revert InvalidTokenId();
}
if (ownerOf(tokenId) != address(this)) {
revert TokenNotSurrendered();
}

address titleEscrow = titleEscrowFactory().getAddress(address(this), tokenId);
_registryTransferTo(titleEscrow, tokenId);

return titleEscrow;
return interfaceId == type(ITradeTrustToken).interfaceId || super.supportsInterface(interfaceId);
}

function pause() external onlyRole(DEFAULT_ADMIN_ROLE) {
Expand All @@ -96,29 +51,12 @@ abstract contract TradeTrustTokenBase is
address from,
address to,
uint256 tokenId
) internal virtual override whenNotPaused {
if (to == BURN_ADDRESS && ownerOf(tokenId) != address(this)) {
revert TokenNotSurrendered();
}
) internal virtual override(TradeTrustSBT, TradeTrustTokenBurnable) whenNotPaused {
super._beforeTokenTransfer(from, to, tokenId);
}

function _mintTitle(
address beneficiary,
address holder,
uint256 tokenId
) internal virtual returns (address) {
address newTitleEscrow = titleEscrowFactory().create(tokenId);
_safeMint(newTitleEscrow, tokenId, abi.encode(beneficiary, holder));

return newTitleEscrow;
}

function _registryTransferTo(address to, uint256 tokenId) internal {
this.transferFrom(address(this), to, tokenId);
address titleEscrow = titleEscrowFactory().getAddress(address(this), tokenId);
if (to != address(this) && to != titleEscrow && to != BURN_ADDRESS) {
revert TransferFailure();
}
}

function genesis() public view virtual override returns (uint256);

function titleEscrowFactory() public view virtual override returns (ITitleEscrowFactory);
}
43 changes: 43 additions & 0 deletions contracts/base/TradeTrustTokenBurnable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

import "./TradeTrustSBT.sol";
import "./RegistryAccess.sol";
import "../interfaces/ITradeTrustTokenBurnable.sol";

abstract contract TradeTrustTokenBurnable is TradeTrustSBT, RegistryAccess, ITradeTrustTokenBurnable {
address internal constant BURN_ADDRESS = 0x000000000000000000000000000000000000dEaD;

function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(TradeTrustSBT, RegistryAccess)
returns (bool)
{
return interfaceId == type(ITradeTrustTokenBurnable).interfaceId || super.supportsInterface(interfaceId);
}

function burn(uint256 tokenId) external virtual override whenNotPaused onlyRole(ACCEPTER_ROLE) {
_burnTitle(tokenId);
}

function _burnTitle(uint256 tokenId) internal virtual {
address titleEscrow = titleEscrowFactory().getAddress(address(this), tokenId);
ITitleEscrow(titleEscrow).shred();

// Burning token to 0xdead instead to show a differentiate state as address(0) is used for unminted tokens
_registryTransferTo(BURN_ADDRESS, tokenId);
}

function _beforeTokenTransfer(
address from,
address to,
uint256 tokenId
) internal virtual override {
if (to == BURN_ADDRESS && ownerOf(tokenId) != address(this)) {
revert TokenNotSurrendered();
}
super._beforeTokenTransfer(from, to, tokenId);
}
}
41 changes: 41 additions & 0 deletions contracts/base/TradeTrustTokenMintable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

import "./TradeTrustSBT.sol";
import "./RegistryAccess.sol";
import "../interfaces/ITradeTrustTokenMintable.sol";

abstract contract TradeTrustTokenMintable is TradeTrustSBT, RegistryAccess, ITradeTrustTokenMintable {
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(TradeTrustSBT, RegistryAccess)
returns (bool)
{
return interfaceId == type(ITradeTrustTokenMintable).interfaceId || super.supportsInterface(interfaceId);
}

function mint(
address beneficiary,
address holder,
uint256 tokenId
) external virtual override whenNotPaused onlyRole(MINTER_ROLE) returns (address) {
return _mintTitle(beneficiary, holder, tokenId);
}

function _mintTitle(
address beneficiary,
address holder,
uint256 tokenId
) internal virtual returns (address) {
if (_exists(tokenId)) {
revert TokenExists();
}

address newTitleEscrow = titleEscrowFactory().create(tokenId);
_safeMint(newTitleEscrow, tokenId, abi.encode(beneficiary, holder));

return newTitleEscrow;
}
}
32 changes: 32 additions & 0 deletions contracts/base/TradeTrustTokenRestorable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

import "./TradeTrustSBT.sol";
import "./RegistryAccess.sol";
import "../interfaces/ITradeTrustTokenRestorable.sol";

abstract contract TradeTrustTokenRestorable is TradeTrustSBT, RegistryAccess, ITradeTrustTokenRestorable {
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(TradeTrustSBT, RegistryAccess)
returns (bool)
{
return interfaceId == type(ITradeTrustTokenRestorable).interfaceId || super.supportsInterface(interfaceId);
}

function restore(uint256 tokenId) external virtual override whenNotPaused onlyRole(RESTORER_ROLE) returns (address) {
if (!_exists(tokenId)) {
revert InvalidTokenId();
}
if (ownerOf(tokenId) != address(this)) {
revert TokenNotSurrendered();
}

address titleEscrow = titleEscrowFactory().getAddress(address(this), tokenId);
_registryTransferTo(titleEscrow, tokenId);

return titleEscrow;
}
}
12 changes: 12 additions & 0 deletions contracts/interfaces/ITradeTrustSBT.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

import "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721ReceiverUpgradeable.sol";
import "./ISBTUpgradeable.sol";
import "./ITitleEscrowFactory.sol";

interface ITradeTrustSBT is IERC721ReceiverUpgradeable, ISBTUpgradeable {
function genesis() external view returns (uint256);

function titleEscrowFactory() external view returns (ITitleEscrowFactory);
}
30 changes: 11 additions & 19 deletions contracts/interfaces/ITradeTrustToken.sol
Original file line number Diff line number Diff line change
@@ -1,22 +1,14 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

import "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721ReceiverUpgradeable.sol";
import "./ISBTUpgradeable.sol";
import "./ITitleEscrowFactory.sol";

interface ITradeTrustToken is IERC721ReceiverUpgradeable, ISBTUpgradeable {
function genesis() external view returns (uint256);

function titleEscrowFactory() external view returns (ITitleEscrowFactory);

function burn(uint256 tokenId) external;

function restore(uint256 tokenId) external returns (address);

function mint(
address beneficiary,
address holder,
uint256 tokenId
) external returns (address);
}
import "./ITradeTrustSBT.sol";
import "./ITradeTrustTokenRestorable.sol";
import "./ITradeTrustTokenBurnable.sol";
import "./ITradeTrustTokenMintable.sol";

interface ITradeTrustToken is
ITradeTrustTokenMintable,
ITradeTrustTokenBurnable,
ITradeTrustTokenRestorable,
ITradeTrustSBT
{}
6 changes: 6 additions & 0 deletions contracts/interfaces/ITradeTrustTokenBurnable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

interface ITradeTrustTokenBurnable {
function burn(uint256 tokenId) external;
}

0 comments on commit a4865e8

Please sign in to comment.