Image for post
Image for post

Ethereum, tokens & smart contracts.

Notes on getting started Part 9. Dapps & MetaMask

Previous notes in case you are just joining us:Part 1. Setting up.
Part 2. Web3.js/node.
Part 3. Solidity.
Part 4. Smart Contracts.
Part 5. Smarter Contracts.
Part 6. Tokens & Inheritance.
Part 7. ERC20 Token Standard.
Part 8. Crowdfunding and ICOs.

Ethereum Dapps ( These are early days ) :

So far we have covered contracts that live in the Ethereum blockchain and use the Ethereum vm, what we have seen so far is a mix of a programming language and a cryptocurrency.

  • The impractical part is a bit more daunting; the average webpage is around 2–3 mb and growing; that same webpage in ethereums VM would cost around $15,000 (and growing), to deal with this issue an add on of sorts is being developed: Swarm. which will deal with storage in a distributed and cost effective way.
  • It should be mentioned that other types of tooling (to make dapp development easier/possible) are currently in active development, check for instance: https://github.com/ethereum for current and future projects.

Enter MetaMask

Image for post
Image for post
Image for post
Image for post
Note: As of this writing adding tokens on metamask is not supported, but it might be in the future.  I would recommend parity or mist for now for token management via UI.
window.addEventListener("load", function() {
// Checking if Web3 has been injected by the browser (Mist/MetaMask)
if (typeof web3 !== "undefined") {
// Use Mist/MetaMask's provider
window.web3 = new Web3(web3.currentProvider);
} else {
console.log("No web3? You should consider trying MetaMask!");
// fallback - use your fallback strategy (local node / hosted node + in-dapp id mgmt / fail)
window.web3 = new Web3(
new Web3.providers.HttpProvider("https://localhost:8545")
);
}
// APP >web3.eth.getAccounts(function(error, accounts) {
if (!error) {
web3.eth.getBalance(accounts[0], function(error, balance) {
if (!error) {
console.log(
"Your account: " +
accounts[0] +
" has a balance of: " +
balance.toNumber() / 1000000000000000000 +
"Ether"
);
} else {
console.error(error);
}
});
} else {
console.error(error);
}
});
});
// "MetaMask - injected web3"
// "Your account: 0xbfca6ecdcb1a21d99befea4fd8cde79bc81e2c57 has a balance of: 0.799386868Ether"

ETHJS

It should be noted that web3 ( which is included in metamask for now) is not the only way to interact with ethereums blockchain, at the base there is a JSON-RPC API and web3 is but one wrapper, there are other like eth.js which is also popular in Dapp development:

window.addEventListener("load", function() {
// Checking if Web3 has been injected by the browser (Mist/MetaMask)
if (typeof web3 !== "undefined") {
// Use Mist/MetaMask's provider
window.web3 = new Web3(web3.currentProvider);
} else {
console.log("No web3? You should consider trying MetaMask!");
// fallback - use your fallback strategy (local node / hosted node + in-dapp id mgmt / fail)
window.web3 = new Web3(
new Web3.providers.HttpProvider("https://localhost:8545")
);
}
// APPconst eth = new Eth(window.web3.currentProvider);
eth.accounts(function(error, accounts) {
if (!error) {
eth.getBalance(accounts[0], function(error, balance) {
if (!error) {
console.log(
"Your account: " +
accounts[0] +
" has a balance of: " +
Eth.fromWei(balance, "ether") +
"Ether"
);
} else {
console.log(error);
}
});
} else {
console.log(error);
}
});
});
// "MetaMask - injected web3"// "Your account: 0xbfca6ecdcb1a21d99befea4fd8cde79bc81e2c57 has a balance of: 0.799386868Ether"Note that unlike the first example, we have to include the ethjs library.
Note:  Calling the blockchain via meta Mask and other libraries is an Asynchronous affair (query the blockchain, wait for a response, do something with the result).In our examples we dealt with this with callbacks, but depending on your library and programming tastes you could deal with the async part with promises,here's an example chaining promises ( and using fat arrows ) in ethjs:const eth = new Eth(window.web3.currentProvider);
eth
.coinbase()
.then(coinbase => eth.getBalance(coinbase))
.then(balance =>
console.log(
"Your coinbase has a balance of: " + Eth.fromWei(balance, "ether")
)
)
.catch(error => {});
// "Your coinbase has a balance of: 0.799386868"Codepen hosted sample: https://codepen.io/k3no/pen/mBvvzO

Call a contract :

We’ll be using our beloved BLIPS crowdfunding token from previous notes as a target for calling a contract.

Note: As a reminder, here's the BLIPS Token address on the Kovan network: 0xCCeEF52Df5Ff1B80e63E3f211021bd0bAe5323D6
window.addEventListener("load", function() {
// Checking if Web3 has been injected by the browser (Mist/MetaMask)
if (typeof web3 !== "undefined") {
// Use Mist/MetaMask's provider
window.web3 = new Web3(web3.currentProvider);
} else {
console.log("No web3? You should consider trying MetaMask!");
// fallback - use your fallback strategy (local node / hosted node + in-dapp id mgmt / fail)
window.web3 = new Web3(
new Web3.providers.HttpProvider("https://localhost:8545")
);
}
const tokenABI = [...]; // See Codepen for full ABI.
const eth = new Eth(window.web3.currentProvider);
const token = eth
.contract(tokenABI)
.at("0xCCeEF52Df5Ff1B80e63E3f211021bd0bAe5323D6");
token.symbol().then(function(tokenSymbol) {
console.log("Token Symbol :" + tokenSymbol[0]);
});
token.name().then(function(tokenName) {
console.log("Token Name :" + tokenName[0]);
});
token.totalSupply().then(function(supply) {
console.log("Total Supply :" + supply[0]);
});
eth
.coinbase()
.then(coinbase => token.balanceOf(coinbase))
.then(balance =>
console.log("Your coinbase has a balance of: " + balance[0] + " tokens")
)
.catch(error => {});
});

// Console :
// "MetaMask - injected web3"// "Token Symbol :BLIPS"// "Token Name :Blips Token"// "Total Supply :5200"// "Your coinbase has a balance of: 2000 tokens"
window.addEventListener("load", function() {
// Checking if Web3 has been injected by the browser (Mist/MetaMask)
if (typeof web3 !== "undefined") {
// Use Mist/MetaMask's provider
window.web3 = new Web3(web3.currentProvider);
} else {
console.log("No web3? You should consider trying MetaMask!");
// fallback - use your fallback strategy (local node / hosted node + in-dapp id mgmt / fail)
window.web3 = new Web3(
new Web3.providers.HttpProvider("https://localhost:8545")
);
}

const coinbase = '0xbfca6ECdcB1a21d99bEfeA4Fd8CDE79Bc81e2c57';
const tokenAccount = '0xCCeEF52Df5Ff1B80e63E3f211021bd0bAe5323D6';
const eth = new Eth(window.web3.currentProvider);
// not meant for production since it would fire every time you load the page... eth
.sendTransaction({
from: coinbase,
to: tokenAccount,
value: Eth.toWei(0.05, 'ether'),
gas: '3000000',
data: '0x',
})
.then(result => {
console.log("Tx:" + result);
})
.catch(error => {});
});
Image for post
Image for post
"Tx:0x23fa03376136f7f23048b87affc0f28a1ea167ccce81833bf9417af2275c6896"
Image for post
Image for post

BLIPS DAPP

So now that we have a basic understanding of how to bridge the browser and the blockchain via metaMask and web3 or ethjs, we need to package it all for consumption into a Dapp, our Dapp will be a simple front for our BLIPS Token campaign that will pull total supply and allow you to contribute and get tokens in exchange for ether, all from the comfort of your browser.

let tokenABI = [...]; // check the source code for the full ABI
let tokenAddress = "0xCCeEF52Df5Ff1B80e63E3f211021bd0bAe5323D6";
let token;
$("#mmAlert").hide();
$("#txSuccess").hide();
// Connect to MetaMask :
window.addEventListener("load", function() {
// Checking if Web3 has been injected by the browser (Mist/MetaMask)
if (typeof web3 !== "undefined") {
// Use Mist/MetaMask's provider
window.web3 = new Web3(web3.currentProvider);
} else {
console.log("No web3? You should consider trying MetaMask!");
// fallback - use your fallback strategy (local node / hosted node + in-dapp id mgmt / fail)
window.web3 = new Web3(
new Web3.providers.HttpProvider("https://localhost:8545")
);
}
Dapp();
});
function Dapp() {
// Init eth:
const eth = new Eth(window.web3.currentProvider);
const token = eth.contract(tokenABI).at(tokenAddress);
// Are we logged into MetaMask :
window.web3.eth.getAccounts(function(err, accounts) {
if (err != null) console.error("An error occurred: " + err);
else if (accounts.length == 0) {
$("#mmAlert").show();
// Prompting for reload, but ideally you should check for account changes
} else {
console.log("User is logged in to MetaMask");
$("#mmAlert").hide();
}
});
// Coinbase Account balance:
eth
.coinbase()
.then(coinbase => eth.getBalance(coinbase))
.then(
balance =>
(document.getElementById("accountBalance").innerHTML = Eth.fromWei(
balance,
"ether"
))
)
.catch(error => {});
// BLIPS supply:token.totalSupply().then(function(supply) {
document.getElementById("supply").innerHTML = supply[0];
});
// BLIPS Balance:
eth
.coinbase()
.then(coinbase => token.balanceOf(coinbase))
.then(
balance =>
(document.getElementById("blipsBalance").innerHTML = balance[0])
)
.catch(error => {});
}
// Get Some BLIPS ! // vanilla JS...
document.getElementById("buy").onclick = function(e) {
e.preventDefault();
var eth = document.getElementById("amount").value;
// Note: Offloading balance validation to metaMask,
// but ideally you should also validate here
// Against Balance.
// Some basic number validation...
if ($.isNumeric(eth) && eth > 0) {
$("#amount").removeClass("is-invalid");
getBlips(eth);
} else {
$("#amount").addClass("is-invalid");
}
};
// Jquery ...
$("#reload").click(function() {
Dapp();
});
function getBlips(amount) {
console.log("Will try to exchange" + amount + "for Blips");
const eth = new Eth(window.web3.currentProvider);
eth
.coinbase()
.then(function(coinbase) {
eth
.sendTransaction({
from: coinbase,
to: tokenAddress,
value: Eth.toWei(amount, "ether"),
gas: "3000000",
data: "0x"
})
.then(result => {
console.log("Tx:" + result);
$("#receipt").html(
'<a href="https://kovan.etherscan.io/tx/' +
result +
'" target="_blank">' +
result +
"</a>"
);
$();
$("#txSuccess").show();
});
})
.catch(error => {});
}
Dependencies:- MetaMask Chrome Plugin.
- CSS: bootstrap 4, font-awesome
- JS: (Babel); Jquery-min, ethjs(from their repo), bootstrap 4
Image for post
Image for post
Image for post
Image for post
Disclaimer: This is a minimal Dapp for educational purposes, it could be improved in a number of ways( modularity,security,UI,UX,features).

Dapp Developing Considerations :

  • The above Dapp code is basically an integration of the previous examples gently hammered into a front end UI, so there is almost no new code except for some validation and interfacing (talking) to the Front End.
  • Most of the initial difficulty is due to the asynchronous nature of interacting with the blockchain via MetaMask and conveying such flow to the user; in the example I opted to offload checking balances to the user via a note that asks for a refresh or reload of the Dapp ( for simplicity ), but you could also add a listener for account changes like MetaMask suggests:
https://github.com/MetaMask/faq/blob/master/DEVELOPERS.md#ear-listening-for-selected-account-changesvar accountInterval = setInterval(function() {
if (web3.eth.accounts[0] !== account) {
account = web3.eth.accounts[0];
updateInterface();
}
}, 100);
  • Validation is also a recurring theme, while MetaMask checks transactions before sending them, depending on your Dapp you could need more validation.
  • One last thing that I didn't check but that might be important are gas costs which we already covered in previous notes, that is if your transactions incur in different gas costs that’s something you will need to bake into your Dapp.

Better DAPPs

You might be thinking this Dapp is too much trouble for what it does, or maybe you are thinking wait a minute, this is nothing but a very complex donate button. You are partially right.

Note: The future might be brighter, the biggest pain point with MetaMask is that it is a chrome plugin, so it requires your users to use chrome and download a plugin, a new library: Mascara , is in the works. This library or others like it would allow you to simply include a light Ethereum client you could interact via javascript, making integration with the blockcahin dramatically easier. 

SERVER SIDE DAPPS :

These are but a few ways to start writing a Dapp, for more complex projects where you would want users to not interact with your contracts via meta mask or their own clients, you would need a few extra steps :

  • Manage your users keys or provide a way for them to do so and interact with your application backend.
  • Manage storage while swarm reaches maturity.

Friendly Recap:

  • Notes Part 1 : Setting up : Getting a wallet/client , connecting to a test Ethereum blockchain and getting some test ether.
  • Notes Part 2: web3.js/node : Interacting with the blockchain through web3.js and node for more convenience and ease of development.
  • Notes Part 3: Solidity : Installing solidity (Ethereums contract writing language ) , Creating a very basic contract, compiling it, deploying it to the blockchain ( the test one) and interacting with it.
  • Notes Part 4: Smart Contracts: We modified our simple contract so we could store and retrieve information (making it smart), in the process we also covered how to watch the blockchain and contracts and finally we took a look at gas and how to estimate it.
  • Notes Part 5: Smarter Contracts: In order to allow contracts more complex behavior (make them smarter) , we need to delve a bit deeper into contract creation via constructors and a few more complex types which we will use in making a token contract.
  • Notes Part 6: Tokens & Inheritance: We made our first Token and interacted with it by transfering some of it from one account to another, we also briefly covered inheritance which is used in more complex contracts.
  • Notes Part 7: ERC20 Token Standard: We made and deployed an erc20 token which can be considered the parting standard for working sub currencies. We examined the code and talked about transfers in between tokens.
  • Notes Part 8: Crowdfunding and ICOs: We explored the subject of crowdfunding via smart contracts in the form of ICOs and the exchange of ether for tokens, we made contracts that can receive ether, collect ether and can be used for exchanging ether and creating an unlimited supply of tokens.
  • Notes Part 9: Dapps & MetaMask (This post): We looked into what is a Dapp and where we are in terms of development ( very early), we then introduced MetaMask which helps make Dapps accessible in the browser , we looked at various ways to interact with MetaMask via javascript and we integrated them into a fully fledged test Dapp that uses our previously made token smart contract, we also touched on the future of Dapps and server implementations.
Image for post
Image for post
✨✨  Now a Book !  ✨✨If you are looking for an introduction to Ethereum, Solidity and Smart Contracts these notes were edited and revised into a convenient book !
Available in ebook and paperback:
https://www.amazon.com/dp/B078CQ8L7V

Written by

AI, Software Developer, Designer : www.k3no.com

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store