Good Great things things come in sets of three, so you're in luck! This is my third guide in a series to help new users get acclimated to the Ethereum ecosystem. If you have not read the others, go back here and start from the beginning.
These guides are written by me, a developer, to you, a user. That means while I've gotten to the level of understanding that I'm at by diving into the code behind the development (that makes me Neo or Turbo; take your pick), the point of these guides is not to make you a developer too, but to make you comfortable in this new technological ecosystem. As I've mentioned in past guides, the Ethereum ecosystem brands itself as a "major version upgrade" to the current way we interact with "the internet", and like any major version upgrade, that means there are new reflexes that we'll need to learn, and some of the old reflexes from the previous version will not be useful any more. Before you can get anywhere in this new world, you need some basic skills. Just like when you started using a computer, you needed to learn clicking and dragging actions, and needed to mouse over each of those little buttons in the top corner of each desktop window to remember which one was the "minimize" and which one was the "close". But now that you've memorized those things, they're second-nature; they're reflexes. And that's the goal of these guides, to get you some practice and repetition under your belt, so these new actions start to feel less strange, and you can go on to explore this brave new world, without needing to spend all your energy on just navigating around.
One other important reminder from the first guide: Ethereum is "decentralized", which means there's no trust built in. To stay safe out here, it means you must operate from a default position of everyone's a con man, including me! I'll give you steps along the way that enable you to verify your actions, which I'd strongly suggest you utilize.
1. Are we there yet?!?
All right, so where were we? Are you a guru yet? You've been listening to me blather on for two whole guides now, so by now all the slackers in the back of the class have dropped off and stopped reading, so it's just you cool kids left, right? So, when I say "tell me your private key", what do you say? You tell me to take a hike, right? You never tell your private key to someone you don't trust and I just told you not to trust me! But you do know where your private key is, if you needed to get at it, right? Great! If I told you to go look up the contract at 0x69b5357D893fcE82248E83CCd9B0871F5D5d9461
, would you know how to do that? Well, one of the sites that I've been recommending is Etherscan, and indeed if you put that hexadecimal string into their search box, you'll find that it will come up with a details page about that contract. And looking at the "Contract Source" for it, you'll see that's the core contract I introduced in the last guide; the one me and cousin Lenny put together to sell you "unicorns" (which are definitely not just horses with a cardboard horn attached to their head. No, they're so much more than just that; have you seen the craftsmanship on those horns?! I just called it "Horse with a Cheap Cardboard Horn" because I like the acronym; HWACCH. It's like an onomatopoeia for swinging a katana through a pineapple! 🍍).
But you're supposed to be getting self-sufficient in this, and one of the points of being a decentralized system is that there's dozens of ways to get at that same data. Etherscan is just one of many companies that have set themselves up as an easy window in to the data coursing through the Ethereum network. But they are not the only. The term for those sort of companies/websites is a "block explorer" (named after the underlying structure that Ethereum keeps its data in; a blockchain). So, go hit the Google and look for an "Ethereum block explorer" that's not Etherscan. Then search for that contract address I mentioned in the prior paragraph on this new block explorer you found and see what you find. Compare the various bits of data that are displayed about that contract to the Etherscan's data for that contract. Is it the same? They should be! (If they're not, make sure the block explorer you found isn't an "Ethereum Classic" block explorer (uses ETC abbreviations instead of ETH); that's a completely separate thing, go find one that isn't a "classic" block explorer)
One thing you may note though is that while the Etherscan page has a nice "Read Contract" tab, and labels the page with a name for the contract, not all block explorers will have that. Mostly because I as the developer, submitted my code to Etherscan to allow them to better parse the contract. Someone might have done the same with my code on other block explorers (I'm looking at you, kid over by the window with the baseball cap pulled down low...), but that's not a guarantee. So, how do you know I'm not the developer of Etherscan, and I'm actually manipulating that interface to show what I want it to show to trick you? Before we go any deeper into this, let's take a look at more advanced ways of verifying things in Ethereum.
2. Don't trust; verify.
Okay, so up to this point, verification of what I've put in these guides has mostly been a matter of you reading carefully, and using Google and Etherscan to verify what I say. But did you ever consider that Etherscan might be being manipulated by me until I brought it up a paragraph ago? Or your search results on Google...? 😏
In the real world, trust starts with identifying the person (is this a spy in disguise and not really your Aunt Ming?), verifying they are actually the source of the information (Did someone forge a signature on this legal document or am I really related to a Nigerian Prince?), and then treating the information as trusted.
So, let's do that in Ethereum. Up to this point, I haven't given you my name or any other identifier. You can look at this blog post's author, but what if that author copied and pasted it from somewhere else, and they're not really the original author? I can say "I'm Midnight426", but if my conniving sister Eve actually copied and pasted this whole thing, and the Midnight0426 user is actually her user account, changing that name in the text before posting it is still easy to do. So, let's try this:
I do solemnly swear that I'm the owner of
Ethereum address 0x6954d0255cfeD71d55Ad8b371b4170B8BF7709dC.
Do you believe me? I totally raised my right hand while typing that out (you should have seen it; it's a royal pain to type that one-handed!)! No? Okay. So, in me saying that, it probably raised two questions with you:
- Why should I trust that statement?
- Why should I care that you're the owner of that address?
Let's cover the second one first, since it's easier, and will make you more willing to put forth the work needed to do the first one. The Ethereum address 0x6954d0255cfeD71d55Ad8b371b4170B8BF7709dC
is important to you, because it is the address that is the creator of all the smart contracts used in this guide series. That's something you can verify on all Ethereum block explorers (even ones that don't have the source code of the contract). Go back to that HWACCH contract at some block explorer, and you should find listed a "creator" or "creation transaction". If it shows a creation transaction, click through for details on that transaction, and it will show where the transaction came from (the "sender" or "creator"). It matches the one above in my statement, no? Now go check the Unicorn Assembler contract; the one that if you pay it, you get HWACCH in exchange (0x2DC588Af5eff094401b1F8016E74E7D46d9E7A31
). Find its creator. Same address, right? Now go check another block explorer. Does it agree? It should! Now come back to Etherscan and check it too; does it agree? Good! Hopefully that gives you some confidence in Etherscan (and the other block explorers) and the data they're presenting.
So that's why you care about that particular address, even though I've never mentioned it so far. It's the address I used to set up this whole guide series. For this particular use case, it's my username/identifier within the Ethereum ecosystem. Okay, so how do you as the recipient of my missive trust that you're hearing it from the lips of the real owner of that address? In the real world, you'd include a signature along with the document to prove its origin. And in Ethereum (and many other cryptocurrencies) there's also the concept of "signing a message" that fulfils the same purpose. This thing we're about to do is more generally as "signing a message with your private key". Public/private key cryptography is actually something that's existed for a while as a security method (it forms part of the underpinning of the communication that keeps HTTPS traffic secure), and cryptocurrencies just picked up that existing technology and is bringing more into the mainstream.
Most of the messages that you sign with your private key in the Ethereum ecosystem are transactions; messages that are something like "send 5 ether from me to Johnny". You may recall from our past exercises in sending a transaction using the MyEtherWallet tool, that after you input all the parameters, it shows you the final blob of data that is your message, and then your next action is to sign it before sending it out into the Ethereum network. Signing that message allows a way to prove it came from you and not any other user (the amazing math behind generating that signature guarantees that the person who created the signature must have been in possession of the private key related to a given public key). So, all Ethereum client software knows how to sign messages with a private key, and also how to verify a signature on a message was actually generated by a particular address (public key).
So, by me saying "I own address 0x6954d0255cfeD71d55Ad8b371b4170B8BF7709dC
", what I'm really saying is "I have the private key that is related to the public address 0x6954d0255cfeD71d55Ad8b371b4170B8BF7709dC
". And to prove that, I'm going to go to MyEtherWallet's Sign Message tool, enter my private key for that address, and there MyEtherWallet gives me an option to enter a custom message to sign with that key.
So, I entered the message I am telling the truth.
, and signed it with my private key. Tada! Here it is; the signature itself is a long hexadecimal string:
0xc00b7ea18a00afeb7fb30d1fa816e698a3aa5e3b7a03241957dce7b53129a6632
82c6ffd612939daeb401b5fc3b7e24b736197ebbeb9b2fc0ba843e836caffb61c
So, take a look at that signature; do you trust it? It doesn't mean much to a human, but to a software tool that knows how to do the public/private key dance, they can verify that's genuine, but they'll need three bits of information:
- The public address that (supposedly) did the signing
- The message they (supposedly) signed
- The signature
MyEtherWallet actually arranges those three things for you in a nice little bit of code that looks like this:
{
"address":"0x6954d0255cfeD71d55Ad8b371b4170B8BF7709dC",
"msg":"I am telling the truth.",
"sig":"0xc00b7ea18a00afeb7fb30d1fa816e698a3aa5e3b7a03241957dce7b53129a663282c6ffd612939daeb401b5fc3b7e24b736197ebbeb9b2fc0ba843e836caffb61c"
}
So, you copy that (from the opening curly brace to the closing one) and head over to MyEtherWallet's Sign Message tool, and click the "Verify Message" link. Paste in that whole bundle, and click "Verify Message". MyEtherWallet should pop up a message saying it's valid! There you go, we're best friends now, right? No? Still slightly skeptical? What if MyEtherWallet just always pops up that message saying its successful? Try changing something in the data being input into that tool and verify it again. Change one of the letters in the address to a different letter. Add some words to the message that was signed. Change a digit in the signature hexadecimal data. Any of those changes, if you try verifying the message again, will pop up with an error saying it's not valid. Try putting it back to the way it should, and checking that it does validate again. Go surf the internet for some other "ethereum verify message" tool, and repeat the process. They should all agree that the message is valid.
Huzzah, so now we're besties? Let's go get some matching "Best Friend" bracelets to wear forever! Don't be concerned if mine says "Eve" on the back, that's just a joke... Why are you backing away from me all of a sudden? Well, if you're clever, you've already noticed that even though the public/private signing technology is agreeing that there is a valid signature on that message, the message itself really doesn't do anything. "I am telling the truth" says nothing about who "I" is (anyone can now take that signature, share it with someone else and impersonate 0x6954d0255cfeD71d55Ad8b371b4170B8BF7709dC
!). And there's no date or other indication about what the message sender is telling the truth about. So there you go, take that whole message signature, and the next time your significant other says it's really your turn to scoop the litter box, you tell them they're mistaken, and then give them that message and signature to show that you're telling the truth.
So, just the same way that you can put a great signature on a horribly written document in the real world, in Ethereum, you can put an iron-clad signature on absolute garbage if you so choose. If I made the message be "The moon is made out of green cheese.", it doesn't mean the moon suddenly becomes much more appealing to mice, but it is provable that whoever holds the private key to that address did make that statement.
All right, so I'm going to do something less dumb now. Here's another message and its signature:
{
"address":"0x6954d0255cfeD71d55Ad8b371b4170B8BF7709dC",
"msg":"I am Midnight426 on Steem and Twitter, I am MidnightLightning on GitHub, and I'm the owner of the Ethereum address 0x6954d0255cfeD71d55Ad8b371b4170B8BF7709dC, which signed this message.",
"sig":"0x178248907aa17d351ff6edff93c05268f9317399a290e809b267a791b59ebe3a1b94509d1acea529a71c0794086568bf9d08735a1e7f3c77b5595f85578491291b"
}
Note the message I signed. I included my Steem username, as well as my Twitter and GitHub usernames too, and brought them all into relation with the Ethereum address 0x6954d0255cfeD71d55Ad8b371b4170B8BF7709dC
. So, take that and go verify that it's a valid signature. Now do you trust me? At this point, the most you can say is that whoever owns the that private key wants to claim to be Midnight426 in those other off-chain services. That's enough information for you to use other channels to go contact Midnight426 on those other platforms, and see if they agree with that message. So, combining your trust for the user accounts on those other platforms (trusting that Eve didn't steal the password for all three of those users on all three other sites, to be able to impersonate those users) plus the validation of the signature from the Ethereum ecosystem should give you a decent degree of trust in this.
3. Do something
By now you've all become proud members of the HWACCH-owning club: you successfully traded currency (ether) for a much more valuable asset (a unicorn! 🦄 🌈 ✨); able to rub elbows with other high-society unicorn-owning awesome people. Your dreams have all come true, right? Well, after a week or so, you start to notice that owning your own HWACCH isn't all sunshine and rainbows and exotic hot-tub parties. No! Those suckers inhale food by the bale-ful and leave odious droppings "presents" around the pasture that are definitely less sparkly than previously advertised. You're looking for a break! You want someone to take these unicorns off your hands and let you get back to enjoying your life again! 😩
Fortunately for you, my niece AJ and I have a solution to all your woes! See AJ's been taking care of the various critters her seven brothers bring home and then abandon ever since she's been old enough to get up the stairs with a toad in each hand. So she knows a thing or two about pampering critters 💆. So, I teamed up with her, and together we created the Unicorn Ranch! Yes, that's right, a lovely 500-acre property with state-of-the-art facilities, custom-equipped to provide the very best in relaxation and rejuvenation specifically for HWACCHs of all shapes and sizes. So, here's the deal: you drop off your HWACCH, pick a length of stay (just a brief spa visit, or an extended, multi-day stay?), pay a nominal fee (those suckers don't stop needing food just because they're out of your sight; we need some income to buy chow for them), and then you're free! Come back after the appointment's over, and you can pick up your HWACCHs and go on your merry way! The Ranch is open for business; stop on over contract 0x97E7ef310499bE2f97C392B8B16Ddd494Af73E22
today!
All right, that was easy enough to describe in real-world terms, but now how in the Ethereum ecosystem do you "drop off" a HWACCH at the Ranch? This is the next "layer" in the Ethereum asset hierarchy. We started by sending transactions that were the generic "send X ether from A to B", and that sometimes triggered a contract to do something else (like assemble a new HWACCH for you), but now you need to do something more complex, like "send X HWACCH from A to B". In a real-world contract, the contract drafter may create some actions that the participants can do (e.g. "This contract may be cancelled if party A stands up and announces to the room 'I don't wanna!'"). The logic and flow of the action is baked into the contract by the designer (lawyer in the case of a real-world contract, or developer in the case of an Ethereum contract), but it still needs to be triggered by the participating human. All contracts in Ethereum lie dormant until someone triggers them; they will take no action on their own without human intervention. A contract that's been activated by a human can (as part of its activated logic) reach out and trigger a second contract. So it can be like a chain of dominos, where one contract triggers another, which can trigger another, but there needs to be a human at the start of it to knock the first domino over.
So, let's start with just sending HWACCH to someone else. The HWACCH contract (0x69b5357D893fcE82248E83CCd9B0871F5D5d9461
) has several actions you can take (in programming terms, these actions are "functions") that do different things with your HWACCH. The names and behaviors of those actions could be anything I wanted them to be when I created the contract. However, I chose to make that token adhere to the ERC20 token standard. The ERC20 (Ethereum Reqeust for Comments #20) document is a proposal to list out a set of lowest-common-denominator actions that any usable token should have. The logic of the actions is left up to the individual contract/token (e.g. one token might not allow you to submit specific transactions on Sundays, but when you are able to submit a transaction, the action taken is the same as other tokens), but the names and inputs into those actions/functions are the same. We already used the balanceOf
function in the previous guide to check and see how many HWACCH you own. That function's a free, read-only function, which is why Etherscan sticks it on the "Read Smart Contract" tab for you to just run through their interface.
But now, we want to actually move our HWACCH around. For that, the ERC20 standard defines the transfer(address _to, uint _value)
function. This is a function that requires two inputs: the _to
address (Ethereum address you're sending the tokens to) and the _value
amount (the amount of tokens you're sending). The logic of the contract then uses the sender of the message (you) to determine which HWACCH balance to deduct from, and moves the asset. Therefore, using the transfer
function, you're only allowed to spend your own HWACCH, but you can send it to any destination you want. Let's use that method to send one HWACCH to the Ranch. We can continue to use the MyEtherWallet tool, but now that we're not just sending ether to a contract, we need to tell MyEtherWallet what the functionality of the contract we're communicating with is. The technical term for that is you need to get the contract's ABI (Application Binary Interface). The ABI is just a list of the functions and the arguments they take, formatted in a way that's easy for a computer to parse (JSON). So how to get the ABI for the HWACCH token? Etherscan has it under the "Contract Source" tab for that contract. You can copy that whole thing, or here's a truncated version that's just the five functions we'll be using in this guide:
[
{
"constant": true,
"inputs": [{ "name": "_owner", "type": "address" }, { "name": "_spender", "type": "address" }],
"name": "allowance",
"outputs": [{ "name": "remaining", "type": "uint256" }],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [{ "name": "_spender", "type": "address" }, { "name": "_value", "type": "uint256" }],
"name": "approve",
"outputs": [],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [{ "name": "_who", "type": "address" }],
"name": "balanceOf",
"outputs": [{ "name": "balance", "type": "uint256" }],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [{ "name": "_from", "type": "address" }, { "name": "_to", "type": "address" }, { "name": "_value", "type": "uint256" }],
"name": "transferFrom",
"outputs": [],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [{ "name": "_to", "type": "address" }, { "name": "_value", "type": "uint256" }],
"name": "transfer",
"outputs": [],
"payable": false,
"type": "function"
}
]
Now with that ABI in hand (or rather, in-clipboard), fire up your local copy of MyEtherWallet (remember, we downloaded the source code for it in the first guide...?), and head to the "Contracts" tab. Make sure the "Gas Price" drop-down in the top-right corner is set to your desired price (something low; we don't need to spend an excessive amount on this), and make sure the "Node" drop-down is set to an "ETH" node. Put the contract's address in the "Contract Address" field, and paste the ABI into the field below it, and click "Access". If MyEtherWallet was able to understand the ABI you gave it, it should give you an additional form element: a drop-down selector where you can "Select a function" to run on that contract.
Okay, to the one guy slouching in the back in a rugby jersey who called out "What's that dorky circle with all the colors in it next to the contract address", you may also have noticed it on Etherscan as well (though Etherscan puts it to the left of the address instead of the right, and they have it in a square instead of a circle). Those things are called "identicons", and they're designed to be a quick way to do a spot check to tell if you're interacting with the right contract address. For example, remember when I tricked you into sending your ether to me instead of the Unicorn-Assembling contract in the last guide (Ah, good times, good times 😂), that was pretty obvious, since even the first couple of characters in the hexadecimal address were different (the real assembler address starts with 0x2DC588
. The fake one I gave starts with 0x6954d0
), even a very lazy person should be able to skim that address and quickly see they're not the same. But by happenstance, my personal address (The one I signed the message with above, which starts with0x6954d0
) is similar to the HWACCH address. Both it and the HWACCH address start with 0x69
; you have to look further than that to make sure you're dealing with that right address. But what if I told you the HWACCH token address was 0x69b5357d893fce82248c83ccd9b0871f5d5d9461
? Is that correct? You've now got to go pull up some reference you trust (probably a block explorer) and go letter by letter with a lot of eyeball back-and-forth to figure out if that thing is the same. Is it? It's not; I changed one "e" to an "c" in that one. But it probably took you a good long time to figure that out. The identicons are there to help make that sort of discernment easier. The logic of the identicons is designed such that even a small change in the address used to generate an identicon will cause a drastic change in the appearance of the identicon. It's possible that two different addresses will have the same identicon (there's less possible identicons than there are possible Ethereum addresses), but if two addresses have the same identicon, they're very likely going to have hexadecimal values that are very different; not just one or two characters off. So when verifying that you're on the address you think you are, you should use the hexadecimal value AND the identicon (if the site you're using provides it). Try copying that bad address into the MyEtherWallet interface, and note that the identicon changes to something dramatically different than what the real address' is.
Okay, put the "Contract Address" back to the real HWACCH address and pick transfer
from the drop-down menu, and it will then show you a form where you can put in those two values (_to
and _value
) you need to supply to that function. Put the Unicorn Ranch address in the _to
field (0x97E7ef310499bE2f97C392B8B16Ddd494Af73E22
), and put "1" in the _value
field. Use your Keystore File to let MyEtherWallet use your private key to sign this transaction, and click the "Write" button. That will pop up a "Warning!" dialog (don't worry; that's expected. MyEtherWallet does that just to make sure you're giving this the due-diligence it requires. Because you're now doing something custom, you're in the driver's seat, not MyEtherWallet, so it does this check to make sure you know that the guard rails are off). In the "Amount to Send" field, you can leave that at zero (we're not sending any additional ether with our HWACCH, just the token). You do still need gas, though, so leave the "Gas Limit" set for whatever MyEtherWallet computes it to need. Click "Generate Transaction" and it will do the background computations needed to turn the function and inputs you've set into a custom transaction and sign it with your private key.
If that looks correct, click the "Yes, I am sure! Make transaction" button, and your command will be sent to the Ethereum blockchain. Once that transaction gets confirmed, let's check your balance to see if it's changed. You can go back to the HWACCH token's page on EtherScan and use the "Read Smart Contract" tab to use the balanceOf
function again, but now that we've inputted that into MyEtherWallet, it knows about that function too. Pick the balanceOf
function from the drop-down list, and enter your own address in the _who
field. The "Write" button has changed to a "Read" button now (since MyEtherWallet now knows this is a free, read-only action). Click the "Read" button, and the "balance" output should show one less HWACCH is in your possession. Enter the Unicorn Ranch's address in the _who
field and click "Read" again, and you'll see their balance has gone up by one.
Congratulations, you've now moved an asset that's not ether around to a different address! 🎉
Now if you're that helicopter parent who's now bouncing on the edge of your chair wondering when you can get your HWACCH back, chill out (seriously, what's it been, two minutes and you miss them already? Go play with your fidget spinner for a while). Take a deep breath. You ready for this? You're not getting that HWACCH back. "What? Why?!?" you might cry, "You said this Ranch was for a temporary drop off, and we can pick up again later!" Yes, the Unicorn Ranch contract is for that. But you weren't interacting with the Unicorn Ranch contract, you were interacting with the HWACCH token contract. Remember back when I told you a contract won't do anything on its own without a human to trigger it? You haven't triggered anything on the Unicorn Ranch contract, so it's been dormant for this whole transaction. What you did by that transfer
action is like creeping up to the Ranch in the dead of night, heaving one of your Unicorns over the pasture fence and then running away. You didn't actually sign your HWACCH up for any spa treatments there, you didn't leave your name or address or anything like that.
"Okay, okay," you say, "So, now I can go tell the Ranch about my drop-off?" Well, that would be like coming back in the morning, walking up to the receptionist and saying "Hey, that Unicorn that suddenly appeared in your herd overnight is actually mine. I'd like it back please." The receptionist will just look at you with a 😕 face, since there's no way to prove you're the owner of that Unicorn. The Ranch doesn't have security cameras monitoring that fence at night (Hey, I said state-of-the-art tools for getting HWACCHs to relax, not state-of-the-art security!), so they can't verify that. On the Ethereum blockchain, you could point out the transaction that you sent that did the transfer, but then you'd also have to prove that you own that sending address, and prove that you haven't done this before (waited for a new receptionist to come on duty, then show them the same transaction again and claim a second Unicorn out of the herd), and our receptionist just isn't cut out for that sort of verification (meaning, I didn't write that into the Ranch contract).
So, that was just a donation to the Unicorn Ranch herd (Thanks! 😉). So how do you actually get the Ranch to know about your HWACCH transfers? The best way is to let the Ranch do the transfer itself, so it can be fully aware of the transfer. But as I described earlier, you're the only one allowed to use the transfer
function to move your own HWACCH around. That's where the transferFrom
function comes in. The transferFrom
function takes an additional input variable compared to the transfer
function; you also have to tell the transferFrom
function the _from
address to withdraw HWACCH from. Now, that might make some of you start to hyperventilate, "Wait, then anyone can come grab my precious Unicorns without my knowledge?" Don't worry, I got your back on that one. I built in logic to the transferFrom
function that before it's allowed to go through, it first checks if the person sending the transaction has an "allowance" for the account they're trying to withdraw from. The "allowance" functionality is a part of the ERC20 standard for this very reason. You as a VIP HWACCH owner can use the approve
function to tell the HWACCH contract that some other contract is allowed to act as your proxy and transfer HWACCH on your behalf. You also set a limit on how much they're approved to transfer, so it's like being the rich parent who has millions of dollars in their bank account, but authorizing Junior to only be allowed to withdraw his $5 weekly allowance every week (kid's gotta' learn the value of hard work; no entitlement complex in my offspring! 🎩)
All right, so pull up the approve
function in the drop-down, and for the _spender
input, put the Unicorn Ranch address. For the _value
enter an amount equal to half the HWACCH you own. This "approve" action is your master switch to enable or disable the Unicorn Ranch contract being able to do anything at all with your HWACCH tokens. You could set it to a very low number to be timid, but the point of this is to pay attention and focus like you have skin in the game, so let's put some skin in the game! With this allowance set to half your herd size, that's the maximum amount that you could lose if you do something wrong. If you mess up and wind up donating your HWACCH to the Ranch instead of checking them in, the max you could lose is half your herd. In that situation, figure out what you did wrong, and then come back here to add some new allowance for the Unicorn Ranch contract and then continue the guide.
Go through the "Write" then "Generate Transaction" then "Yes, I'm sure" series again, to send that "approve" action to the network. Then switch to the allowance
function in the drop-down, put your own public address in the _owner
field, and the Unicorn Ranch address in the _spender
field, and click the "Read" button. It should show the amount that you just authorized the Ranch to be allowed. If that's all set, then it's time to start talking (sending transactions to) the Unicorn Ranch contract rather than the HWACCH token contract. To do that, you're going to need the ABI for the Unicorn Ranch contract, so head over to the 0x97E7ef310499bE2f97C392B8B16Ddd494Af73E22
page on Etherscan, go to the "Contract Source" tab and grab the ABI. Or, here's an abbreviated ABI with only the functions you'll need for these exercises you need.
That contract has a lot of functions; there's a lot going on here! This is the part of the process that is the most technical. This is like when buying a house, and the title agent sets the ream of paper in front of you, full of legalese and asks you to sign it. Just like wading through a contract in the real world, if it's well-written and you take your time reading it, it should be pretty understandable. I've posted the source code for this Unicorn Ranch contract on Etherscan, and we'll step through some of the critical pieces together. But unlike your title agent when buying a home, you trust your mortgage broker and title agent to not be screwing you over. On the other hand I've told you not to trust me as a default. So, if you don't understand what you're reading, just like in the real world you might hire an independent lawyer to interpret a contract for you, for a smart contract, you might need the assistance of a developer you trust to help you understand it.
The Unicorn Ranch booking logic is based around there being a handful of different types/categorizations of visits you can purchase for your beloved beasts. They're listed out in the VisitType
variable's declaration:
enum VisitType { Spa, Afternoon, Day, Overnight, Week, Extended }
So, six types of visits. And each visit type has an associated cost (per unicorn) and length (duration). You can use the visitLength
and visitCost
functions to determine what the current cost and length are for each of the six types. However, you may note that when using the visitLength
or visitCost
function, the input you need to give it to specify which VisitType
you mean is not the name of the type (e.g. "Spa", "Day", "Extended"), but rather its looking for a number. The number is the order of the type you want, as it appears in that VisitType
definition, starting with zero. So, "Spa" is 0, "Afternoon" is 1, "Day" is 2, etc. up to "Extended" is 5. And since I like you a lot (besties, remember? 💖), I've even put the "Spa" visit and "Afternoon" visits on sale, so they cost you absolutely nothing! (Aren't I the best friend ever?!)
Now, as you're querying the cost of longer visit types, the value that's returned is in wei, so don't freak out that it's in the billions or higher. And the length values are given in blocks (not hours or seconds or the like). The Ethereum protocol works to keep blocks being added to the underlying blockchain at a rate of one every 10 seconds. So, currently the length of a "Spa" visit is 720 blocks. Multiply that by 10 seconds/block and you get 7,200 seconds. Divide that by 3,600 (seconds in an hour) gives you 2 hours. So a Spa visit is 2 hours in length.
So, you can book a visit, of a specific type, which will transfer your HWACCH to the Ranch (you will lose possession of them!). However, after the specified length of time has passed, you will then be allowed to complete the booking using the completeBooking
function and get your HWACCH back.
Let's actually follow the code and see what it does:
Looking through the contract source, you'll find several bookFooVisit
functions (one for each of the visit types) as well as one bookVisit
function. The bookSpaVisit
, bookAfternoonVisit
and the rest of those type are convenience functions so that you don't have to memorize the "Spa" is 0, "Afternoon" is 1, "Day" is 2, progression. So, if we were to run the bookSpaVisit
function, we see that it calls the addBooking
function, passing along "Spa" as the type, and however many Unicorns we sent along for the booking. So find in the contract where the addBooking
function is, which is a much more complex function.
The addBooking
function first checks to see if you sent along enough ether to cover the current cost per unicorn you are attempting to book. Since Spa visits are free, we're not going to worry about that. Next it makes a call to the HWACCH contract, and attempts to use the transferFrom
function to move your Unicorns to its own address:
ERC20Token cardboardUnicorns = ERC20Token(cardboardUnicornTokenAddress);
cardboardUnicorns.transferFrom(msg.sender, address(this), _unicornCount); // Transfer the actual asset
Those two lines of code tell the running code that the thing at cardboardUnicornTokenAddress
is an ERC20 Token contract, and then it executes transferFrom
, using msg.sender
(the contract that sent the transaction that's currently being executed) as the source account, and address(this)
(this contract's own public address) as the destination. The HWACCH contract handles all the checking to see if the Ranch is authorized for this, and if there's a problem (not enough allowance, or you don't own enough HWACCH to make the transfer, etc.) it will throw an error and the execution will stop right there and go no further.
If that transfer was successful, the Ranch contract continues on to record the booking.
visitingUnicorns = visitingUnicorns.add(_unicornCount);
uint expiresBlock = block.number.add(visitLength[uint8(_type)]); // Calculate when this booking will be done
// Add the booking to the ledger
bookings[msg.sender].push(Visit(
_unicornCount,
_type,
block.number,
expiresBlock,
VisitState.InProgress,
0,
0
));
First it updates its master record of how many unicorns are currently checked-in at the Ranch (visitingUnicorns
), then it figures out when this booking will be done (expiresBlock
is the current block (block.number
) plus the length of the specified visit type), and adds that as an entry to the bookings
record for the public address who sent the message (msg.sender
). The function wraps up by sending out some events about the new booking, so other contracts that want to be notified when stuff happens on this contract have a means to do so.
Okay, so that's how you get your HWACCH into the Ranch and have such an action be logged by the Ranch (part of its bookings
listing). So, how can be we sure that we'll be able to get them back out again? Well, that would be the logic of the completeBooking
function:
The completeBooking
function requires an input value of an _index
, which is the sequence order for the booking of yours you made with the Ranch (the first booking you make at the Ranch will be index #0, the next will be #1, then #2, etc.).
require(bookings[msg.sender].length > _index); // Sender must have at least this many bookings
Visit storage v = bookings[msg.sender][_index];
require(block.number >= v.expiresBlock); // Expired time must be past
require(v.state == VisitState.InProgress); // Visit must not be complete or repossessed
This is the initial logic that determines if you're able to proceed with the return of your well-rested Unicorns. It first makes sure a booking exists at the given _index
for you, and then looks up the booking in its main ledger (bookings
). If the expired time has passed, and you haven't already resolved this booking, it then proceeds.
Hey now, what's this? Next in the code is a comment saying "Determine if any births occurred"! 👶
Yes, those HWACCH can be quite the frisky lot (strap a horn to a horse and suddenly they're strutting around like they're the best Sneeches on the beaches), and yes, while we at the Unicorn Ranch are fairly attentive, if you leave enough unicorns with us, for an extended period of time, odds are some of them will match up, and you'll end up going home with more than what you started with! 💏
The logic for determining how many births occurred is:
// Determine if any births occurred
uint birthCount = 0;
if (SafeMath.sub(block.number, v.startBlock) >= birthBlockThreshold) {
if (v.unicornCount >= 100) {
birthCount = uint(birthPerHundred).mul(v.unicornCount / 100);
} else if (v.unicornCount >= 10) {
birthCount = uint(birthPerTen).mul(v.unicornCount / 10);
}
}
if (birthCount > 0) {
uint availableUnicorns = cardboardUnicorns.balanceOf(address(this)) - visitingUnicorns;
if (availableUnicorns < birthCount) {
birthCount = availableUnicorns;
}
unicornsToReturn = unicornsToReturn.add(birthCount);
}
What that does is look to see if the Unicorns have been at the ranch longer than the birthBlockThreshold
, and if so, if there's at least 10 unicorns that were checked in, you'll get some amount added for every group of ten (birthPerTen
), or if the herd was more than 100, an even bigger ratio (birthPerHundred
). The contract then checks its own supply of HWACCH compared to how many are actually checked-in on some sort of booking (visitingUnicorns
) and if there are extras, then those must be the new babies! They're added to the total to return to the address running the current transaction.
// Update the status of the Visit
v.state = VisitState.Completed;
v.completedBlock = block.number;
v.completedCount = unicornsToReturn;
bookings[msg.sender][_index] = v;
// Transfer the asset back to the owner
visitingUnicorns = visitingUnicorns.sub(v.unicornCount);
cardboardUnicorns.transfer(msg.sender, unicornsToReturn);
Then there's a bit of cleanup: the booking itself is marked as Completed (so you can't check out again, and withdraw more HWACCH!), and then it updates the master number of how many unicorns are currently checked-in overall, and uses the transfer
method to send the appropriate number of unicorns back to their previous owner. The Ranch doesn't need to use the transferFrom
method here, since the HWACCH that's being returned is from the pool that's currently owned by the Ranch, and it's allowed to spend its own HWACCH.
Okay, that's it; that's the core mechanics of this contract! Do you understand them? Do you trust them? Well, if you trust Etherscan's reporting that it verified the source code is accurate, then you can be assured that is the logic that will be followed when you do this transaction.
So, let's do it! Jump over to MyEtherWallet again, pull up the bookSpaVisit
function, set "3" for the _unicornCount
(a few, so they'll have someone to talk to while they're getting their hair done), and click the "Write" button. Since we know the cost of this type of visit is zero, we still don't need to send any ether along with the transaction. Click "Generate Transaction" then "Yes, I'm sure" series again, to send that booking request to the network. If on the "Generate Transaction" step MyEtherWallet is trying to set the Gas Limit to "-1", that's an indication that MyEtherWallet thinks the transaction is not going to complete successfully. That likely means you didn't do the "approve/allowance" step properly, or you don't have enough HWACCH in your wallet to send that many. Go fix that and try again, and MyEtherWallet should properly compute a positive-number gas limit for you.
Once that's confirmed, switch to the getBookingCount
function and enter your own public address in the _who
field. Click "Read" and it should show a result of "1" (you have one booking, but its index is 0. If you had 2 bookings, they would be index 0 and 1). Use the getBooking
function to get the details about your booking at index #0. It should come back showing your 3 unicorns booked with a _type
of zero (which is the "Spa" type), and it will give you an expiresBlock
of when you can come back to pick up your well-groomed beasts.
That's it, you're free! Three less hungry mouths to feed! At least for two hours. So, what are you going to do with your free time? Go grab a drink and post a comment below with your expires block (so we all can count down with you) and a selfie of you enjoying your relaxing beverage 🍹
Well, now we've got two hours to kill. I could just tell you to go away and come back again. But what sort of teacher would I be if I did that? No, I've got something fun to fill the time in interim! And by "fun" I mean "way to make your life easier". Remember back in the previous guide, where you sent just raw ether using the MyEtherWallet tool? Remember that it was labeled "Send Ether & Tokens". Well, let's explore that second half; HWACCH is a token, so can MyEtherWallet make our life easier than having to copy and paste ABIs all day? Head over to the MyEtherWallet interface and go to the "Send Ether & Tokens" tab. Unlock it with your private key, and instead of looking at the left half of the screen, look at the right side. Underneath the "Account Balance" widget that shows your ETH balance, there's a "Token Balances" widget. If you click the "Show All Tokens" button, you'll be greeted by a slew of zeroes as MyEtherWallet lists out all the popular tokens that it's aware of, and shows you how many you have (the Ethereum Foundation "Unicorn" token is in there, BTW!). But HWACCH isn't listed there. Click the "Add Custom Token" to inform MyEtherWallet about those amazing new "unicorns" that you own. Enter the "Horse with a Cheap Cardboard Horn" token address in the "Address" field (0x69b5357D893fcE82248E83CCd9B0871F5D5d9461
), "HWACCH" for the token symbol, and zero for the Decimals (don't try dealing in fractions of a unicorn; my crazy cousin Lenny wanted to try that but I put a stop to it), and click "Save". The interface should then update to show "HWACCH" under the "Token Balances", and show your proper herd size! Because HWACCH is an ERC20-compliant token contract, MyEtherWallet knows to look for the balanceOf
function to query how many you have, so do that behind-the-scenes for you. It can also use the transfer
function for you, so you don't have to do that custom: now that you've added HWACCH to the interface, on the left half of the form, under the "Amount to Send", the "ETH" after the amount is now a drop-down. Click it, and you can switch it to "HWACCH". Now you can enter an amount of HWACCH to send and a destination address, and it will work just like sending ether to someone. Neat, huh? I didn't have you do it this way initially, since now you know what MyEtherWallet is doing behind-the-scenes rather than just having to trust it knows what its doing.
4. Welcome home!
All right, has it been two hours yet? More specifically, has the indicated block expiration number passed? We can use Etherscan to check if that's the case by heading to the home page of Etherscan. On the home page, Etherscan lists the most recently-added blocks to the Ethereum blockchain. Each block is given a number that represents its height in the whole chain. Check the label on the first-listed block, and see if it's bigger than the expiration block you looked at earlier. If it's past that time, you can pick up your Unicorns!
Fire back up MyEtherWallet, check that the Gas Price and Node are set correctly, head to the "Contracts" tab, enter the Unicorn Ranch address and ABI, and then pick completeBooking
from the drop-down list, and put "0" for the _index
value. Write, sign, and transmit that function, and welcome your HWACCHs home! Go check your balanceOf
on the HWACCH contract to verify the 3 have returned. And on the Unicorn Ranch contract, use the getBooking
information to look up the details of that index #0 booking of yours, and you should see the _state
value updated to "1" (indicating "Completed").
There you go; the contract did as it was supposed to and returned your tokens to you. ✨
5. Profit
Okay, so that was fun exercise. But now that you've worked through this stirring tale of horses and cardboard, is there any continuing value in HWACCH unicorn tokens? Well, as you can see from the fact that you can withdraw more unicorns than you put in if you meet the "birth" logic. So this contract acts kind of like a Certificate of Deposit; you agree to lock up your asset for a certain amount of time, and after that time, you can withdraw it, along with some interest. So that's one way you can use this contract for profit. Note that the "expiration block" is just the minimum time you must leave your unicorns at the Ranch. You can leave them in there longer. And when you do complete the booking, the birth calculations use the real time the unicorns have been at the Ranch, not the length of time associated with the visit type they were there for. Go check out the birthBlockThreshold
to get the number of blocks you'd need to leave the Unicorns there for in order to get some births to happen. Divide that by 360 to get the number of hours you'd need to leave the unicorns there for births to happen. Try sending more than 10 unicorns on a new booking (pick a different type of booking to mix it up!), and leave them there for at least that number of hours. Check that the current block number is greater than startBlock
+ birthBlockThreshold
, and then withdraw your unicorns to earn your profit!
So, there's a financial incentive for you to come patronize my Ranch by leaving your unicorns with AJ and me. How about another incentive? One that works for people who don't have any HWACCH at all? Well, as I've been running this Ranch for a while now, we run into the unfortunate situation where someone drops off their HWACCH for just a Spa visit, and then goes off to tour the world, and doesn't return for months! And I'm stuck with the bill for all that Unicorn Chow! So I as a Ranch owner want to set a maximum amount of time after your booking is complete that you can claim your HWACCH back. So, you may have noticed there's one other set of functions that allow you to interact with a booking. There's a reposessionBlocks
value, and a repossessBooking
function. The repossessBooking
function takes an owner address and booking index number and checks to see if that booking has been left uncompleted for more than repossessionBlocks
(currently set for 43,200 blocks, which is 5 days). If so, we decide that owner is not coming back, and the unicorns that were checked in are considered a donation to the Ranch! So, that helps me as the owner, but that means I have to keep my eyes out for bookings that are past their repossession block limit, and trigger the repossession (remember, a contract can't act automatically on its own. A human needs to trigger it with a transaction). So, my lovely Unicorn Ranch business can accept bookings automatically on my behalf, and unicorns can be picked up by their owners automatically with no intervention from me. But in order for me to process repossessions, I need to be manually doing that? No thank you, I plan to be on the golf course! So, in order to solve that situation, I added a financial incentive into the repossession process 💰. Note that anyone can trigger the repossession of a booking that's past its threshold (not just the Ranch owner). As part of sweeping the HWACCH into the Ranch's coffers, the contract calculates a bounty for the person to triggered the repossession, and gives them a cut of the HWACCH that was repossessed. So, if you want to be a bounty hunter, there's HWACCH in it for you! So you could just monitor the Unicorn Ranch contract, watch the incoming transactions, and mark on your calendar when those bookings will be up for repossession, come back and see if they got claimed or not, and grab a bounty for turning in the ones that didn't. You could also do both; book your own unicorns on visits that are long enough to create births, and do some spying on other people's bookings to see if they forgot about them and claim a bounty on them.
And you can see now why you might want to pay for a longer booking: if you only pay for a "Spa" visit, but intend to leave them there long enough to generate births, you also need to be mindful you don't leave them too long, lest they be eligible to be repossessed. Take a look at the math for that:
- Birth wait = 43,860 blocks (almost 122 hours)
- Spa length + Repossession wait = 720 blocks (2 hours) + 43,200 blocks (120 hours) = 43,920 blocks (122 hours)
So, note that the birth wait is just 60 blocks short of the repossession limit of a Spa visit. That means you only have a 10 minute window in which you can claim your unicorns plus extra births, before it's then also eligible for someone to trigger a repossession on you! Possible, but a bit of a gamble. That situation may be an opportunity to use that increased Gas price slider, to make sure you get your transaction included in the blocks you want it to! Or, use one of the other booking types that are a bit longer, so you have a longer margin between when the birth wait is hit before the repossession limit is hit. So, when you're looking at it as a financial investment, the relationship between the cost of a visit type and the length of the visit type makes sense. If you're trying to hit that perfect sweet spot, where you'll be able to claim those extra births, but not get repossessed, if you want a bigger window of time to hit that target, it will cost you more. The two longest visit types are even longer than the birth wait time, so as soon as the booking is done, you can complete them and get the extra births, giving you a full five day window to avoid repossession.
- Spa Visit: 720 blocks (2 hours) visit length, gives a 10 minute reclaim window
- Afternoon Visit: 1,440 blocks (4 hours) visit length, gives a 2 hour reclaim window
- Day Visit: 2,880 blocks (8 hours) visit length, gives a 6 hour reclaim window
- Overnight Visit: 8,640 blocks (24 hours) visit length, gives a 22 hour reclaim window
- Week Visit: 60,480 blocks (7 days) visit length, gives 5 day reclaim window
- Extended Visit: 120,960 blocks (14 days) visit length, gives 5 day reclaim window
Now compare the cost to leave a unicorn at the Ranch with the cost to assemble them in the first place. The current rate to assemble a new unicorn is 1 finney (0.001 ether). The most expensive visit ("Extended") is 0.007 finney (0.00007 ether). And you need to send at least 10 unicorns to trigger any births at all. So, if you send 10 unicorns on an Extended stay at the Unicorn Ranch, you'll spend 0.07 finney to do so, and in the end will get one additional unicorn. So, instead of paying 1 finney to mint a new one, you only pay 0.07 finney; a massive discount! But to use that discount you need to remember to come back and claim it at the right time. And if you pick a lower-cost visit type, it's an even bigger discount to earn yourself some additional unicorns.
So, while the "Afternoon" visit type is on sale for zero cost, might be worth utilizing...! If you do use one of the longer-length visits, be sure to include enough ether to cover the cost per unicorn that you're sending. If you don't send enough, the transaction will abort (which will use up all the gas you sent with the transaction as a penalty). If you send too much, there's no refund built-in; the Ranch will happily accept your over-payment! 🤑
So, there's means to turn your HWACCH into more HWACCH (possibly at zero cost, if you're willing to put in some effort to make the target window), but why would you want to amass a boatload of HWACCH? Currently, you can't do much of anything with them beyond these guides. But being an ERC20 token, HWACCH can be interacted with by many other contracts on the Ethereum blockchain. And who knows, in the future I may write a contract that can only be used by HWACCH-holders. Or anyone else could create such a contract; you don't need me for that!
6. Where do we go from here?
That's it. That's the basics. You now have practiced:
- Creating a private key/wallet/account
- Purchasing ether
- Sending ether to another address
- Reading contract source code
- Reading contract state values
- Sending custom transactions to an address
- Sending ERC20 tokens to another address
- Validating signed messages from other addresses
- Sending tokens and ether in a single transaction
- Monitoring the height of the blockchain and timing of transactions
We've done this whole guide relying heavily on Etherscan and MyEtherWallet, though we also touched on the fact that those are not the only tools that provide those services. For additional practice, go back to the beginning and do the whole thing over again, but don't use Etherscan or MyEtherWallet at all; find another block explorer and another transaction tool to use and see if you can figure it out.
I said in the first guide that I'd come back around to hardware wallets: Hardware wallets are great devices that manage your private keys for you in such a manner that it's impossible for them to leave the device. The device is smart enough to know how to do the private key signing of messages/transactions, and when it's USB-connected to a computer/phone, apps on the computer/phone can request the hardware wallet do the signing and send the signature back, and that's the only interaction it can do, so the private key can never be read off the device. It means that you just have to protect the physical device (keep it in a strongbox or bank safe deposit box. I steered you away from them to start with partly because they're expensive (around $100 each), so possibly not affordable for everyone, and not strictly necessary for interacting with cryptocurrencies. The second reason is to teach you how to do what it is doing. You going through the process of generating your own private key and signing transactions with it, you can now visualize what a hardware wallet does when you ask it to sign a transaction for you.
These basics should allow you to jump in on interacting with any smart contract on the Ethereum network. If you're looking for something more advanced to do, look up some tutorials on how to set up your own Parity or Geth client; that will turn your computer into an active node in the Ethereum network, and can then be used to make sure that MyEtherWallet is being honest (you can point it at your local Parity/Geth node in the "Node" drop-down, so the true blockchain data will come directly from your local server).
Now that you know how to interact with smart contracts in general, here's some other projects to check out:
- Ethereum Name Service (ENS) (documentation): In the same way that a DNS service changes a domain name (e.g.
example.com
) into an IP address (e.g.93.184.216.34
), ENS strives to do the same thing for Ethereum, changing domain names with a.eth
suffix into Ethereum addresses. Etherscan is integrated with this service; you can look up an address by its ENS domain (try looking upunicornRanch.eth
,unicornsRus.eth
, andcardboardUnicorns.eth
to find some familiar friends...) - MoonCat Rescue: Save the MoonCats! This project is a fun way to explore another way of generating tokens on the Ethereum blockchain. The HWACCH tokens are generated by paying Ether for them, but MoonCats need to be "searched for" (Proof-of-Work "mining" for them) instead.
So, that said, here's one more challenge for you. I created a contract at 0x2F490751589DB68f3C406bF9c14C95Ec7fa26840
where you can sell back your HWACCH to me. However, you first need to prove you completed this guide in order to be eligible to have your tokens refunded. You're going to have to trigger the claimReward()
function first, which if you can get it to execute correctly, will let you sell back up to 100 HWACCH (using the sell
function). Take a look at the source code for the claimReward
function to figure out what you need to do to verify that you are worthy of the reward 🏆.
If this guide series has been useful to you, please give it an upvote here on Steem, and/or send along an ether tip to any of my contracts. I may also do an extra, bonus guide about writing an app that interacts with the Ethereum blockchain (you saw how MyEtherWallet has logic build in to check the balances of ERC20-adherent contracts; given the logic of the repossession bounties on the Unicorn Ranch, one could write a web application that made it easier to find and claim repossess-able bookings, without having to bounce through different ABI transactions), but that would be more for other developers, and be not of as much interest for general users. You may have noticed that there's a lot more functions on my contracts than were used by this guide; all the other functions give me as the administrator the ability to tweak numbers and contract addresses. That means you have to trust me to not fiddle with the numbers too much, but it also allows me to change ownership of the contracts, where I could hand over ownership to another individual, or to an organization/committee who decided whether things need adjusting by votes of their membership! And, as I mentioned at the end of the last section, more contracts could be written to allow HWACCH-holders to do more things with their tokens, which I may do as well!
Thanks for sticking with it to the end! As a reward for getting here, one more word to the wise: don't send your HWACCH to the Ranch for an "Afternoon" visit; it's a trap! (Now that you know that, see if you can figure out why...) If I find any errors or updates needed for this guide, I'll post them below in a comment. Have fun surfing the "Web 3.0"! 🚀
Excellent post, enjoyed reading it throughout! I have written a basic report for Ripple if you anyone is interested in learning more about investing in this crypto: https://steemit.com/cryptocurrency/@calovera/introduction-to-crypto-analysis-learn-how-to-trade-ripple-xrp
Since the writing of this article, the structure of the JSON message signatures on MyEtherWallet changed slightly. Here's the updated signature data structure that should work using the current version of that website:
{ "address": "0x6954d0255cfed71d55ad8b371b4170b8bf7709dc", "msg": "I am Midnight426 on Steem and Twitter, I am MidnightLightning on GitHub, and I'm the owner of the Ethereum address 0x6954d0255cfeD71d55Ad8b371b4170B8BF7709dC, which signed this message.", "sig": "0xf515a622eff1f20e980216bc67306368c68685d84c15e6af6e8876c4de4a787d193c63cc786198ec1fec5932e54377764f3241fff03ecb805acef67d5844894e1b", "version": "3", "signer": "web3" }
Updating again! The technology of signing messages via Ethereum hasn't changed (needs a private key, and results in a long hexadecimal data "signature"), but different organization structures keep evolving on top of them. Here's that same message signed using the Ethereum Attestation Service (EAS): the whole signature is encoded into the URL of this link:
https://easscan.org/offchain/url/#attestation=eNqlkktu3DAMhu8y66Dgm9Qyk2kuUXShB3WAogV6%2FNIKBkUXXcWGbJqifn6k%2Be0GX8huLzesBb9fkcDf%2BX7vRPKVZps87aH93fgBOVCD3lLDTzBAOvShLIoe20cOA9jad5%2FYdfQxZEr24OUauZd2REdOzBTBfUQEfDCunWOP4CQOEVorudQDhmXuSTJWRGMO6gF7eSq0lmjZS4Ti0rGmsoBU586H41J9XTHYcQg63OP%2B7g5tvZ2kZEyZY%2BHC0dtayGOuLFqyHThW0zGCNq%2FRZCSpdV3Miwlxru3ziGyNEYOQcrtmxiyuWAE82SdwgmKLBgq0NAs3SZB6TxS12XdeIreXggtGawYvcBw%2Ff%2FzKj%2B5%2B5qLPHYcqvBEY2iKQVXhiWU%2B3cGFhYqvdbUmg7GJa9zrxaVI%2Bcbfmcu040SyN%2F6rJfFrHl%2BZPZTkaEq52NJ7qpeWXUp0I0yu6suXJdJ20vzuiH5ZTrSehmJxvdiZg8GDjxjXFJgxVmbIam5mKVEjFXx653mHEfHxUPcCyQK6BJTG%2B5ICrsmpOsRZRVDVsUTafCovwoj9E7cpt64OimLxo898%2FcKt5oDMIsrGNZShQoGtK102yWvNusFsDT2hss7jSBu6APsV8NKieI47b9z80COwq
That's less readable as a human, directly, but it adds several additional bits of data including the time the person signed it, whether the signer is allowed to undo their signature ("revoke" it), and what the purpose of the message is ("Make a Statement" in this case)