In the end of November 2017 a rather weird altcoin saw the light in the Bitcon Era space - Monero Gold, an ERC20 Token. On November 29th, early in the morning the Smart Contract was deployed.
Now, at this point anybody that knows about Monero has to get alarmed, right? Monero, the most prominent fork of Bytecoin, the result of years of work of a very dedicated community, probably the most anonymous currency in circulation today - in the form of an ERC20-Token?
ERC20-Tokens are basically Smart Contracts deployed on the Ethereum Blockchain that enable anybody to create their own currency within an hour and no prior knowledge. Don't believe me? - I built my own "B33R"-Token with this handy tutorial and learned mostly one thing - it is shocklingly easy to do. The great advantage of the ERC20-standard is that anybody can build wallets and everything you need for your own coin ecosystem very easily, as it is - the name spoils it - standardized.
Now, the "easy"-part is actually a great feature of the ERC20-tokens nature. It's easy to create a token that anybody connected to the Ethereum blockchain can send and recieve. Building in-game currencies or local payment systems that are 100% verifiable and secure can now be deployed by anybody that knows the difference between an integer and a string.
Now back to the fact that Monero Gold came as ERC20-token. This doesnt make any sense, whatever angle you look at it. Monero itself differs vastly from any other currency, uses its own hashing algorithm, is super-private, has nifty features like ring-signatures and so on. An ERC20-token doesnt have any of these features. But wait - ERC20-tokens are an important tool for ICOs. Let's say a team wants to develop their own transaction system and lacks the funds to do so. They can have an ICO, give out ERC20-tokens and later, when their system is up and running, exchange the tokens back for the real deal. Maybe the Monero Gold makers just wanted to do that? Yes, maybe, but they probably should have mentioned that SOMEWHERE. Which they didnt.
So, just by logical thinking, immediately after the launch it is extremely obvious that this token has no value and also has no affiliation with Monero. Everything screams scam, seconds after the contract has been deployed.
But - nevertheless - on February 2nd, only two months after its birth, this coin had reached a total 24h-volume of 214.000$ and a price of 0.17$. Or in other words, a total shitcoin, nothing more than an ERC20-token with some bad, bad, BAD Marketing (this is the official "dev"-team. I am dead serious -> Monero Gold Dev Team) reached a market cap of over 4 million dollars.
Until this point, it looks like a normal shitcoin development, elegantly executed with enough gullible people backing it.
BUT WAIT.
It gets better, so much better. In short, the owner of the contract executed an integer underflow and created a couple trillion units of his own currency, and nobody saw it coming.
Let's go back to the ERC-20 tokens. So these tokens are basically smart contracts deployed on the Ethereum blockchain, right?
Let's take a look at the contract that was deployed for Monero Gold:
pragma solidity ^0.4.11; contract MoneroGold { string public name = "Monero Gold"; // token name string public symbol = "XMRG"; // token symbol uint256 public decimals = 8; // token digit mapping (address => uint256) public balanceOf; mapping (address => mapping (address => uint256)) public allowance; uint256 public totalSupply = 21000000 * (10**decimals); address public owner; modifier isOwner { assert(owner == msg.sender); _; } function MoneroGold() { owner = msg.sender; balanceOf[owner] = totalSupply; } function transfer(address _to, uint256 _value) returns (bool success) { require(balanceOf[msg.sender] >= _value); require(balanceOf[_to] + _value >= balanceOf[_to]); balanceOf[msg.sender] -= _value; balanceOf[_to] += _value; Transfer(msg.sender, _to, _value); return true; } function transferFrom(address _from, address _to, uint256 _value) returns (bool success) { require(balanceOf[_from] >= _value); require(balanceOf[_to] + _value >= balanceOf[_to]); require(allowance[_from][msg.sender] >= _value); balanceOf[_to] += _value; balanceOf[_from] -= _value; allowance[_from][msg.sender] -= _value; Transfer(_from, _to, _value); return true; } function approve(address _spender, uint256 _value) returns (bool success) { require(_value == 0 || allowance[msg.sender][_spender] == 0); allowance[msg.sender][_spender] = _value; Approval(msg.sender, _spender, _value); return true; } function setName(string _name) isOwner { name = _name; } function burnSupply(uint256 _amount) isOwner { balanceOf[owner] -= _amount; SupplyBurn(_amount); } function burnTotalSupply(uint256 _amount) isOwner { totalSupply-= _amount; } event Transfer(address indexed _from, address indexed _to, uint256 _value); event SupplyBurn(uint256 _amount); event Approval(address indexed _owner, address indexed _spender, uint256 _value); }
A 4 million dollar scam, executed in 68 lines of code.
When you skim the code, the basic attributes of the tokens can be seen immediately.
string public name = "Monero Gold"; // token name string public symbol = "XMRG"; // token symbol uint256 public decimals = 8; // token digit mapping (address => uint256) public balanceOf; mapping (address => mapping (address => uint256)) public allowance; uint256 public totalSupply = 21000000 * (10**decimals); address public owner;
So, there is a token, it's called Monero Gold, the symbol it XMRG, it has up to 8 decimal points and there is a total supply of 21.000.000 XMRG. Nothing special here, my B33R-Token looks exactly the same.
Now, ERC20-tokens offer a variety of features. For example, you can create tokens of which you can produce a basically infinite number AFTER the contract was deployed. (Useful for example for in-game currencies and a rapdly growing userbase)
But this would be to obvious, as anybody reading the contract would not invest into a currency whose supply is basically unlimited.(But honestly, if you consider buying the Monero GOLD ERC-20 token, I doubt you know what a smart contract is.)
You can also include a function to "burn" tokens. This gives you the chance to remove a certain amount from the circulation after you have initially set-up the contract. This makes sense - unsold tokens can be burnt after the ICO and therefore not dillude the shareholder value.
The creater of the Monero Gold contract also included a Burn function, but a very special one:
function burnSupply(uint256 _amount) isOwner { balanceOf[owner] -= _amount; SupplyBurn(_amount); }
This exploits the fact that solidity itself has no protection against accidental or malicious over/underflows. An integer like this can only hold 256 bits and is unsigned. (u_int) An unsigned integer can only take a positive value. And here is the whole exploit. Instead of adding money to his balance (which the owner couldnt have done), he burnt enough to cause the integer value to go below 0. Which it cant. It therefore jumped straight back up to the highest possible value possible, in case of an int256 that is 1.15792089237316E+69, or 1.157.920.892.373.160.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.
So with this exploit, the owner created more units of money than there are sandgrains on earth and immediately began selling them on various exchanges. With this insane inflation, Monero Gold quickly lost any value and is now worthless.
The lessons to learn from this?
- ERC-20 tokens are not hard to create or to exploit.
- Don't buy anything that carries the name of a well-known coin and has a "Gold", "Diamond", "Plus", "Dark", "Cash" or just about anything stuck to it UNLESS you know exactly what you are doing. In a market where there are already coins for every single imaginable use-case, the only reason to use a big name is trying to get publicity.
- Someone should write a script that automatically checks newly deployed smart contracts for this and similar exploits.
- I should really get better at Solidity, there is seemingly a lot of money to be made.