you need to write the createPenguin function
Is it not the one that is in my solidity file ?
i repplied in the dm
Solved using Promise ‘then… catch’
$('#create-btn').click(() => {
showMessage('');
const newDna = getDna();
console.log('newDna', newDna);
instance.methods
.createKittyGen0(newDna)
.send({})
.then((result) => {
showMessage('Kitty created successfully');
console.log('txhash', result.transactionHash);
})
.catch((error) => {
console.error(error);
});
});
Found at https://web3js.readthedocs.io/en/v1.2.7/web3-eth-contract.html#id37
Solved.
Since window.ethereum.enable() is deprecated I used an alternative via window.ethereum.request() as mentioned here
index.js
var web3 = new Web3(Web3.givenProvider); // any provider where Metamask is set to
var instance;
var user;
var contractAddress = "0x8Cea2c1DB2c1ec1c1E1180f53f477c37922232a8";
/* Deprecated code (19apr22) as in video:
=> https://ethereum.stackexchange.com/questions/92095/web3-current-best-practice-to-connect-metamask-to-chrome
$(document).ready(function(){
window.ethereum.enable().then(function(accounts){
user = accounts[0];
instance = new web3.eth.Contract(abi, contractAddress, {from: user});
console.log(instance);
})
})
*/
$(document).ready( async function(){
if (window.ethereum){
try {
const accounts = await window.ethereum.request({method: 'eth_requestAccounts'});
console.log('accounts: ', accounts);
user = accounts[0];
instance = new web3.eth.Contract(abi, contractAddress, {from: user});
console.log('instance: ', instance);
// listener for Kitty births..
instance.events.Birth({}, (error, event) => {
if (error) {
var msg = 'Kitty birth error: ' + error;
console.log(msg);
alert(msg);
} else {
console.log('Kitty birth event: ', event);
var birthTime = parseInt(event.returnValues.birthTime);
var birthTimeDT = 'unknown';
if (birthTime != NaN) {
var birthTimeDate = new Date( birthTime * 1000);
var birthTimeDT = birthTimeDate.toGMTString()+" = "+birthTimeDate.toLocaleString();
}
var msg = "A new kitty has been born!"
+ "\n At: " + birthTimeDT
+ "\n Owner: " + event.returnValues.owner
+ "\n Mum Id: " + event.returnValues.mumId
+ "\n Dad Id: " + event.returnValues.dadId
+ "\n Genes: " + event.returnValues.genes
+ "\n Generation: " + event.returnValues.generation
+ "\n Kitten Id: " + event.returnValues.kittenId;
$('#newKittenDetails').html("<pre>" + msg + "</pre>");
}
});
} catch(error){
if (error.code === 4001){
console.log('User rejected ethereum accounts request');
}
}
} else {
console.log('window.ethereum not available');
}
});
$('#newKitty').click(() => {
console.log('new Kitty instance: ', instance);
if (instance) {
var dnaStr = getDna();
console.log('newKitty dnaStr = ' + dnaStr);
instance.methods.createKittenGen0(dnaStr).send({}, function(error, txHash){
if (error) {
var msg = 'Create new gen0 Kitty error:' + error;
console.log(msg);
alert(msg);
} else {
console.log('Kitten created! txHash=' + txHash);
}
});
} else {
console.log('New Kitty error: instance not available!');
}
});
In index.html , i added this code below the 3 buttons:
<p><hr></p>
<p><span id="newKittenDetails"></span></p>
abi.js:
abi = [
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "approved",
"type": "address"
},
{
"indexed": true,
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "Approval",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "kittenId",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "mumId",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "dadId",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "genes",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "generation",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "birthTime",
"type": "uint256"
}
],
"name": "Birth",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "from",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "to",
"type": "address"
},
{
"indexed": true,
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "Transfer",
"type": "event"
},
{
"constant": true,
"inputs": [],
"name": "CREATE_LIMIT_GEN0",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "Name",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "Symbol",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "gen0Counter",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "kittyIndexToOwner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"internalType": "uint256",
"name": "_genes",
"type": "uint256"
}
],
"name": "createKittenGen0",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"internalType": "uint256",
"name": "_id",
"type": "uint256"
}
],
"name": "getKitty",
"outputs": [
{
"internalType": "uint256",
"name": "genes",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "birthTime",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "mumId",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "dadId",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "generation",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"internalType": "address",
"name": "_owner",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "totalSupply",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "name",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "symbol",
"outputs": [
{
"internalType": "string",
"name": "tokenSymbol",
"type": "string"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"internalType": "uint256",
"name": "_tokenId",
"type": "uint256"
}
],
"name": "ownerOf",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"internalType": "address",
"name": "_to",
"type": "address"
},
{
"internalType": "uint256",
"name": "_tokenId",
"type": "uint256"
}
],
"name": "transfer",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
}
];
The Kittycontract.sol:
I have extended the Birth event with the generation and birthDate.
// SPDX-License-Identifier: MIT
pragma solidity ^0.5.12;
import "./IERC721.sol";
import "./Ownable.sol";
contract Kittycontract is IERC721, Ownable {
string public constant Name = "DemoKitties";
string public constant Symbol = "DK";
uint256 public constant CREATE_LIMIT_GEN0 = 10;
event Birth(address owner, uint256 kittenId, uint256 mumId, uint256 dadId, uint256 genes, uint256 generation, uint256 birthTime);
struct Kitty {
uint256 genes;
uint64 birthTime;
uint32 mumId;
uint32 dadId;
uint16 generation;
}
Kitty[] private allKitties; // index => kitty id (token id)
mapping (address => uint256) ownerTokenBalance; // get uint256 amount (token kitty count) of owner address
mapping (uint256 => address) public kittyIndexToOwner; // get owner address of uint256 kitty id (token id)
uint256 public gen0Counter;
function createKittenGen0(uint256 _genes) public onlyOwner {
require(gen0Counter < CREATE_LIMIT_GEN0, "Max number of Generation0 kittens reached");
gen0Counter++;
_createKitty(0, 0, 0, _genes, msg.sender); // no parents, owned by the contract
}
function _createKitty(
uint256 _mumId, uint256 _dadId,
uint256 _generation, uint256 _genes,
address _owner
) private returns (uint256) { // cat Id
uint64 _now = uint64(now);
Kitty memory _kitty = Kitty({
genes: _genes, birthTime: _now,
mumId: uint32(_mumId), dadId: uint32(_dadId),
generation: uint16(_generation)
});
uint256 newKittenId = allKitties.push(_kitty) -1; // zero based Id
emit Birth(_owner, newKittenId, _mumId, _dadId, _genes, _generation, uint256(_now));
_transfer(address(0), _owner, newKittenId); // address(0): birth of new kitten to owner
return newKittenId;
}
function getKitty(uint256 _id) external view returns(
uint256 genes, uint256 birthTime,
uint256 mumId, uint256 dadId,
uint256 generation
) {
Kitty storage kitty = allKitties[_id]; // storage is a pointer to the original mapping, memory creates a local copy
genes = kitty.genes;
birthTime = uint256(kitty.birthTime);
mumId = uint256(kitty.mumId);
dadId = uint256(kitty.dadId);
generation = uint256(kitty.generation);
}
// ---
function balanceOf(address _owner) external view returns (uint256) {
return ownerTokenBalance[_owner];
}
function totalSupply() public view returns (uint256) {
return allKitties.length;
}
function name() public view returns (string memory) {
return Name;
}
function symbol() public view returns (string memory tokenSymbol) {
return Symbol;
}
function ownerOf(uint256 _tokenId) external view returns (address) {
address owner = kittyIndexToOwner[_tokenId];
require(owner != address(0), "No owner of not existing address");
return owner;
}
function transfer(address _to, uint256 _tokenId) external {
require(_to != address(0), "TO address must be defined.");
require(_to != address(this), "Cannot transfer to the contract itself");
require(_to != msg.sender, "Cannot send to yourselves");
require(owns(msg.sender, _tokenId), "Cannot send token you not own");
_transfer(msg.sender, _to, _tokenId);
}
function _transfer(address _from, address _to, uint256 _tokenId) internal {
ownerTokenBalance[_to]++;
if (_from != address(0)) {
ownerTokenBalance[_from]--;
}
kittyIndexToOwner[_tokenId] = _to;
emit Transfer(_from, _to, _tokenId);
}
function owns(address claimant, uint256 tokenId) internal view returns (bool) {
return kittyIndexToOwner[tokenId] == claimant;
}
}
Hi,
it wont give me prompt from MetaMask, when I reload the page, the console shows me this:
This is my code in index.js
var web3 = new Web3(Web3.givenProvider);
var instance;
var user;
var contractAddres = "0x9fbB81F918Fb630CF7F46abcE10F13Fb2F5A72b4";
$(document).ready(function(){
window.ethereum.enable().then(function(accounts){
instance = new web3.eth.Contract(abi, contractAddres, {from: accounts[0]});
user = accounts[0];
console.log(instance);
})
})
I don’t run this with python but with this:
the error is you abi in your abi.js file. it has a mssing comma or bracket or something you can come to this conclusion by reading the error message. can u paste in your abi in here
Re: Metamask and Web3 set up.
I am getting this error when refreshing (plus, console.log(instance) is not logging anything)
hey @DaveRad ! Can you send a screen shoot of the code? Where you call the library and also when start using it.
Hi @Kenn.eth !
Re: lesson ‘Web3.js Start Coding’ at appx 9:20 min:
(I was mistaken about the ‘Metamask and Web3 set up’ lesson in my above post)
When I refresh the page, I do receive a prompt from Metamask (pop up) I receive this message:
Then, when click ‘connect’ (on Metamask), I get the following error (appears under the above error and no console log):
Here is a screen capture of my index.js:
Also, initially, I could not get a prompt for Metamask with ‘the web3.min.js’ file. I then read about the 'legacy" plug in so I used the ‘metamask.web3.min.js’ file (I put it in the same folder). Then the prompt worked.
Here is a screen shot of the index.html file where I implemented it:
In the above screenshot, I had left the script src for the web3.min.js in, however, I had tried it with the script src = web3.min.js removed and, just used the metamask.web3.min.js. Both ways work (with or without web3.min.js) Thus, I am not sure if it is still needed.
Try to add async
to the anonimous function after $(document).ready(async funtion() { ...
Also at window.ethereum.enable()
the function at then
should also be async
.
Carlos Z
hmm…so, I am getting the same error messages.
I tied adding an await as well but, that never worked either (same errors).
Maybe I am not implementing the await properly (if needed)
$(document).ready(async function(){
window.ethereum.enable().then(async function(accounts){
instance = await new web3.eth.Contract(abi, contractAddress, {from: accounts[0]});
user = accounts[0];
console.log(instance);
});
you might need to remove one of the 2 web3 library, or metamask.web3.min
or web3.min
, just use one, probably the web3.min
is quite old and stopped to work, not sure, but if the metamask
library is working, use that one instead.
Carlos Z
So, tired removing each one and only the metamask.web3.min.js works.
Getting rid of the web3.min.js solved the refresh error message (i.e. no error message on the refresh).
However, I still get the error message when I click ‘connect’ on Metamask with nothing console logging.
I might have to check that metamask.web3.min
file.
Lets try to use the CDN for web3.min.js
instead those 2, in your index.html
file just add
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/web3/1.2.7-rc.0/web3.min.js"></script>
Remember to remove both web3 library and just use this one, hopefully should work, if not, could you be able to provide a github repo for this project? that way i can replicate the issue by downloading your project.
This is the link from where i took that CDN : https://www.cdnpkg.com/web3/file/web3.min.js/
Carlos Z
Awesome, that worked!
Thanks for the link!
I just looked up CDN. I guess I could alternatively install it as a dependency?
Anyway, Thank you very much for the help!
Dave
Glad to know that it works
Alternatively, you can download one of the versions (suggest to always use the last version published) and save it as your new web3.min.js
, using CDN or your own file are practically the same, just that in case the CDN does not work, it might be nice to have your own library, thats why you can also save the file.
Carlos Z
I see. Good to know.
Thank you!
Dave