Assignment - Event

@kenn.eth

Hi, thanks for the reply. Here’s my GitHub repository: https://github.com/EmmerichS/HelloKitties

I’ll try using the cookie system to remember who logged in. If I get stuck I’ll come back to you.

Take care
Em

What’s the best way to detect if the user is connected via Metamask (after the page has loaded)? The idea is that I want certain elements (such as login button) to become invisible if the user is already connected.

1 Like

Check out ethereum.isConnected(). Maybe that’ll help.

https://docs.metamask.io/guide/ethereum-provider.html#properties

@mcgrane5

So I’m a little stuck. I’ve managed to retireve the account that is currently connected to the app with this code snippet:

`function getAccount() {

ethereum.request({ method: 'eth_accounts' }).then(function(accounts) {
    let account = accounts[0];
    console.log(account);
});

}`

This prints out the current account in the console. But what I can’t figure out is how to retrieve the last account connected to the app so that I can then make the comparison. Do you kow how to do this?

1 Like

@kenn.eth reccommened using cookies above i never thought of this approach but i would use local storage myself. So what i would do is to use local storage to set the current account each time someone new uses the app that way that account will always be availabe for fecthing so you can query from local storage and if the accounts are the same then connect to web3 and if not prompt the user to clock the button. Ill tell you what do you want to share your github repo and if you cant get Local storage to work ill go in and do it for you. You should try yourself tho. Ill five a snippet of how to set and get data from local storage

function setCurrentUser() {
    
    currentLoggedInUserObject = { 'user': account.toString()};
    localStorage.setItem('currentLoggedInUserObject', JSON.stringify(currentLoggedInUserObject));
    retrieveCurrentLoggedInUser = localStorage.getItem('currentLoggedInUserObject');
    currentSelectedWallet = JSON.parse(retrieveCurrentLoggedInUser).user

   console.log(currentSelectedWallet)
}

The use this in combination with an if. If the current and last are the same load web3 as normal else require the button click. It might need a bit more fiddling than that but if you cnt get it as i said just link me your github and ill get it running for you

The thing here is using vanilla.js like this is very tideous for something liek this because you need to refresh the page for changes to take place. if you were using react you could have it such that each time you change account directly from metamask the it updates some state and you account would update live on the UI without the need for a refresh

hey @Emmerich ! I just run your code and is workig good remembering the connected account.
When account is not connected will trigger this connect msg.
If you have a solution that have some issues, please send a picture here and will take a look.

hey @Emmerich. very sorry its only that i happened by cance to go back to this forum today i noticed that you actually did post your github link sorry i never noticed when writing my last post. So i fixed your code and it now allows the user to connect. If a user goes into metamask and changes their account the webpage live updates and inits web 3 for the newly changed account. I have a video below showing you the changes in effect. I will write you a post now explaining what i dod so you can copy over. its not that much but i did change to async await rather than jquery

Link to demo vid of new chnages
https://youtu.be/3_itpuUquHc

screenshots

var web3js = new Web3(Web3.givenProvider);

var instance;
var account;

var contractAddress = "0x47DB3F044fF100b6d0BA019192F3ccAfe2412541";

so the first few lines are the same. Howeevr we are going to use local storgae to remember what the last account was that was using the app.


const btn = document.getElementById("connect");
btn.onclick = connect;

ethereum.on('accountsChanged', function (accounts) {
    connect();
})

function loadBlockchainData() {

    loadWeb3();

}

async function loadWeb3() {
    if (window.ethereum) {
      window.web3 = new Web3(window.ethereum)
      await window.ethereum.enable()
    }
    else if (window.web3) {
      window.web3 = new Web3(window.web3.currentProvider)
    }
    else {
      window.alert('Non-Ethereum browser detected. You should consider trying MetaMask!')
    }

    const accounts = await web3.eth.getAccounts();
    account = accounts[0];
    console.log(account)

    currentLoggedInUserObject = { 'user': account.toString()};
    localStorage.setItem('currentLoggedInUserObject', JSON.stringify(currentLoggedInUserObject));
    retrieveCurrentLoggedInUser = localStorage.getItem('currentLoggedInUserObject');
    currentSelectedWallet = JSON.parse(retrieveCurrentLoggedInUser).user
    console.log(currentSelectedWallet)

    console.log("accounts are ", account, currentSelectedWallet)
    if (account.toLowerCase() == currentSelectedWallet.toLowerCase()) {

        connect();
    } 
}

I then listen to an ethereum event which detects whever the account in metamask was changed. On this event i call the connect function which ill explain below. which uses local storage to check the befor and after accountsThe other option of calling this connect function is whenever the user clicks on the connect button. Below this i call a function called lodWeb3 which juts connects to eth with metamask. Once the connection is made i get the accounts. I check if the current account is equal to the last logged in account and if it is connect if not do nothing, prompting the user to manually click the connect button themselves.

function connect() {

    window.ethereum.enable().then(function(accounts) {

        //Creating an instance of the contract
        instance = new web3js.eth.Contract(abi, contractAddress, {from: accounts[0]})

        user = accounts[0];
        btn.innerHTML = user.slice(0, 10) + "..";

        console.log(instance)
        currentLoggedInUserObject = { 'user': user.toString()};
        localStorage.setItem('currentLoggedInUserObject', JSON.stringify(currentLoggedInUserObject));
        console.log("hellooooo", currentLoggedInUserObject)

        instance.events.Birth()
        .on('data', function(event) {

            //Here I console the DNA (genes), but only get a partial value.
            console.log(event.returnValues.genes); 

            alert("Congratulations Em!!! Your cat has been created! And here are all the stats:" + 
            JSON.stringify(event.returnValues, null, 4));

            console.log(event.returnValues);
        })
        .on('error', function(error) {
            console.log(error);
        })


    })

    return true;
}

loadBlockchainData();

the last function is the actual connect function.Here we create a new instance of the contract using the current loggied in account. I then update the last logged in user to the current account so that we can effectively do the check whenever the page is refreshed or the account changed. Then i just change the html value of your button to the the current logged in account.

Lastly i call loadBlockchainData() which in turn calls loadWeb3(). Ths is effectivley your “main()”. As for your other files i dodnt chsnge much i just linked index.js in the catalogue, home and other html pages and i changed thr button tag to have an ID called connect so that we can call button.onclick to execute the connect function

Entire index,js

var web3js = new Web3(Web3.givenProvider);

var instance;
var account;
var user
var contractAddress = "0x47DB3F044fF100b6d0BA019192F3ccAfe2412541";


const btn = document.getElementById("connect");
btn.onclick = connect;

ethereum.on('accountsChanged', function (accounts) {
    connect();
})

function loadBlockchainData() {

    loadWeb3();

}

async function loadWeb3() {
    if (window.ethereum) {
      window.web3 = new Web3(window.ethereum)
      await window.ethereum.enable()
    }
    else if (window.web3) {
      window.web3 = new Web3(window.web3.currentProvider)
    }
    else {
      window.alert('Non-Ethereum browser detected. You should consider trying MetaMask!')
    }

    const accounts = await web3.eth.getAccounts();
    account = accounts[0];
    console.log(account)

    currentLoggedInUserObject = { 'user': account.toString()};
    localStorage.setItem('currentLoggedInUserObject', JSON.stringify(currentLoggedInUserObject));
    retrieveCurrentLoggedInUser = localStorage.getItem('currentLoggedInUserObject');
    currentSelectedWallet = JSON.parse(retrieveCurrentLoggedInUser).user
    console.log(currentSelectedWallet)

    console.log("accounts are ", account, currentSelectedWallet)
    if (account.toLowerCase() == currentSelectedWallet.toLowerCase()) {

        connect();
    } 
}

function connect() {

    window.ethereum.enable().then(function(accounts) {

        //Creating an instance of the contract
        instance = new web3js.eth.Contract(abi, contractAddress, {from: accounts[0]})

        user = accounts[0];
        btn.innerHTML = user.slice(0, 10) + "..";

        console.log(instance)
        currentLoggedInUserObject = { 'user': user.toString()};
        localStorage.setItem('currentLoggedInUserObject', JSON.stringify(currentLoggedInUserObject));
        console.log("hellooooo", currentLoggedInUserObject)

        instance.events.Birth()
        .on('data', function(event) {

            //Here I console the DNA (genes), but only get a partial value.
            console.log(event.returnValues.genes); 

            alert("Congratulations Em!!! Your cat has been created! And here are all the stats:" + 
            JSON.stringify(event.returnValues, null, 4));

            console.log(event.returnValues);
        })
        .on('error', function(error) {
            console.log(error);
        })


    })

    return true;
}

loadBlockchainData();



// loadWeb3();
1 Like

@mcgrane5

Dear Evan, first off, thanks for taking the time and effort to help me out. Your tip with localStorage is what eventually helped me figure out the problem. Second off, I’ve looked at your code and honestly, I find it incredibly complicated. In the end all I had to do was save the Metamask address in localStorage and later retrieve it so that I could compare it to the current address - a couple of lines of code.
Here’s my code snippet of the index.js file

index.js
var web3js = new Web3(Web3.givenProvider);

var instance;
var user;
var contractAddress = "0xc2B1512EAEEfe984a9bb5C85158cbD57Ac91b060";

$(document).ready(function() {
    checkAccount();
})

function checkAccount() {   
    ethereum.request({ method: 'eth_accounts' }).then(function(accounts) {
        let account = accounts[0]; 
        //This console.log is just for my own reference and will be deleted later
        console.log(account + " Waddup " + " " + localStorage.getItem("currentAccount"));
        //This is where I compare the two addresses to one another. If they are the same I call the connect function which
        //will save me the hassle of always having to manually re-connect
        if(account == localStorage.getItem("currentAccount")) {
            connect();
        }
    });
}

function connect() {
    ethereum.request({ method: 'eth_requestAccounts' })
    .then(function(accounts) {
        instance = new web3js.eth.Contract(abi, contractAddress, {from: accounts[0]})
        user = accounts[0];

        //Here I store the address I've just logged in with in localSotrage
        localStorage.setItem("currentAccount", accounts[0]);

        instance.events.Birth()
            .on('data', function(event) {
                alert("Congratulations Em!!! Your cat has been created! And here are all the stats:" + 
                JSON.stringify(event.returnValues, null, 4));
            })
            .on('error', function(error) {
                console.log(error);
            })            
        })
    .catch((error) => {
        console.log(error);
    })     
}

Here’s a link again to my github account: https://github.com/EmmerichS/HelloKitties

Again, thanks so much. I appreciate your help. You helped me find the way to figuring out this headache :slight_smile:
Regards
Emmerich

1 Like

@kenn.eth

Dear Kenneth,

Problem solved. In the end I used localStorage to store the address I had logged in with and eth_accounts to retrieve current one. All I had to do was compare the two and if they were the same connect automatically.
Here’s the index.js file:

index.js
var web3js = new Web3(Web3.givenProvider);

var instance;
var user;
var contractAddress = "0xc2B1512EAEEfe984a9bb5C85158cbD57Ac91b060";

$(document).ready(function() {
    checkAccount();
})

function checkAccount() {   
    ethereum.request({ method: 'eth_accounts' }).then(function(accounts) {
        let account = accounts[0]; 

        //This console.log is just for my own reference and will be deleted later
        console.log(account + " Waddup " + " " + localStorage.getItem("currentAccount"));
        
        //This is where I compare the two addresses to one another. If they are the same I call the connect function which
        //will save me the hassle of always having to manually re-connect
        if(account == localStorage.getItem("currentAccount")) {
            connect();
        }
    });
}

function connect() {
    ethereum.request({ method: 'eth_requestAccounts' })
    .then(function(accounts) {
        instance = new web3js.eth.Contract(abi, contractAddress, {from: accounts[0]})
        user = accounts[0];

        //Here I store the address I've just logged in with in localSotrage
        localStorage.setItem("currentAccount", accounts[0]);

        instance.events.Birth()
            .on('data', function(event) {
                alert("Congratulations Em!!! Your cat has been created! And here are all the stats:" + 
                JSON.stringify(event.returnValues, null, 4));
            })
            .on('error', function(error) {
                console.log(error);
            })            
        })
    .catch((error) => {
        console.log(error);
    })     
}

Also, here’s my github again: https://github.com/EmmerichS/HelloKitties

Thanks for your help :slight_smile:
Regards
Emmerich

1 Like

thats great new @Emmerich. yeah sorry about that the only reason mine is a little longer is because i added the dynamic updating with the ethereum.onchange account event so you dont need to refresh whenever you change metasmask accounts. great that you go it working. aww man yeah local storage can be a lifesaver. you cand do even more complicated stuff with it like story arrays ob objects etc its so handy

1 Like

Added a box with id = "newMintBox " which changes the css and text within when the event listener is hit.

Struggled a fair bit with getting the event to hit.

Make sure that there is some object (even if empty) for options in the event brackets, such that

 instance.events.Birth({})
.on(...)

Here is the code:

index.js

var web3 = new Web3(Web3.givenProvider)

var instance;
var user;
var contractAddress = "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512";

$(document).ready(() => {
    window.ethereum.enable().then(function(accounts) {
        instance = new web3.eth.Contract(abi, contractAddress, {from: accounts[0]})
        user = accounts[0];

        console.log(instance)
    
        instance.events.Birth({})
        .on('data', function(event) {
            console.log(event)
            let owner = event.returnValues._owner;
            let kittenId = event.returnValues._kittenId;
            let mumId = event.returnValues._mumId;
            let dadId = event.returnValues._dadId;
            let genes = event.returnValues._genes;
        
            $('#newMintBox').css('display', 'block');
            $('#newMintBoxText').text("Cat ID: " + kittenId + " Cat's DNA: " + genes);
        }).on('error', function(error){
            $('#newMintBox').css('display', 'block')
            $('#newMintBoxText').html("Kitty Mint Failed!!!")
        })

    })
})


function mintGen0Cat() {
    instance.methods.createKittyGenZero(getDna()).send({}, function(error, txHash) {
        if(error) {
            console.log(error);
            $('#newMintBoxText').text("There's an error: " + error);
        } else {
            console.log(txHash);
        }
    })
}

$('#newMintBoxAccept').click(() => {
    $('#newMintBox').css('display', 'none')
})
1 Like

Calling this function after the contract instance has been initialized and passing the instance as an argument:

function eventListeners(instance) {

    instance.events.Birth({}, (error, event) => {
        if (error)
            console.log(error);
        else {
            alert("Transaction was successful. You now own a Kitty :)");
            console.log(event.returnValues);
        }
    });
}


Hey friends, can anyone help me with some guidance what is the problem here with my createkitty button?

index.js

// const Web3 = require("web3");
 ethereum.request({ method: 'eth_requestAccounts' });
 const web3Button = document.querySelector('.enableweb3Button');
 var { instance, contractAddress="0xDC2855A526CeEbA58f452841c6b5c29B3288daa", user } = newFunction();

 
 web3Button.addEventListener('click', () => {
   //Will Start the metamask extension
   ethereum.request({ method: 'eth_requestAccounts' });
   instance = new web3.eth.Contract(abi, contractAddress, {from: accounts[0]})
   user = accounts[0];
   
   console.log(instance);

})


createpixButton.addEventListener('click', () => {
    var dnaStr = getDna;
  
   instance.methods.createPixGen0(dnaStr).send({}, function (error, txHash){
    if(error)
        console.log(error);
    else
        console.log(txHash);
    })
})


instance.event.Create().on('data', function(event){
  console.log(event);
  let owner = event.returnValues.owner;
  let pixId = event.returnValues.pixId;
  let mumId = event.returnValues.mumId;
  let dadId = event.returnValues.dadId;
  let genes = event.returnValues.genes;
  $("PixCreation").css("display", "block");
  $("PixCreation").text("owner:" + owner
                        +" pixId:" + pixId
                        +" mumId:" + mumId
                        +" dadId:" + dadId
                        +" genes:" + genes)
})
.on('error', console.error);

hey @valleria ! The issue here is that createpixButton is not declared. At least is what I can see in the code. If you have it declare it somewhere else, please show it here.

I created a modal as the pop-up to display the birth event details. I’ve added snippets from the index.html and factory.css files, and included the index.js file in its entirety.

index.html snippet
   <div id="modalBirth" class="modal">
        <div class="modal-content">
            <span class="closeBtn">&times;</span>
            <p> Successfull Fishy Birth!!!</p>
            <!-- Fishy details: Genes, Token ID, User Address -->
            <div class="modalDetails">
                <label><b>Genes: </b><span id="birthGenes"></span></label>
                <label><b>Token ID: </b><span id="birthTokenId"></span></label>
                <label><b>Owner: </b><span id="birthOwner"></span></label>
            </div>
        </div>
    </div>
factory.css snippet
.modal {
    display:none; 
    position: fixed;
    z-index: 500;
    left: 0;
    top: 0;
    height: 100%;
    width: 100%;
    overflow: auto;
    background-color: rgba(0,0,0,0.5);
}

.modal-content {
    background-color: coral;
    margin: 35% auto;
    padding: 20px;
    width: 70%;
    box-shadow: 0 5px 8px 0 rgba(0,0,0,0.2), 
                0 7px 20px 0 rgba(0,0,0,0.15);
    animation-name: modalopen;
    animation-duration: 1.5s;
}

.closeBtn {
    color: silver;
    float: right;
    font-size: 30px;
}

.closeBtn:hover, .closeBtn:focus {
    color: rgba(0,0,0);
    text-decoration: none;
    cursor: pointer;
}

@keyframes modalopen {
    from{opacity: 0}
    to {opacity: 1}
}
index.js
var web3 = new Web3(Web3.givenProvider);
var instance;
var user;
//get contractAddress from console after migration command
var contractAddress = "0x1CBc1F99cEfDc084Fb5260f8c5bb94FBEDEd1843";

$(document).ready(function() {
    window.ethereum.enable().then(function(accounts) {
        //         new web3.Contract(jsonInterface[, address][, options])
        instance = new web3.eth.Contract(abi, contractAddress, {from: accounts[0]});
        user = accounts[1];

        console.log("Smart Contract interfacing complete.....");
        console.log(instance);
        listenerBirth(instance);
    })
})

function generateFishyGen0(dnaString) {
    //how to call smart contract function with the front-end
        //unless smart contract has "view" keyword, then its a setter function which modifies the state, and we use send()
            //this a call-back function where we're waiting on the ETH node to respond
    console.log("dnaString: " + dnaString);
    var dnaSt = dnaString.toString();
    console.log("dnaSt to create function check: " + dnaSt);
    
    instance.methods.createFishyGen0(dnaSt).send({from: user}, function(error, txHash){
        if (error) {
            console.log("Create Fishy Error: " + error);
        }
        else {
            console.log("Create Fishy Tx: " + txHash);
            console.log(instance);
        }
    })
}

function listenerBirth(instance){
   instance.events.Birth({})
   .on('connected', function(subscriptionId){
       console.log(subscriptionId);
   })
   .on('data', function(event){
       console.log(event);
       //Fishy details: Genes, Token ID, User Address
       var _genes = event.returnValues.genes;
       var _tokenId = event.returnValues.tokenId;
       var _owner = event.returnValues.owner;
       openModalBirth(_genes, _tokenId, _owner);
   })
   .on('error', function(error, receipt) { 
       // If the transaction was rejected by the network with a receipt, the second parameter will be the receipt.
       console.log("Birth event error: " + error + " receipt: " + receipt);
   });
}

//Get modal element
var modal = document.getElementById('modalBirth');
//Get close button
var closeBtn = document.getElementsByClassName('closeBtn')[0];
//Listen for close click
closeBtn.addEventListener('click', closeModalBirth);
//Listen for outside click
window.addEventListener('click', clickOutside);

function openModalBirth(genes, tokenId, owner) {
    modal.style.display = 'block';
    $('#birthGenes').html(genes);
    $('#birthTokenId').html(tokenId);
    $('#birthOwner').html(owner);
}

function closeModalBirth() {
    modal.style.display = 'none';
}

//close modal with outside click
function clickOutside(e) {
    if(e.target == modal) {
    modal.style.display = 'none';
    }
}


2 Likes

index.js

var web3;

if(window.ethereum) {

web3 = new Web3(window.ethereum)

}else if(window.web3) {

web3 = new Web3(Web3.givenProvider)

}

var instance;

var user;

var contractAddress = “0x61da89e5C0b0d9822FFf9da4A7d6CAd39836d6FB”;

$(document).ready(async function() {

const accounts = await window.ethereum.request({ method: "eth_requestAccounts" });

if(accounts.length > 0) {

    instance = new web3.eth.Contract(abi, contractAddress, { from: user });

    user = accounts[0];

}

function createKitty() {

    let dna = getDna();

   

    instance.methods.createKittyGen0(dna).send({from: user}, function(error, txHash) {

        if(error) {

            console.log(error)

        }else if(txHash) {

            checkSpawnedEvents()

        }

    })

}

async function checkSpawnedEvents() {

    instance.events.KittySpawned({

        fromBlock: await web3.eth.getBlockNumber()

    }, function(error, event) {

        if(error) {

            console.log(error)

        }else if(event) {

            let tokenId = event.returnValues.kittyId;

            alert(`Kitty successfully created with TokenId: ${ tokenId }`)

        }

    })

}

$("#createBtn").click(function() {

    createKitty()

})

})

1 Like

After researching many errors, I finally got it right! Here’s my code for index.js:

var web3;

if(window.ethereum) {

web3 = new Web3(window.ethereum)
}else if(window.web3) {

web3 = new Web3(Web3.givenProvider)
}
var instance;

var user;

var contractAddress = "0xfA44A9ec90408d37A8af89643B6336dd748D9D60";

$(document).ready(async function() {
    const accounts = await window.ethereum.request({ method: "eth_requestAccounts" });

if(accounts.length > 0) {

    instance = new web3.eth.Contract(abi, contractAddress, { from: user });

    user = accounts[0];
    instance.events.Birth().on('data', function(event){
        console.log(event);
        let owner = event.returnValues.owner;
        let kittenId = event.returnValues.kittenId;
        let momId = event.returnValues.momId;
        let dadId = event.returnValues.dadId;
        let genes = event.returnValues.genes;
        $("#kittyCreation").css("display","block");
        $("#kittyCreation").text("owner: " + owner + "kittenId: " + kittenId + "momId: " + momId + "dadId: " + dadId + "genes: " + genes)
    });

}
})
function createKitty() {
    var dnaStr = getDna();
    instance.methods.createKittyGen0(dnaStr).send({from: user}, function(error, txHash){ //we either get an error or a transaction hash.
        if(error)
            console.log(error);
        else
            console.log(txHash);
    })
}
$("#createBtn").click(function() {
    createKitty()
})
1 Like

i get an error : gas limit must be at least 21000

Here is my solution :slight_smile: :

$(document).ready(function() {
    window.ethereum.enable().then(function(accounts) {
        instance = new web3.eth.Contract(abi, contractAddress, {from: accounts[0]});
        user = accounts[0];
        console.log(instance);

        // listener fot kitty birth events:
        instance.events.Birth({}, function(error, event) {
            if(error) {
                console.log(error)
                alert(error)
            }else{
                console.log(event)
                alert(`Kitty has been born! 
                      \n Owner: ${event.returnValues.owner}
                      \n Dad Id: ${event.returnValues.dadId}
                      \n Mum Id: ${event.returnValues.mumId}
                      \n Genes: ${event.returnValues.genes}
                      \n Token Id: ${event.returnValues.tokenId}
                    `);
            }
        });
    });
});
1 Like

I am getting this error: (index):37 Uncaught ReferenceError: _createPenguin is not defined
at HTMLButtonElement.onclick ((index):37:44)
index.html:

<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Academy Penguin </title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/web3/1.5.0/web3.min.js" integrity="sha512-0/nXBDmnbXRIkGvwIK2UWg4F8xscIFZHGl2sWevr6f0DnFEqZh4uTw78qLQYC16tVxbbHhoaaZLSBoIopZQucg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
  <script src="https://cdn.jsdelivr.net/npm/web3@latest/dist/web3.min.js"></script>
  <script type="text/javascript" src="./js/jquery-3.4.1.js"></script>
  <link rel="stylesheet" href="./bootstrap/css/bootstrap.min.css">
  <script type="text/javascript" src="./bootstrap/js/popper.js"></script>
  <script type="text/javascript" src="./bootstrap/js/bootstrap.min.js"></script>
  <script type="text/javascript" src="./js/abi.js"></script>
  <script type="text/javascript" src="./js/colors.js"></script>
  <script type="text/javascript" src="./js/penguinFactory.js"></script>
  <script type="text/javascript" src="./js/penguinSettings.js"></script>
  <script type="text/javascript" src="./js/button.js"></script>
  <script type="text/javascript" src="./js/index.js"></script>
  

  <link rel="stylesheet" href="./css/mystyle.css">
  <link rel="stylesheet" href="./css/penguin.css">
  <link rel="stylesheet" href="./css/colors.css">
  <link rel="stylesheet" href="./css/factory.css">
  <link rel="stylesheet" href="./css/frontend.css">
  <link rel="stylesheet" href="./css/animations.css">
  <link rel="stylesheet" href="./css/button.css">


</head>
  <body>
    <div class="container p-5" style="margin-top: 12vh;margin-bottom: 10vh;">
        <div align="center">
        <h1 class="c-white">Penguin-Factory</h1>
        <p class="c-white">Create your custom Penguin</p>
        <button onclick="randomPenguin()" class="randomPenguin">Random Penguin</button>
        <button onclick="defaultPenguin()"class="defaultPenguin">Default Penguin</button>
        <button onclick="_createPenguin()">Create new Penguin</button>
        <button onclick="buttonColor()" class="colorsB">Colors</button>
        <button onclick="buttonPattern()" class="attributesB">Patterns and Attributes</button>

    </div>
        <div class="row">
            <div class="col-lg-4 penguinBox m-2 light-b-shadow">
                <div class="penguin ">
                    <div class="penguin-bottom">
                    <div class="right-hand"></div> 
                    <div class="left-hand"></div>
                    <div class="right-feet"></div>
                    <div class="left-feet"></div>
                    </div>

                    <div id="head" class="penguin-top">
                      <div class="belly"></div>
                        
                        <div class="pattern"></div>
                        <div class="pattern-left"></div>
                        <div class="pattern-right"></div>
                        <div class="left-cheek"></div>
                        <div class="right-cheek"></div>
                        <div class="beak-bottom"></div>
                        <div class="beak-top"></div>
                        <div class="blush-left"></div>
                        <div class="blush-right"></div>
                        <div class="left-eye">
                          <div class="sparkle"></div>
                        </div>
                        <div class="right-eye">
                          <div class="sparkle"></div>
                        </div>
                        

                    </div>



                    
                </div>
                <br>
                <div class="dnaDiv" id="penguinDNA">
                    <b>
                        DNA:
                        <!-- Colors -->
                         <span id="dnabody"></span>
                         <span id="dnabelly"></span>
                         <span id="dnaface"></span>
                         <span id="dnahand"></span>
                        
                         <!-- attributes -->
                         <span id="dnashape"></span>
                         <span id="dnadecoration"></span>
                         <span id="dnadecorationMid"></span>
                         <span id="dnadecorationSides"></span>
                         <span id="dnaanimation"></span>
                         <span id="dnaspecial"></span>
                    </b>
                </div>
            </div>
            <div class="col-lg-7 attributes m-2 light-b-shadow">


<!-- Penguin colors -->
<div id="penguinColors">
                <div class="form-group">
                    <label for="formControlRange"><b>Head and body</b><span class="badge badge-dark ml-2" id="headcode"></span></label>
                    <input type="range" min="10" max="98" class="form-control-range" id="bodycolor">
                </div>
                <div class="form-group">
                    <label for="formControlRange"><b>Belly</b><span class="badge badge-dark ml-2" id="bellycode"></span></label>
                    <input type="range" min="10" max="98" class="form-control-range" id="bellycolor">
                </div>  
                <div class="form-group">
                  <label for="formControlRange"><b>Face</b><span class="badge badge-dark ml-2" id="facecode"></span></label>
                  <input type="range" min="10" max="98" class="form-control-range" id="facecolor">
                </div>
                <div class="form-group">
                  <label for="formControlRange"><b>Hands</b><span class="badge badge-dark ml-2" id="handcode"></span></label>
                  <input type="range" min="10" max="98" class="form-control-range" id="handcolor">
                </div>
                <div class="form-groupP">
                  <label for="formControlRange"><b>Eye shape</b><span class="badge badge-dark ml-2" id="eyeName"></span></label>
                  <input type="range" min="1" max="7" class="form-control-range" id="eyeshape">
                </div>
                <div class="form-groupP">
                  <label for="formControlRange"><b>Pattern</b><span class="badge badge-dark ml-2" id="decorationPattern"></span></label>
                  <input type="range" min="1" max="7" class="form-control-range" id="patternshape">
                </div>
                <div class="form-groupP">
                  <label for="formControlRange"><b>Pattern Color Mid</b><span class="badge badge-dark ml-2" id="decorationMidcolor"></span></label>
                  <input type="range" min="10" max="98" class="form-control-range" id="patterncolormid">
                </div>
                <div class="form-groupP">
                  <label for="formControlRange"><b>Pattern Color Sides</b><span class="badge badge-dark ml-2" id="decorationSidescolor"></span></label>
                  <input type="range" min="10" max="98" class="form-control-range" id="patterncolorsides">
                </div>
                <div class="form-groupP">
                  <label for="formControlRange"><b>Animation</b><span class="badge badge-dark ml-2" id="animationName"></span></label>
                  <input type="range" min="1" max="6" class="form-control-range" id="animation">
                </div>
              </div>
              <div class="alert alert-sucess" role="alert" id="PenguinCreation" style="display:none"></div>
            </div>

            </div>
            <br>

        </div>



    </div>
    <footer align="left">
        <p>Ivan on Tech Academy Bootcamp July 2020</p>
    </footer>

  </body>


</html>

index.js:

var 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": "penguinId",
        "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"
      }
    ],
    "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": "CREATION_LIMIT_GEN0",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "PenguinIndexToOwner",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "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": [],
    "name": "name",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [],
    "name": "owner",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [],
    "name": "symbol",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "internalType": "address",
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "transferOwnership",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [
      {
        "internalType": "uint256",
        "name": "_id",
        "type": "uint256"
      }
    ],
    "name": "getPenguin",
    "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": false,
    "inputs": [
      {
        "internalType": "uint256",
        "name": "_genes",
        "type": "uint256"
      }
    ],
    "name": "createPenguinGen0",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [
      {
        "internalType": "address",
        "name": "owner",
        "type": "address"
      }
    ],
    "name": "balanceOf",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "balance",
        "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": [
      {
        "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"
  }
]
 var web3 = new Web3(Web3.givenProvider);
  var contractInstance;
  let contract_address = "0x5a98F7Ee17eA9287aF91521435ebaCE8a98a9F53";
  
 
  
  
   // *************************************************************************************************
      // *            -------------------Main structure on page load--------------------------                       *                                                                            *
      // *************************************************************************************************
  
  $(document).ready(function() {
    
     
      window.ethereum.enable().then(async function(accounts) {
  
         
        contractInstance = new web3.eth.Contract(ABI, contract_address, {from: accounts[0]});
        user = accounts[0];
        console.log(contractInstance)
        const s = await contractInstance.methods.totalSupply().call()
        //console.log(s)

        contractInstance.events.Birth().on('data', function(event){
          console.log(event);
          let owner = event.returnValues.owner;
          let penguinId = event.returnValues.penguinId;
          let mumId = event.returnValues.mumId;
          let dadId = event.returnValues.dadId;
          let genes = event.returnValues.genes;
          $("#PenguinCreation").css("display", "block");
          $("#PenguinCreation").text("owner:" + owner
          +" PenguinId:" + penguinId
          +" mumId:" + mumId
          +" dadId:" + dadId
          +" genes:" + genes)
        })
        .on('error', console.error);
      });
    })
    
  

Penguincontract.sol:

// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0 <0.9.0;

import "./IERC721.sol";
import "./ownable.sol";

contract Penguincontract is IERC721, Ownable {

    uint256 public constant CREATION_LIMIT_GEN0 = 10;
    string public constant name = "MichaelPenguins";
    string public constant symbol = "MP";

    event Birth(
        address owner,
        uint256 penguinId,
        uint256 mumId,
        uint256 dadId,
        uint256 genes
        );

    struct Penguin {
        uint256 genes;
        uint256 birthTime;
        uint256 mumId;
        uint256 dadId;
        uint256 generation;
    }

    Penguin[] penguins; 

    mapping (uint256 => address) public PenguinIndexToOwner;
    mapping (address => uint256) ownershipTokenCount; 

    uint256 public gen0Counter;

    function getPenguin(uint256 _id) external view returns (
        uint256 genes,
        uint256 birthTime,
        uint256 mumId,
        uint256 dadId,
        uint256 generation
        //address owner
    )
    {
        Penguin storage penguin = penguins[_id];

        birthTime = uint256(penguin.birthTime);
        mumId = uint256(penguin.mumId);
        dadId = uint256(penguin.dadId);
        generation = uint256(penguin.generation);
        genes = penguin.genes;
    }

    function createPenguinGen0(uint256 _genes) public onlyOwner returns (uint256) {
        require(gen0Counter < CREATION_LIMIT_GEN0);

        gen0Counter++;

        return _createPenguin(0, 0, 0, _genes, msg.sender);
    }

    function _createPenguin(
        uint256 _mumId,
        uint256 _dadId,
        uint256 _generation,
        uint256 _genes,
        address _owner
    ) private returns (uint256) {
        Penguin memory _penguin = Penguin({
            genes: _genes,
            birthTime: uint64(now),
            mumId: uint32(_mumId),
            dadId: uint32(_dadId),
            generation: uint16(_generation)
        });

        uint256 newPenguinId = penguins.push(_penguin) - 1;

        emit Birth(_owner, newPenguinId, _mumId, _dadId, _genes);

        _transfer(address(0), _owner, newPenguinId);
    }

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
      function balanceOf(address owner) external view returns (uint256 balance) {
        return ownershipTokenCount[owner];
    }
    /*
     * @dev Returns the total number of tokens in circulation.
     */
    function totalSupply() external view returns (uint) {
        return penguins.length;
    }
    
    function ownerOf(uint256 _tokenId) external view returns (address){
        return PenguinIndexToOwner[_tokenId];
    }
    
    function transfer(address _to, uint256 _tokenId) external {
        require(_to != address(0));
        require(_to != address(this));
        require(_owns(msg.sender, _tokenId));

        _transfer(msg.sender, _to, _tokenId);
    }

    function _transfer(address _from, address _to, uint256 _tokenId) internal {
        ownershipTokenCount[_to]++;

        PenguinIndexToOwner[_tokenId] = _to;

        if (_from != address(0)) {
            ownershipTokenCount[_from]--;
        }   

        emit Transfer(_from, _to, _tokenId);
    }

    function _owns(address _claimant, uint256 _tokenId) internal view returns (bool) {
        return PenguinIndexToOwner[_tokenId] == _claimant;
    }
    
}

1 Like