NFT 轉賬不一致?
我對區塊鏈相當陌生。我對
ERC-721
NFT 的理解是它應該在地址之間以原子方式傳遞。特別是,如果我跟踪 NFT 的**“from”和“to”**欄位,並且當我查看跨時間的交易時,我希望看到如下內容:
from -> to ========== A -> B B -> C C -> D
這通常是正確的,但也有例外。例如,在檢查以下 NFT 時,它似乎從一個錢包“傳送”到另一個錢包:
這不是一個孤立的案例。誰能幫我理解發生了什麼?
您正在談論的特定令牌是垃圾郵件令牌。它的目的是通知盡可能多的人“你有一個免費的令牌”,這樣它就可以欺騙你把注意力放在可能不值得你注意的事情上。
請參閱https://etherscan.io/address/0x11bCfAe88954f2961389658f5e57bE3B4d83D03E#code上的合約程式碼
特別是
function emitTransfers(uint256[] calldata tokenId, address[] calldata from, address[] calldata to) external onlyOwner { require(tokenId.length == from.length && from.length == to.length, "Arrays do not match."); for(uint256 i = 0;i < tokenId.length;i++) { if(_owners[tokenId[i]] == address(0)) { emit Transfer(from[i], to[i], tokenId[i]); } } }
在這裡,合約的所有者,垃圾郵件發送者 0xbfb12a8d07bb458dc05bef8edc5425da54651c4e,正在廣播
Transfer
事件。合約沒有強制要求這些代幣在最後一個 TO 地址和下一個 FROM 地址之間具有連續性。
人們這樣做的另一個原因是,如果某個知名人士是 TO 地址,它就會出現。一些自動化工具會注意到這一點,並將此交易標記為對 TO 人對契約的背書。
當然這是一個騙局,因為 TO 人在交易中沒有代理權。
是的,很難用幾行來解釋,但要理解轉移工作流程,
ERC-721
標準是基於可替代令牌標準ERC-20
的,因此它們都提供以下功能:將代幣從一個賬戶轉移到另一個賬戶,獲取一個賬戶的目前代幣數量,並批准第三方賬戶是否可以轉移代幣。
此外,ERC-721 代幣還提供以下 NFT 獨有的功能:
獲取特定令牌的所有者
那麼可以說 ERC-20 和 ERC-721 有兩個工作流程將代幣從一個地址轉移到另一個地址。第一個工作流在所有者轉移代幣時使用,它在
_transfer()
內部函式中實現如下:/** * Transfers `tokenId` from `from` to `to`. * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. * * Requirements: * * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * * Emits a {Transfer} event. */ function _transfer( address from, address to, uint256 tokenId ) internal virtual { require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner"); require(to != address(0), "ERC721: transfer to the zero address"); _beforeTokenTransfer(from, to, tokenId); // Clear approvals from the previous owner _approve(address(0), tokenId); _balances[from] -= 1; _balances[to] += 1; _owners[tokenId] = to; emit Transfer(from, to, tokenId); _afterTokenTransfer(from, to, tokenId); }
當第三方代表所有者使用該功能轉移代幣時,使用第二個轉移代幣的工作流程。
transferFrom()
function transferFrom( address from, address to, uint256 tokenId ) public virtual override { //solhint-disable-next-line max-line-length require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); _transfer(from, to, tokenId); }
換句話說,該
transferFrom()
函式正在檢查以下任何條件是否為真:
- msg.sender (呼叫此函式的人)是所有者。
- msg.sender已被批准代表所有者轉移令牌**。**
- 所有者已批准msg.sender轉移其所有代幣。
當所有者呼叫 transferFrom() 函式時,第一個條件為“真” **。**這意味著我們可以在上一節中看到的傳輸工作流程中使用 transferFrom() 函式。
該
getApproved()
函式用於第二個條件,它只是查找_tokenApprovals
私有變數。function getApproved(uint256 tokenId) public view virtual override returns (address) { require(_exists(tokenId), "ERC721: approved query for nonexistent token"); return _tokenApprovals[tokenId]; }
該
_tokenApprovals
變數是令牌 ID和address
.// Mapping from token ID to approved address mapping(uint256 => address) private _tokenApprovals;
因此,所有者需要首先呼叫approve() 函式才能使第二個條件為真。它將花費者地址和令牌 ID 添加到 _tokenApprovals 變數中,因此 _isApprovedOrOwner() 內部函式將返回 true。
在第三個條件中,該
isApprovedForAll()
函式檢查所有者是否已給予msg.sender全面批准以發送其代幣。function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { return _operatorApprovals[owner][operator]; }
它查找 _operatorApprovals 私有變數,一個映射映射。
// Mapping from owner to operator approvals mapping(address => mapping(address => bool)) private _operatorApprovals;
它由**setApprovalForAll()**函式通過 _setApprovalForAll() 內部函式更新:
function setApprovalForAll(address operator, bool approved) public virtual override { _setApprovalForAll(_msgSender(), operator, approved); }
要恢復,要使第三個條件為真,所有者需要呼叫 setApprovalForAll() 函式來提前給予 msg.sender 批准。
如果這三個條件中的任何一個為真,則 transferFrom() 函式呼叫 _transfer() 內部函式,並執行傳輸,如上一節所述。
// To set as approved function _setApprovalForAll( address owner, address operator, bool approved ) internal virtual { require(owner != operator, "ERC721: approve to caller"); _operatorApprovals[owner][operator] = approved; emit ApprovalForAll(owner, operator, approved); }