Transactions

NFT 轉賬不一致?

  • November 7, 2022

我對區塊鏈相當陌生。我對ERC-721NFT 的理解是它應該在地址之間以原子方式傳遞。

特別是,如果我跟踪 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變數是令牌 IDaddress.

// 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);
}

引用自:https://ethereum.stackexchange.com/questions/138936