interfaceIERC6997{structTransferValidation{// The address of the owner.
addressfrom;// The address of the receiver.
addressto;// The token Id.
uint256tokenId;// Whether is a valid transfer.
boolvalid;}structApprovalValidation{// The address of the owner.
addressowner;// The approved address.
addressapprove;// The token Id.
uint256tokenId;// Whether it is a total approval.
boolapproveAll;// Whether it is a valid approval.
boolvalid;}/**
* @dev Emitted when a new transfer validation has been requested.
*/eventValidateTransfer(addressindexedfrom,addressto,uint256indexedtokenId,uint256indexedtransferValidationId);/**
* @dev Emitted when a new approval validation has been requested.
*/eventValidateApproval(addressindexedowner,addressapprove,uint256tokenId,boolindexedapproveAll,uint256indexedapprovalValidationId);/**
* @dev Returns true if this contract is a validator ERC721.
*/functionisValidatorContract()externalviewreturns(bool);/**
* @dev Returns the transfer validation struct using the transfer ID.
*
*/functiontransferValidation(uint256transferId)externalviewreturns(TransferValidationmemory);/**
* @dev Returns the approval validation struct using the approval ID.
*
*/functionapprovalValidation(uint256approvalId)externalviewreturns(ApprovalValidationmemory);/**
* @dev Return the total amount of transfer validations created.
*
*/functiontotalTransferValidations()externalviewreturns(uint256);/**
* @dev Return the total amount of transfer validations created.
*
*/functiontotalApprovalValidations()externalviewreturns(uint256);}
isValidatorContract() 函数必须实现为 public。
transferValidation(uint256 transferId) 函数可以实现为 public 或 external。
approvalValidation(uint256 approveId) 函数可以实现为 public 或 external。
// SPDX-License-Identifier: CC0-1.0
pragmasolidity^0.8.0;import"./IERC6997.sol";import"@openzeppelin/contracts/token/ERC721/ERC721.sol";/**
* @dev Implementation of ERC6997
*/contractERC6997isIERC6997,ERC721{// Mapping from transfer ID to transfer validation
// 从转移 ID 到转移验证的映射
mapping(uint256=>TransferValidation)private_transferValidations;// Mapping from approval ID to approval validation
// 从批准 ID 到批准验证的映射
mapping(uint256=>ApprovalValidation)private_approvalValidations;// Total number of transfer validations
// 转移验证总数
uint256private_totalTransferValidations;// Total number of approval validations
// 批准验证总数
uint256private_totalApprovalValidations;/**
* @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
*/constructor(stringmemoryname_,stringmemorysymbol_)ERC721(name_,symbol_){}/**
* @dev Returns true if this contract is a validator ERC721.
*/functionisValidatorContract()publicpurereturns(bool){returntrue;}/**
* @dev Returns the transfer validation struct using the transfer ID.
*
*/functiontransferValidation(uint256transferId)publicviewoverridereturns(TransferValidationmemory){require(transferId<_totalTransferValidations,"ERC6997: invalid transfer ID");TransferValidationmemoryv=_transferValidation(transferId);returnv;}/**
* @dev Returns the approval validation struct using the approval ID.
*
*/functionapprovalValidation(uint256approvalId)publicviewoverridereturns(ApprovalValidationmemory){require(approvalId<_totalApprovalValidations,"ERC6997: invalid approval ID");ApprovalValidationmemoryv=_approvalValidation(approvalId);returnv;}/**
* @dev Return the total amount of transfer validations created.
*
*/functiontotalTransferValidations()publicviewoverridereturns(uint256){return_totalTransferValidations;}/**
* @dev Return the total amount of approval validations created.
*
*/functiontotalApprovalValidations()publicviewoverridereturns(uint256){return_totalApprovalValidations;}/**
* @dev Returns the transfer validation of the `transferId`. Does NOT revert if transfer doesn't exist
*/function_transferValidation(uint256transferId)internalviewvirtualreturns(TransferValidationmemory){return_transferValidations[transferId];}/**
* @dev Returns the approval validation of the `approvalId`. Does NOT revert if transfer doesn't exist
*/function_approvalValidation(uint256approvalId)internalviewvirtualreturns(ApprovalValidationmemory){return_approvalValidations[approvalId];}/**
* @dev Validate the transfer using the transfer ID.
*
*/function_validateTransfer(uint256transferId)internalvirtual{TransferValidationmemoryv=transferValidation(transferId);require(!v.valid,"ERC6997: the transfer is already validated");addressfrom=v.from;addressto=v.to;uint256tokenId=v.tokenId;super._transfer(from,to,tokenId);_transferValidations[transferId].valid=true;}/**
* @dev Validate the approval using the approval ID.
*
*/function_validateApproval(uint256approvalId)internalvirtual{ApprovalValidationmemoryv=approvalValidation(approvalId);require(!v.valid,"ERC6997: the approval is already validated");if(!v.approveAll){require(v.owner==ownerOf(v.tokenId),"ERC6997: The token have a new owner");super._approve(v.approve,v.tokenId);}else{super._setApprovalForAll(v.owner,v.approve,true);}_approvalValidations[approvalId].valid=true;}/**
* @dev Create a transfer petition of `tokenId` from `from` to `to`.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
*
* Emits a {TransferValidate} event.
*/function_transfer(addressfrom,addressto,uint256tokenId)internalvirtualoverride{require(ERC721.ownerOf(tokenId)==from,"ERC6997: transfer from incorrect owner");require(to!=address(0),"ERC6997: transfer to the zero address");if(_msgSender()==from){TransferValidationmemoryv;v.from=from;v.to=to;v.tokenId=tokenId;_transferValidations[_totalTransferValidations]=v;emitValidateTransfer(from,to,tokenId,_totalTransferValidations);_totalTransferValidations++;}else{super._transfer(from,to,tokenId);}}/**
* @dev Create an approval petition from `to` to operate on `tokenId`
*
* Emits an {ValidateApproval} event.
*/function_approve(addressto,uint256tokenId)internaloverridevirtual{ApprovalValidationmemoryv;v.owner=ownerOf(tokenId);v.approve=to;v.tokenId=tokenId;_approvalValidations[_totalApprovalValidations]=v;emitValidateApproval(v.owner,to,tokenId,false,_totalApprovalValidations);_totalApprovalValidations++;}/**
* @dev If approved is true create an approval petition from `operator` to operate on
* all of `owner` tokens, if not remove `operator` from operate on all of `owner` tokens
*
* Emits an {ValidateApproval} event.
*/function_setApprovalForAll(addressowner,addressoperator,boolapproved)internaloverridevirtual{require(owner!=operator,"ERC6997: approve to caller");if(approved){ApprovalValidationmemoryv;v.owner=owner;v.approve=operator;v.approveAll=true;_approvalValidations[_totalApprovalValidations]=v;emitValidateApproval(v.owner,operator,0,true,_totalApprovalValidations);_totalApprovalValidations++;}else{super._setApprovalForAll(owner,operator,approved);}}}