What I am trying to achieve is calling a transferFrom from ERC20 contract inside an ERC721 contract like this:
My ERC20 contract:
pragma solidity ^0.7.0;
import "../openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import "../openzeppelin-contracts/contracts/math/SafeMath.sol";
contract ERC20Token is IERC20 {
using SafeMath for uint256;
bytes32[] public candidateList;
uint public totalTokens;
uint public balanceTokens;
uint public tokenPrice;
// what is the voter address?
// total tokens purchased
// tokens voted per candidate
struct voter {
address voterAddress;
uint tokensBought;
uint256[] tokensUsedPerCandidate;
}
mapping(address => voter) public voterInfo;
mapping(bytes32 => uint256) public votesReceived;
string public symbol;
string public name;
uint8 public decimals;
mapping(address => uint256) balances;
mapping(address => mapping(address => uint256)) allowed;
constructor(uint256 _totalTokens, uint256 _tokenPrice, bytes32[] memory _candidateNames) {
symbol = "NCToken";
name = "NCSOFT TOKEN";
decimals = 0;
totalTokens = _totalTokens;
balanceTokens = _totalTokens;
tokenPrice = _tokenPrice;
candidateList = _candidateNames;
emit Transfer(address(0), msg.sender, totalTokens);
function transferFrom(address from, address to, uint256 tokens) public override returns (bool) { //This is the function I am trying to call from ERC721 contract
balances[from] = SafeMath.sub(balances[from], tokens);
allowed[from][msg.sender] = SafeMath.sub(allowed[from][msg.sender], tokens);
balances[to] = SafeMath.add(balances[to], tokens);
emit Transfer(from, to, tokens);
return true;
}
}
My ERC721 contract:
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "../openzeppelin-contracts/contracts/token/ERC721/IERC721.sol";
import "../openzeppelin-contracts/contracts/token/ERC721/ERC721.sol";
import "../openzeppelin-contracts/contracts/token/ERC721/IERC721Receiver.sol";
import "../openzeppelin-contracts/contracts/math/SafeMath.sol";
import "../openzeppelin-contracts/contracts/utils/Address.sol";
import "../openzeppelin-contracts/contracts/utils/Counters.sol";
import "./ERC20Token.sol";
contract NFTtoken is ERC721 {
using SafeMath for uint256;
using Address for address;
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
bytes32[] candidates = [bytes32('Rama'), bytes32('Nick'), bytes32('Jose')];
ERC20Token ERC20TokenContract = new ERC20Token(1000, 1, candidates); //instantiating an ERC20 contract
address payable public owner;
mapping(bytes4 => bool) supportedInterfaces;
mapping(uint256 => address) tokenOwners; //a mapping from NFT ID to the address that owns it
mapping(address => uint256) balances; //a mapping from NFT ID to the address that owns it
mapping(uint256 => address) allowance; //a mapping from NFT ID to approved address
mapping(address => mapping(address => bool)) operators; //Mapping from owner address to mapping of operator addresses.
// mapping (uint256 => string) idToUri;
uint8 public decimals;
uint256[] public allValidTokenIds;
mapping(uint256 => uint256) private allValidTokenIndex;
string[] public allNFTNames;
struct NFT {
//uint NFTID;
string name;
address creator;
}
mapping(address => NFT) public nftInfo;
constructor() ERC721("NC NFT example", "NCNFT") {
owner = msg.sender;
decimals = 0;
}
function mint(string calldata nftName) external payable {
uint256 newItemId = _tokenIds.current();
_mint(msg.sender, newItemId);
nftInfo[msg.sender].name = nftName;
nftInfo[msg.sender].creator = msg.sender;
allValidTokenIndex[newItemId] = allValidTokenIds.length;
allValidTokenIds.push(newItemId);
_tokenIds.increment();
}
function transferNFT(address from, address to, uint256 tokenId) public returns (bool){
transferFrom(from, to, tokenId);
ERC20TokenContract.transferFrom(to, nftInfo[from].creator, 10);
//<-----***********This is throwing an error! I am trying to call ERC20Token.transferFrom.
}
function allNFTs() public view returns (uint256[] memory) {
return allValidTokenIds;
}
}
Error Message when transferNFT from ERC721 is called.
MetaMask - RPC Error: [ethjs-query] while formatting outputs from RPC '{"value":{"code":-32603,"data":{"message":"VM Exception while processing transaction: revert ERC721: operator query for nonexistent token","code":-32000,"data":{"0x0b5d04087c39a8caa2f730815e42f619d33c9d0c3b8682c8c01d3f1ecf0e7d0f":{"error":"revert","program_counter":7889,"return":"0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002c4552433732313a206f70657261746f7220717565727920666f72206e6f6e6578697374656e7420746f6b656e0000000000000000000000000000000000000000","reason":"ERC721: operator query for nonexistent token"},"stack":"RuntimeError: VM Exception while processing transaction: revert ERC721: operator query for nonexistent token\n at Function.RuntimeError.fromResults (C:\\Program Files\\WindowsApps\\GanacheUI_2.5.4.0_x64__5dg5pnz03psnj\\app\\resources\\static\\node\\node_modules\\ganache-core\\lib\\utils\\runtimeerror.js:94:13)\n at BlockchainDouble.processBlock (C:\\Program Files\\WindowsApps\\GanacheUI_2.5.4.0_x64__5dg5pnz03psnj\\app\\resources\\static\\node\\node_modules\\ganache-core\\lib\\blockchain_double.js:627:24)\n at runMicrotasks (<anonymous>)\n at processTicksAndRejections (internal/process/task_queues.js:93:5)","name":"RuntimeError"}}}}'
{code: -32603, message: `[ethjs-query] while formatting outputs from RPC '{…/task_queues.js:93:5)","name":"RuntimeError"}}}}'`}
code: -32603
message: "[ethjs-query] while formatting outputs from RPC '{\"value\":{\"code\":-32603,\"data\":{\"message\":\"VM Exception while processing transaction: revert ERC721: operator query for nonexistent token\",\"code\":-32000,\"data\":{\"0x0b5d04087c39a8caa2f730815e42f619d33c9d0c3b8682c8c01d3f1ecf0e7d0f\":{\"error\":\"revert\",\"program_counter\":7889,\"return\":\"0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002c4552433732313a206f70657261746f7220717565727920666f72206e6f6e6578697374656e7420746f6b656e0000000000000000000000000000000000000000\",\"reason\":\"ERC721: operator query for nonexistent token\"},\"stack\":\"RuntimeError: VM Exception while processing transaction: revert ERC721: operator query for nonexistent token\\n at Function.RuntimeError.fromResults (C:\\\\Program Files\\\\WindowsApps\\\\GanacheUI_2.5.4.0_x64__5dg5pnz03psnj\\\\app\\\\resources\\\\static\\\\node\\\\node_modules\\\\ganache-core\\\\lib\\\\utils\\\\runtimeerror.js:94:13)\\n at BlockchainDouble.processBlock (C:\\\\Program Files\\\\WindowsApps\\\\GanacheUI_2.5.4.0_x64__5dg5pnz03psnj\\\\app\\\\resources\\\\static\\\\node\\\\node_modules\\\\ganache-core\\\\lib\\\\blockchain_double.js:627:24)\\n at runMicrotasks (<anonymous>)\\n at processTicksAndRejections (internal/process/task_queues.js:93:5)\",\"name\":\"RuntimeError\"}}}}'"
[[Prototype]]: Object
localhost/:1 Uncaught (in promise)
{code: -32603, message: `[ethjs-query] while formatting outputs from RPC '{…/task_queues.js:93:5)","name":"RuntimeError"}}}}'`, stack: '{\n "code": -32603,\n "message": "[ethjs-query] wh…gaeaoehlefnkodbefgpgknn/background-0.js:1:216902)'}
code: -32603
message: "[ethjs-query] while formatting outputs from RPC '{\"value\":{\"code\":-32603,\"data\":{\"message\":\"VM Exception while processing transaction: revert ERC721: operator query for nonexistent token\",\"code\":-32000,\"data\":{\"0x0b5d04087c39a8caa2f730815e42f619d33c9d0c3b8682c8c01d3f1ecf0e7d0f\":{\"error\":\"revert\",\"program_counter\":7889,\"return\":\"0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002c4552433732313a206f70657261746f7220717565727920666f72206e6f6e6578697374656e7420746f6b656e0000000000000000000000000000000000000000\",\"reason\":\"ERC721: operator query for nonexistent token\"},\"stack\":\"RuntimeError: VM Exception while processing transaction: revert ERC721: operator query for nonexistent token\\n at Function.RuntimeError.fromResults (C:\\\\Program Files\\\\WindowsApps\\\\GanacheUI_2.5.4.0_x64__5dg5pnz03psnj\\\\app\\\\resources\\\\static\\\\node\\\\node_modules\\\\ganache-core\\\\lib\\\\utils\\\\runtimeerror.js:94:13)\\n at BlockchainDouble.processBlock (C:\\\\Program Files\\\\WindowsApps\\\\GanacheUI_2.5.4.0_x64__5dg5pnz03psnj\\\\app\\\\resources\\\\static\\\\node\\\\node_modules\\\\ganache-core\\\\lib\\\\blockchain_double.js:627:24)\\n at runMicrotasks (<anonymous>)\\n at processTicksAndRejections (internal/process/task_queues.js:93:5)\",\"name\":\"RuntimeError\"}}}}'"
stack: "{\n \"code\": -32603,\n \"message\": \"[ethjs-query] while formatting outputs from RPC '{\\\"value\\\":{\\\"code\\\":-32603,\\\"data\\\":{\\\"message\\\":\\\"VM Exception while processing transaction: revert ERC721: operator query for nonexistent token\\\",\\\"code\\\":-32000,\\\"data\\\":{\\\"0x0b5d04087c39a8caa2f730815e42f619d33c9d0c3b8682c8c01d3f1ecf0e7d0f\\\":{\\\"error\\\":\\\"revert\\\",\\\"program_counter\\\":7889,\\\"return\\\":\\\"0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002c4552433732313a206f70657261746f7220717565727920666f72206e6f6e6578697374656e7420746f6b656e0000000000000000000000000000000000000000\\\",\\\"reason\\\":\\\"ERC721: operator query for nonexistent token\\\"},\\\"stack\\\":\\\"RuntimeError: VM Exception while processing transaction: revert ERC721: operator query for nonexistent token\\\\n at Function.RuntimeError.fromResults (C:\\\\\\\\Program Files\\\\\\\\WindowsApps\\\\\\\\GanacheUI_2.5.4.0_x64__5dg5pnz03psnj\\\\\\\\app\\\\\\\\resources\\\\\\\\static\\\\\\\\node\\\\\\\\node_modules\\\\\\\\ganache-core\\\\\\\\lib\\\\\\\\utils\\\\\\\\runtimeerror.js:94:13)\\\\n at BlockchainDouble.processBlock (C:\\\\\\\\Program Files\\\\\\\\WindowsApps\\\\\\\\GanacheUI_2.5.4.0_x64__5dg5pnz03psnj\\\\\\\\app\\\\\\\\resources\\\\\\\\static\\\\\\\\node\\\\\\\\node_modules\\\\\\\\ganache-core\\\\\\\\lib\\\\\\\\blockchain_double.js:627:24)\\\\n at runMicrotasks (<anonymous>)\\\\n at processTicksAndRejections (internal/process/task_queues.js:93:5)\\\",\\\"name\\\":\\\"RuntimeError\\\"}}}}'\",\n \"stack\": \"Error: [ethjs-query] while formatting outputs from RPC '{\\\"value\\\":{\\\"code\\\":-32603,\\\"data\\\":{\\\"message\\\":\\\"VM Exception while processing transaction: revert ERC721: operator query for nonexistent token\\\",\\\"code\\\":-32000,\\\"data\\\":{\\\"0x0b5d04087c39a8caa2f730815e42f619d33c9d0c3b8682c8c01d3f1ecf0e7d0f\\\":{\\\"error\\\":\\\"revert\\\",\\\"program_counter\\\":7889,\\\"return\\\":\\\"0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002c4552433732313a206f70657261746f7220717565727920666f72206e6f6e6578697374656e7420746f6b656e0000000000000000000000000000000000000000\\\",\\\"reason\\\":\\\"ERC721: operator query for nonexistent token\\\"},\\\"stack\\\":\\\"RuntimeError: VM Exception while processing transaction: revert ERC721: operator query for nonexistent token\\\\n at Function.RuntimeError.fromResults (C:\\\\\\\\Program Files\\\\\\\\WindowsApps\\\\\\\\GanacheUI_2.5.4.0_x64__5dg5pnz03psnj\\\\\\\\app\\\\\\\\resources\\\\\\\\static\\\\\\\\node\\\\\\\\node_modules\\\\\\\\ganache-core\\\\\\\\lib\\\\\\\\utils\\\\\\\\runtimeerror.js:94:13)\\\\n at BlockchainDouble.processBlock (C:\\\\\\\\Program Files\\\\\\\\WindowsApps\\\\\\\\GanacheUI_2.5.4.0_x64__5dg5pnz03psnj\\\\\\\\app\\\\\\\\resources\\\\\\\\static\\\\\\\\node\\\\\\\\node_modules\\\\\\\\ganache-core\\\\\\\\lib\\\\\\\\blockchain_double.js:627:24)\\\\n at runMicrotasks (<anonymous>)\\\\n at processTicksAndRejections (internal/process/task_queues.js:93:5)\\\",\\\"name\\\":\\\"RuntimeError\\\"}}}}'\\n at new i (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-0.js:18:148782)\\n at s (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-0.js:18:146325)\\n at Object.internal (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-0.js:18:146935)\\n at y.<anonymous> (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-0.js:1:210928)\\n at Object.h (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-0.js:18:35204)\\n at u (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-0.js:1:117610)\\n at y.a.emit (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-0.js:1:118146)\\n at y._setTransactionStatus (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-1.js:1:46740)\\n at y.setTxStatusFailed (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-1.js:1:45972)\\n at B._failTransaction (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-0.js:1:225990)\\n at B.approveTransaction (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-0.js:1:217659)\\n at async B.updateAndApproveTransaction (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-0.js:1:216902)\"\n}\n at new i (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-0.js:18:148782)\n at s (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-0.js:18:146325)\n at Object.internal (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-0.js:18:146935)\n at y.<anonymous> (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-0.js:1:210928)\n at Object.h (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-0.js:18:35204)\n at u (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-0.js:1:117610)\n at y.a.emit (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-0.js:1:118146)\n at y._setTransactionStatus (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-1.js:1:46740)\n at y.setTxStatusFailed (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-1.js:1:45972)\n at B._failTransaction (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-0.js:1:225990)\n at B.approveTransaction (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-0.js:1:217659)\n at async B.updateAndApproveTransaction (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-0.js:1:216902)"
[[Prototype]]: Object
setTimeout (async)
(anonymous) @ inpage.js:1
write @ inpage.js:1
This is my javascript file calling the functions from both contracts.
// Import libraries we need.
import { default as Web3} from 'web3';
import { default as contract } from 'truffle-contract'
import voting_artifacts from '../../build/contracts/Voting.json'
import voting_artifacts2 from '../../build/contracts/DeedToken.json'
window.App = {
start: function() {
var self = this;
self.transferNFT();
},
transferNFT: function() {
NFTContract.deployed().then(function(contractInstance) {
let toAddress = $("#to-address").val();
let NFTid_temp = $("#nft-id").val();
let NFTid = NFTid_temp.substring(7);
contractInstance.transferFrom(web3.currentProvider.selectedAddress, toAddress, NFTid, {gas: 140000, from: web3.eth.accounts[0]});
})
}
}
window.addEventListener('load', async function() {
if (window.ethereum) {
await window.ethereum.send('eth_requestAccounts');
window.web3 = new Web3(window.ethereum);
}
else {
console.warn("No web3 detected.");
window.web3 = new Web3(new Web3.providers.HttpProvider("http://127.0.0.1:8545"));
}
App.start();
});