Scammy Abilities Found In The Bitfinex LEO ERC20 Contract Code

Bitfinex LEO ERC20 token owner can not only print or mint unlimited new tokens but also they can delete anyone's coins including but not limited to the ones on centralized or decentralized exchange, hot or cold storage, hardware or software wallet, and/or paper or brain wallet.

It’s very well known that smart contracts can be tricky. Non-technical people get tempted to buy an ERC20 token based on the hype level, without any prior knowledge regarding the quality of the token and the safety of the token they are buying.
Bitfinex, one of the largest crypto exchanges in the industry, has issued a token called LEO. This token allows the entity that controls it to print or mint unlimited new tokens, also it allows them to delete anyone's coins including but not limited to the ones on centralized or decentralized exchanges, hot or cold storage, hardware or software wallet, and/or paper or brain wallet.
Don't get fooled, buying an ERC20 does not mean your assets are really yours! This is not the first time I’ve exposed such a smart contract. Just last week we published on Cointelligence a report about a similar smart contract that allows the same functionality, check out our review about WHEN Smart Contract.

Does LEO ERC20 contract enable multi-billion dollar scam and/or fraud?
We leave it up to you to decide, now let’s dive deep into the LEO Token.

Introduction

LEO is an ERC20 token introduced on May 10, 2019 by iFinex Inc. in their announcement. You can find the LEO Whitepaper here. Although we were unable to find a GitHub repository, their token contract code was verified on Etherscan. We used the verified Etherscan code for LEO, LeoController, and TokenFactory to test and deploy a copy of this token in Ropsten testnet.
LEO Token - The ERC20 token issued by Unus Sed Leo Limited, a subsidiary of iFinex Inc.
Controller - The controller contract enables the owner to transfer, approve, issue, burn, and change the controller itself. Please also note that although the “0xf17ebb3a24dc6d6b56d38adf0df499c1cd9e5672” contract currently “controls” LEO ERC20 contract, the “controller” can be easily upgraded or changed to any address at any time by the owner thus enabling them to pretty much do anything with the LEO token.

LEO Controller contract

LEOController contract: The owner can change the “Controller” of LEO ERC20 contractLEOController contract The owner can change the Controller of LEO ERC20 contract

 

The LEOController contract owner can change the “controller” at any point of time and set this to any wallet address they control.

  • By calling the function “upgradeController” on line 698 and entering any wallet address of their choice.
  • Once the above transaction is confirmed, the entered address will become the new “controller” of LEO ERC20 Contract.

LEO contract: The owner can burn your tokens and mint unlimited new tokensLEO contract The owner can burn your tokens and mint unlimited new tokens

 

How could the LEO owner keep minting tokens forever?

As explained before, once the controller address is changed to a wallet address (or even a new smart contract), they could simply call the function “generateTokens” on line 460.
Parameters

  • _owner → The wallet which will receive the newly minted LEO tokens.
  • _amount → The amount of tokens to “print” which will go to the above address.

Note - The LEO whitepaper does not mention what the maximum token supply is and this contract allows them to keep on minting LEO tokens as we were able to “print” a quadrillion LEO tokens on a testnet using their code.

How could the LEO owner delete someone else’s tokens?

The function “destroyTokens” on 477 enables the LEO controller wallet to burn anyone’s LEO tokens including but not limited to the ones present in a centralized or decentralized exchange, a hardware or software wallet, hot or cold storage, and/or a paper or brain wallet. It doesn't matter where your coins are, they can delete your coins if they want to. As simple as that.
Parameters

  • _owner → The wallet from which the existing LEO tokens will be burned.
  • _amount → The amount of tokens to “delete” from the above-mentioned wallet address.

Further Evidence

We copied the exact same code for the LEO ERC20 token, controller, and factory to deploy the following contract on the Ropsten testnet.
Wallets/Addresses

  • Sender Address: 0x58FA58089956c5cba21d9f61434B1902F8121b32
  • Randomly generated address: 0xada183F6Ff6E7805EE5bDA701d40958858FeE548

First we changed the controller from the Sender address to a copy of “LEOController” to see if we could again change the controller back to the Sender address using the function “upgradeController”.

Steps

  • Token Factory Deployed
  • LEO Token Deployed
  • LEOController Deployed
  • Checked who actually is the “controller” on LEO token contract: 0x58FA58089956c5cba21d9f61434B1902F8121b32.
  • Changed the controller using the function “changeController” on LEO contract to previously-deployed “LEOController” contract
  • Confirmed the controller was actually changed to the smart contract address.

At this point, our testnet LEO contract is exactly similar to LEO ERC20 contract in the following ways

  • The controller of LEO contract is a smart contract.
  • The controller code in testnet exactly matches with the one in mainnet.

Now, we’re trying to determine:

  • If we can burn or destroy someone else’s LEO tokens by first changing the controller.
  • If we can issue an insanely large quantity of LEO token to see if there is a cap.

Steps

  • Although, at this point, we knew that it wasn’t possible for the owner to change the controller on the “LEO” contract using the function “changeController”, we still intentionally sent that transaction for it to revert or fail. Failed
  • We went to “LEOController” contract and used the function “upgradeController” to change the controller of the controlled smart contract, i.e. LEO, to the Sender address again. Succeeded

Note - that we changed controller from Sender to a smart contract and then again back to the Sender because we wanted to show you that it is quite easy for us to change the controller in a testnet (and for them in the mainnet).

Issuing Tokens

Since now the Sender is the controller of LEO contract again, it can access the LEO contract functions “generateTokens” and “destroyTokens”. We generated a random wallet address “0xada183F6Ff6E7805EE5bDA701d40958858FeE548” to send some insanely huge amount of LEO tokens 1,000,000,000,000,000,000,000,000,000,000,000,000 (one undecillion) LEO transferred.

Burning Tokens

We wanted to determine if we (the Sender) could delete or destroy tokens from the random address 0xada183F6Ff6E7805EE5bDA701d40958858FeE548 we previously generated.
In the above transaction, we successfully burned/deleted/destroyed 10,000,000,000 (ten billion) tokens from someone else’s wallet or an address we did not own.
You can see that the address “0xada183F6Ff6E7805EE5bDA701d40958858FeE548” now has a balance of 999,999,999,999,999,999,999,999,990,000,000,000 (nine hundred ninety-nine decillion, nine hundred ninety-nine nonillion, nine hundred ninety-nine octillion, nine hundred ninety-nine septillion, nine hundred ninety-nine sextillion, nine hundred ninety-nine quintillion, nine hundred ninety-nine quadrillion, nine hundred ninety-nine trillion, nine hundred ninety billion) testnet LEO tokens only.

 


Contracts Comparison

LEO Original Testnet Diff
MiniMeTokenFactory Original Testnet Diff
LEOController Original Testnet Diff

TLDR: How does this affect me?

Paolo Ardoino, CTO of Bitfinex, replied to our tweet which outlines this issue, stating:
“For security and future proof reasons we left the ability also to upgrade the Token Contract. That's really a key feature for a contract that might live lot of years. Minting more tokens would just not make sense for Finex... like shooting our foot. “
We not only loved his tweet but would also like to publicly thank him for his reply, because we believe this is how we can hold ourselves accountable and help guide this industry towards a better future.
Now let’s get back to business! Make a good note that smart contracts are designed to be trustless. Bitfinex breaks trust here by putting a backdoor here, which gives them a ticket to cheat whenever they need to, with an unfair advantage over people like you and me. Repeatedly throughout this whole article, the only fact we have pointed out is their ability to mint any number of (or unlimited) LEO coins at their discretion and delete any wallet’s coin, now or in the future.
To summarize and simplify everything for our non-technical readers, we don’t deny or question the smart contract’s ability to be upgradeable. The problem here is not technical but philosophical. If you are okay with Bitfinex being able to do what they can do with LEO, we understand that as well and respect your point of view. But for us, LEO does not play well with the spirit and philosophy of blockchain because they can dictate terms. Also, based on our flawed and humble understanding, a cryptocurrency:

  • Should be open to everyone. You can come and go as you please.
  • Should be fair. No one should have any unfair advantage over anyone else. 
  • Should be inclusive. It should not be restricted to anyone regardless of what they said or did or where they came from, instead  being totally indifferent to "who" they are or "what" they could possibly become.
  • Should be censorship-resistant if not censorship-free. No one should be stopped from using or accessing any feature at any given point of time. When it comes to a blockchain network (smart contract in this case), even bad actors like fraudsters, hackers, and scammers should be treated in uncensored fashion -- inclusively, equally, openly, and fairly. If you can not censor bad actors in Bitcoin, why should you be able to do that in LEO? “Upgradability” does not justify the “ability” of dictating terms.
  • Should be immutable. Whatever has happened should stay there forever for anyone and everyone to validate, agree, or disagree.
  • The network should be decentralized. There should not be any central entity who can dictate terms on what should happen. Even though the Ethereum network is decentralized, LEO token contract is not because they can dictate terms. 
  • Should be distributed. Everyone should be able to themselves get the history of the network and validate the authenticity of the data.

People trust blockchain because it is trustless. The trusted trustless nature of blockchain made people like you and me interested in this amazing technology.
We do not hold any grudges towards Bitfinex on a personal level, but are not afraid to point our fingers at them when we feel they are wrong and that they need to do the right thing. We offer a solution to Bitfinex, to create a new token without such features and swap them with the investors. This action alone could possibly boost investor confidence in the LEO token.
Finally, this debate can go in circles because Bitfinex would argue they need “upgradability” (do they really?) and we wouldn’t simply accept the fact that someone else’s coin can be deleted even if those were not ours. We hereby rest our case to you, our amazing reader, to make up your own mind and see if you want to trust the LEO ERC20 contract.