Как перевести токен из другого контракта

#ethereum #solidity #smartcontracts #openzeppelin

Вопрос:

У меня есть два контракта, которые развернуты отдельно.

Первый контракт.сол

 contract FirstContract is ERC721 {  using Counters for Counters.Counter;  Counters.Counter public _id;   constructor(address admin) ERC721("Token Name", "TOKEN") {    }   function incrementToken() public {  _id.increment();  }   function currentToken() public view returns (uint256) {  return _id.current();  }   function mint(address to, uint256 tokenId) public {  _mint(to, tokenId);  } }  

Второй контракт.сол

 import "./FirstContract.sol";  contract SecondContract {  FirstContract firstContract;   constructor(address _address) {  firstContract = FirstContract(_address);  }   // Mint a token to msg.sender  function createToken() external {  firstContract.incrementToken();  uint256 newTokenId = firstContract.currentToken();  firstContract.mint(msg.sender, newTokenId);   }    // Transfer the ownership of the token  function transferToken(from address, address to, uint256 tokenId) external {   // Error here. transferFrom is the method inherited from ERC721  firstContract.transferFrom(from, to, tokenId);   } }  

После чеканки токена с использованием createToken in SecondContract , когда я звоню transferToken , я получаю следующую ошибку:

ERC721: вызывающий абонент передачи не является владельцем и не утвержден

Это, скорее всего, связано с тем, что SecondContract msg.sender при вызове transferFrom while tx.origin является фактическим владельцем токена. Я попытался одобрить SecondContract как одноразовый оператор передачу токена approve(address(this), tokenId) , но все равно получил ту же ошибку. Я тоже пробовал approve(address(firstContract), tokenId) или setApproveForAll(address(firstContract), true) , но результат тот же.

The only way to get this work is if I use _transfer in FirstContract :

 function transferByAnybody(address from, address to, uint256 tokenId) public {  _transfer(from, to, tokenId); }  

и вызов этого метода из SecondContract :

 function transferToken(from address, address to, uint256 tokenId) external {  firstContract.transferByAnybody(from, to, tokenId);  }  

что далеко не идеально, потому что любой может вызвать метод передачи, независимо от того, являетесь ли вы владельцем токена или нет.