Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: remarks handling logic #19

Merged
merged 8 commits into from
Sep 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 55 additions & 51 deletions contracts/TitleEscrow.sol
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,13 @@ contract TitleEscrow is Initializable, IERC165, TitleEscrowErrors, ITitleEscrow
}
_;
}
/**
* @dev Modifier to check if the bytes array length is within the limit
*/
modifier remarkLengthLimit(bytes memory remark) {
if (remark.length > 120) revert RemarkLengthExceeded();
_;
}

/**
* @notice Initializes the TitleEscrow contract with the registry address and the tokenId
Expand Down Expand Up @@ -105,8 +112,8 @@ contract TitleEscrow is Initializable, IERC165, TitleEscrowErrors, ITitleEscrow
* @dev See {IERC721Receiver-onERC721Received}.
*/
function onERC721Received(
address, /* operator */
address, /* from */
address /* operator */,
address /* from */,
uint256 _tokenId,
bytes calldata data
) external virtual override whenNotPaused whenActive returns (bytes4) {
Expand All @@ -125,8 +132,8 @@ contract TitleEscrow is Initializable, IERC165, TitleEscrowErrors, ITitleEscrow
if (_beneficiary == address(0) || _holder == address(0)) {
revert InvalidTokenTransferToZeroAddressOwners(_beneficiary, _holder);
}
_setBeneficiary(_beneficiary);
_setHolder(_holder);
_setBeneficiary(_beneficiary, "");
_setHolder(_holder, "");
isMinting = true;
}

Expand All @@ -137,103 +144,100 @@ contract TitleEscrow is Initializable, IERC165, TitleEscrowErrors, ITitleEscrow
/**
* @dev See {ITitleEscrow-nominate}.
*/
function nominate(address _nominee)
public
virtual
override
whenNotPaused
whenActive
onlyBeneficiary
whenHoldingToken
{
function nominate(
address _nominee,
bytes memory remark
) public virtual override whenNotPaused whenActive onlyBeneficiary whenHoldingToken remarkLengthLimit(remark) {
if (beneficiary == _nominee) {
revert TargetNomineeAlreadyBeneficiary();
}
if (nominee == _nominee) {
revert NomineeAlreadyNominated();
}

_setNominee(_nominee);
_setNominee(_nominee, remark);
}

/**
* @dev See {ITitleEscrow-transferBeneficiary}.
*/
function transferBeneficiary(address _nominee)
public
virtual
override
whenNotPaused
whenActive
onlyHolder
whenHoldingToken
{
function transferBeneficiary(
address _nominee,
bytes memory remark
) public virtual override whenNotPaused whenActive onlyHolder whenHoldingToken remarkLengthLimit(remark) {
if (_nominee == address(0)) {
revert InvalidTransferToZeroAddress();
}
if (!(beneficiary == holder || nominee == _nominee)) {
revert InvalidNominee();
}

_setBeneficiary(_nominee);
_setBeneficiary(_nominee, remark);
}

/**
* @dev See {ITitleEscrow-transferHolder}.
*/
function transferHolder(address newHolder)
public
virtual
override
whenNotPaused
whenActive
onlyHolder
whenHoldingToken
{
function transferHolder(
address newHolder,
bytes memory remark
) public virtual override whenNotPaused whenActive onlyHolder whenHoldingToken remarkLengthLimit(remark) {
if (newHolder == address(0)) {
revert InvalidTransferToZeroAddress();
}
if (holder == newHolder) {
revert RecipientAlreadyHolder();
}

_setHolder(newHolder);
_setHolder(newHolder, remark);
}

/**
* @dev See {ITitleEscrow-transferOwners}.
*/
function transferOwners(address _nominee, address newHolder) external virtual override {
transferBeneficiary(_nominee);
transferHolder(newHolder);
function transferOwners(address _nominee, address newHolder, bytes memory remark) external virtual override {
transferBeneficiary(_nominee, remark);
transferHolder(newHolder, remark);
}

/**
* @dev See {ITitleEscrow-surrender}.
*/
function surrender() external virtual override whenNotPaused whenActive onlyBeneficiary onlyHolder whenHoldingToken {
_setNominee(address(0));
function surrender(
bytes memory remark
)
external
virtual
override
whenNotPaused
whenActive
onlyBeneficiary
onlyHolder
whenHoldingToken
remarkLengthLimit(remark)
{
_setNominee(address(0), "");
ITradeTrustToken(registry).transferFrom(address(this), registry, tokenId);

emit Surrender(msg.sender, registry, tokenId);
emit Surrender(msg.sender, registry, tokenId, remark);
}

/**
* @dev See {ITitleEscrow-shred}.
*/
function shred() external virtual override whenNotPaused whenActive {
function shred(bytes memory remark) external virtual override whenNotPaused whenActive remarkLengthLimit(remark) {
if (_isHoldingToken()) {
revert TokenNotSurrendered();
}
if (msg.sender != registry) {
revert InvalidRegistry(msg.sender);
}

_setBeneficiary(address(0));
_setHolder(address(0));
_setBeneficiary(address(0), "");
_setHolder(address(0), "");
active = false;

emit Shred(registry, tokenId);
emit Shred(registry, tokenId, remark);
}

/**
Expand All @@ -255,27 +259,27 @@ contract TitleEscrow is Initializable, IERC165, TitleEscrowErrors, ITitleEscrow
* @notice Sets the nominee
* @param newNominee The address of the new nominee
*/
function _setNominee(address newNominee) internal virtual {
emit Nomination(nominee, newNominee, registry, tokenId);
function _setNominee(address newNominee, bytes memory remark) internal virtual {
emit Nomination(nominee, newNominee, registry, tokenId, remark);
nominee = newNominee;
}

/**
* @notice Sets the beneficiary
* @param newBeneficiary The address of the new beneficiary
*/
function _setBeneficiary(address newBeneficiary) internal virtual {
emit BeneficiaryTransfer(beneficiary, newBeneficiary, registry, tokenId);
_setNominee(address(0));
function _setBeneficiary(address newBeneficiary, bytes memory remark) internal virtual {
emit BeneficiaryTransfer(beneficiary, newBeneficiary, registry, tokenId, remark);
if (nominee != address(0)) _setNominee(address(0), "");
beneficiary = newBeneficiary;
}

/**
* @notice Sets the holder
* @param newHolder The address of the new holder
*/
function _setHolder(address newHolder) internal virtual {
emit HolderTransfer(holder, newHolder, registry, tokenId);
function _setHolder(address newHolder, bytes memory remark) internal virtual {
emit HolderTransfer(holder, newHolder, registry, tokenId, remark);
holder = newHolder;
}
}
9 changes: 5 additions & 4 deletions contracts/base/TradeTrustTokenBurnable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,18 @@ abstract contract TradeTrustTokenBurnable is TradeTrustSBT, RegistryAccess, ITra
/**
* @dev See {ITradeTrustTokenBurnable-burn}.
*/
function burn(uint256 tokenId) external virtual override whenNotPaused onlyRole(ACCEPTER_ROLE) {
_burnTitle(tokenId);
function burn(uint256 tokenId, bytes memory remark) external virtual override whenNotPaused onlyRole(ACCEPTER_ROLE) {
if (remark.length > 120) revert RemarkLengthExceeded();
_burnTitle(tokenId, remark);
}

/**
* @dev Internal function to burn a token.
* @param tokenId The ID of the token to burn.
*/
function _burnTitle(uint256 tokenId) internal virtual {
function _burnTitle(uint256 tokenId, bytes memory remark) internal virtual {
address titleEscrow = titleEscrowFactory().getAddress(address(this), tokenId);
ITitleEscrow(titleEscrow).shred();
ITitleEscrow(titleEscrow).shred(remark);

// Burning token to 0xdead instead to show a differentiate state as address(0) is used for unminted tokens
_registryTransferTo(BURN_ADDRESS, tokenId);
Expand Down
35 changes: 24 additions & 11 deletions contracts/interfaces/ITitleEscrow.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,42 +16,55 @@ interface ITitleEscrow is IERC721Receiver {
address registry,
uint256 tokenId
);
event Nomination(address indexed prevNominee, address indexed nominee, address registry, uint256 tokenId);
event Nomination(
address indexed prevNominee,
address indexed nominee,
address registry,
uint256 tokenId,
bytes remark
);
event BeneficiaryTransfer(
address indexed fromBeneficiary,
address indexed toBeneficiary,
address registry,
uint256 tokenId
uint256 tokenId,
bytes remark
);
event HolderTransfer(
address indexed fromHolder,
address indexed toHolder,
address registry,
uint256 tokenId,
bytes remark
);
event HolderTransfer(address indexed fromHolder, address indexed toHolder, address registry, uint256 tokenId);
event Surrender(address indexed surrenderer, address registry, uint256 tokenId);
event Shred(address registry, uint256 tokenId);
event Surrender(address indexed surrenderer, address registry, uint256 tokenId, bytes remark);
event Shred(address registry, uint256 tokenId, bytes remark);

/**
* @notice Allows the beneficiary to nominate a new beneficiary
* @dev The nominated beneficiary will need to be transferred by the holder to become the actual beneficiary
* @param nominee The address of the nominee
*/
function nominate(address nominee) external;
function nominate(address nominee, bytes memory remark) external;

/**
* @notice Allows the holder to transfer the beneficiary role to the nominated beneficiary or to themselves
* @param nominee The address of the new beneficiary
*/
function transferBeneficiary(address nominee) external;
function transferBeneficiary(address nominee, bytes memory remark) external;

/**
* @notice Allows the holder to transfer their role to another address
* @param newHolder The address of the new holder
*/
function transferHolder(address newHolder) external;
function transferHolder(address newHolder, bytes memory remark) external;

/**
* @notice Allows for the simultaneous transfer of both beneficiary and holder roles
* @param nominee The address of the new beneficiary
* @param newHolder The address of the new holder
*/
function transferOwners(address nominee, address newHolder) external;
function transferOwners(address nominee, address newHolder, bytes memory remark) external;

function beneficiary() external view returns (address);

Expand All @@ -74,10 +87,10 @@ interface ITitleEscrow is IERC721Receiver {
/**
* @notice Allows the beneficiary and holder to surrender the token back to the registry
*/
function surrender() external;
function surrender(bytes memory remark) external;

/**
* @notice Allows the registry to shred the TitleEscrow by marking it as inactive and reset the beneficiary and holder addresses
*/
function shred() external;
function shred(bytes memory remark) external;
}
2 changes: 1 addition & 1 deletion contracts/interfaces/ITradeTrustTokenBurnable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ interface ITradeTrustTokenBurnable {
* @dev Burn a token.
* @param tokenId The ID of the token to burn.
*/
function burn(uint256 tokenId) external;
function burn(uint256 tokenId, bytes memory remark) external;
}
6 changes: 1 addition & 5 deletions contracts/interfaces/ITradeTrustTokenMintable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,5 @@ interface ITradeTrustTokenMintable {
* @param tokenId The ID of the token to mint.
* @return The address of the corresponding TitleEscrow.
*/
function mint(
address beneficiary,
address holder,
uint256 tokenId
) external returns (address);
function mint(address beneficiary, address holder, uint256 tokenId) external returns (address);
}
2 changes: 2 additions & 0 deletions contracts/interfaces/TitleEscrowErrors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,6 @@ interface TitleEscrowErrors {
error RecipientAlreadyHolder();

error TokenNotSurrendered();

error RemarkLengthExceeded();
}
2 changes: 2 additions & 0 deletions contracts/interfaces/TradeTrustTokenErrors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ interface TradeTrustTokenErrors {
error TokenExists();

error TransferFailure();

error RemarkLengthExceeded();
}
29 changes: 10 additions & 19 deletions contracts/presets/TitleEscrowSignable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,10 @@ contract TitleEscrowSignable is SigHelper, TitleEscrow, TitleEscrowSignableError
/**
* @dev See {ITitleEscrowSignable-transferBeneficiaryWithSig}.
*/
function transferBeneficiaryWithSig(BeneficiaryTransferEndorsement memory endorsement, Sig memory sig)
public
virtual
override
whenNotPaused
whenActive
onlyBeneficiary
whenHoldingToken
{
function transferBeneficiaryWithSig(
BeneficiaryTransferEndorsement memory endorsement,
Sig memory sig
) public virtual override whenNotPaused whenActive onlyBeneficiary whenHoldingToken {
if (endorsement.deadline < block.timestamp) {
revert SignatureExpired(block.timestamp);
}
Expand Down Expand Up @@ -71,19 +66,15 @@ contract TitleEscrowSignable is SigHelper, TitleEscrow, TitleEscrowSignableError
}

++nonces[holder];
_setBeneficiary(endorsement.nominee);
_setBeneficiary(endorsement.nominee, "");
}

/**
* @dev See {ITitleEscrowSignable-cancelBeneficiaryTransfer}.
*/
function cancelBeneficiaryTransfer(BeneficiaryTransferEndorsement memory endorsement)
public
virtual
override
whenNotPaused
whenActive
{
function cancelBeneficiaryTransfer(
BeneficiaryTransferEndorsement memory endorsement
) public virtual override whenNotPaused whenActive {
if (msg.sender != endorsement.holder) {
revert CallerNotEndorser();
}
Expand All @@ -110,8 +101,8 @@ contract TitleEscrowSignable is SigHelper, TitleEscrow, TitleEscrowSignableError
);
}

function _setHolder(address newHolder) internal virtual override {
function _setHolder(address newHolder, bytes memory remark) internal virtual override {
++nonces[holder];
super._setHolder(newHolder);
super._setHolder(newHolder, remark);
}
}
Loading
Loading