Apr 08, 2020

Win NGNT!

Someone made an NGNT game and sent it to us. Check it out!

Support received two emails sometime early this morning from an admittedly curious (and funny) sender email address.

NaijaSatoshi’s first email
Naija Satoshi’s second email

This piqued my curiousity and I immediately went to ngnt.win to check out what “Naijasatoshi” had built.

I was & I still am, very impressed by what I saw. We decided to honour NS’s request and share what they did.

What is Win NGNT?

Win NGNT Copy

It’s a game. It’s a dApp. It’s a chance to Win NGNT. At least, that’s what NS is promising.

Win NGNT is a “decentralized app” (dApp) that lets you “Play for a chance to win more than 110,000 NGNT”.

  • To participate, one needs to buy a ticket worth 500 NGNT.
  • There are 250 tickets for each game.
  • Once 250 tickets are bought, the game ends and the 90% of the money used to buy tickets is sent to a random ticket owner.
  • After this, the game starts again and the process may repeat itself for as many games as possible.

I tried buying a ticket using both Trust Wallet & Coinbase Wallet and it worked as advertised. This took 2–3 minutes the first time & ~1 minute subsequent times.

Successful ticket purchase

Is it a scam? (No, it’s not)

I’ve spent hours looking at the code for both the smart contract and the dApp. I’m not a blockchain security expert like the folks at Quantstamp Labs but I have a good amount of experience with both Solidity and JavaScript.

I can say with certainty that this works as advertised. The contract uses an oracle (Provable) to choose a winner at random and actually sends 90% of the pot to that winner. More on the possible motivations for 90% (as opposed to 100%) below.

It’s relatively simple code all through. If you’re interested my notes per the technical details of how it works, there’s a section below just for that.

How to play

There are pretty straightforward instructions on the website itself. I’m just going to copy and paste them here.

  • Get a Wallet: You’ll need a cryptocurrency wallet to store your NGNT if you don’t already have one. We recommend Trust Wallet for mobile devices and MetaMask for desktop browsers.
  • Get NGNT: Next you’ll need NGNT in your wallet. The quickest and easiest way to get NGNT is to visit buy.ngnt.org.
  • Buy your tickets: Visit this page using either the integrated browser in Trust Wallet or the browser with MetaMask installed. Choose how many tickets you wish to buy with using the form [above] and click buy!
  • Get your winnings: If you win, your NGNT will be automatically sent to the address you used to purchase your tickets. You don’t need to do anything to collect your winnings! The exact prize amount will be a little over 110,000 NGNT.
There’s a Naira Token community on Telegram for questions & discussions concerning NGNT. Click this link to join.

Technical Notes

1. Smart Contract

The smart contract lives at 0x0d43D69d8a5580c9B9f736B9476440ef9578Cbc7. Here are the things I noticed:

  • The contract source code is verified on Etherscan and it matches the code in the github repository that was shared with us. I verified this by compiling the WinNGNT.sol contract in the repo & comparing the bytecode with the creation code from Etherscan.
  • It is not an upgradeable smart contract.
  • The smart contract implements GSN. This allows to users to buy tickets without needing ETH to pay for gas. I particularly like this addition. It’s very much in line with the spirit of NGNT.
  • As mentioned above, the contract uses Provable to generate a random index with which it picks a winner. The EVM is deterministic and cannot truly generate a random number. Oracles are good for use cases like this but there are arguments against their use. However, Provable (formerly Oraclize) is one of the more trusted (and tested) oracles out there.
  • The contract keeps 10% of the pot for a few reasons that shall be listed below. There are no access control mechanisms in the smart contract, nobody can withdraw that 10%.
  • One likely reason for keeping 10% of the pot is to have ETH to perform the actions required for it to choose a winner (call Provable) and send the winnings to said winner.
  • Another reason is to keep GSN working. The contract checks the GSN Relay Recipient every five games. If it has dropped below 1 ETH, it funds it to keep it at 1 ETH.
  • The contract converts NGNT to ETH using Uniswap. It also does this every 5 games. It doesn’t attempt to be selective per pricing, it just swaps NGNT to ETH at whatever the current exchange rate is from Uniswap. The only drawback with this is that it is possible for the NGNT<->ETH liquidity pool to run out. Unfortunately, there really isn’t any other way to achieve this without making users interact with ETH. On the flip side, we (BuyCoins) are already committed to keeping this liquidity pool going (for other reasons). Furthermore, anybody can provide liquidity for NGNT on Uniswap and earn fees. I intend to write more about this in a subsequent post.

2. dApp

The front-end application is pretty straightforward too. I compared the source code provided in the email to what is actually hosted (by minifying & diff-ing). Everything checks out.

  • It uses GSN Provider to make all contract calls. As I highlighted earlier, this makes it possible to interact with the dApp without needing ETH for fees.
  • The first time one buys a ticket, it calls the NGNT contract’s approve function. Signing this transaction allows the Win NGNT contract to transfer up to 100,000,000,000 NGNT from the signing address. However, there’s nothing to worry about here. The only function in the Win NGNT contract that can call NGNT’s transferFrom is buyTicket. buyTicket will always charge you 500 NGNT per ticket except in one instance.
  • The only scenario in which buyTicket doesn’t charge 500 NGNT per ticket is during a first time ticket purchase. This is probably because approve in the step above charges 50 NGNT as the GSN Fee. As such, the ticket price for that first ticket alone is 450 NGNT (bringing the cost to a total of 500 NGNT).
  • On the “My tickets” page, the dApp makes a call to a server hosted on Heroku. This request responds with a list of ticket quantities & transaction hashes for the current wallet address.
  • On the “Past wins” page, the dApp makes another call to the same server (but a different) endpoint, presumably to get information about past winners.
  • I’m fairly certain that all the server does is use Web3 (or a similar library) to listen on Win NGNT contract events and then persists them somehow to serve the frontend. This makes sense because querying the blockchain directly for details like tickets for a specific user & past wins is bound to be hella annoying.

Shout out to Naijasatoshi. It’s lovely to see the fun things that can be built on top of NGNT and more broadly, the EVM.

Copied to clipboard!