In a previous post, we introduced Banano Quest as a proof of concept designed to alleviate the struggles involved with fastening mobile applications to a blockchain. We also discussed the benefits of onboarding new developers and gamers into decentralized applications using non-fungible token rewards.
Now, let’s take a look under the hood and get into the blockchain integration mechanics from the code level. Pocket Network’s goal is to provide tools and best practices that reduce the request load for developers on the blockchain side. This frees up time for developers to focus more effort on refining their DApp user experience. Here are the 3 main components of the Banano Quest application.
Banano Quest Application
Networking and Data
The Banano Quest application uses Core Data to store all data and minimize API calls to the Pocket Ethereum Node. Due to transaction times on Ethereum, we expect players who are creating and completing quests to be constantly refreshing their screens in an attempt to retrieve the latest dataset. To avoid multiple API requests in short amounts of time, we implemented a polling scheme that does the following:
- Whenever a user submits a transaction the application saves the transaction receipt into Core Data.
- A repeating task pulls all transactions for each specific action (quest creation and claiming) and pulls the transaction receipt.
- If status = 1, the application displays the local notification.
This generic listener checks every 60 seconds for any transaction coming out of the application which informs users that there is no need to refresh their screen to check if the transaction has gone through.
Pocket Ethereum Plugin
The Pocket iOS plugin system allows any iOS DApp to support the decentralized network that a developer wishes to build on.This simplifies the complexity of blockchain development which minimizes friction involved with decentralized application production.
Each plugin can be created independently and supported individually as a Cocoapods package. Developers can pick and choose which plugins they prefer to support on their network.
To add Ethereum support for your DApp, you can use our Pocket iOS Ethereum Plugin.
Every plugin has a set of standard interface methods that developers can use:
Creating a wallet
// The data parameter is not used in the Ethereum plugin let wallet = try? PocketEth.createWallet(data: nil)
Every blockchain uses a different hashing algorithm to create a wallet. For example, in Ethereum to create an account it uses the keccak256 algorithm.
Importing a wallet
// The data parameter is not used in the Ethereum plugin let privateKey = "plain_text_private_key" let address = "0x000000000" let importedWallet = try? PocketEth.importWallet(privateKey: privateKey, address: address, data: nil)
Import any existing wallet with the private key, public key, and any extra data. The function returns a Wallet object. The data field is a generic dictionary defined by each plugin for data needed in a specific blockchain.
Creating a transaction
// Ethereum's transaction object var params = [AnyHashable : Any]() params["to"] = "0x0000000000" params["data"] = nil params["nonce"] = BigUInt.init(0) // In weiparams["gasPrice"] = BigUInt.init(0) params["gasLimit"] = BigUInt.init(0) params["value"] = BigUint.init(0) // For custom data just use a Data object params["data"] = Data.init() // For smart contract calls use a Dictionary with the following structure params["data"] = [AnyHashable: Any]() params["data"]["abi"] = "" // Raw abi JSON for the specific function you're calling params["data"]["params"] = [Object]() // Parameters for the function in the same order specified for the smart contract abilet wallet = try? PocketEth.createWallet(data: nil) // The "from" param for the transaction is automatically extracted from the Wallet object let transaction = try? PocketEth.createTransaction(wallet: wallet!, params: params)
Creating a transaction writes to the given blockchain. This will have different confirmation times, depending on the blockchain, and your application’s UI will need to reflect that.
Creating a Query
// Queries are structured like JSON-RPC calls, all methods are supported except sendTransaction and sendRawTransaction let queryParams = ["rpcMethod": "eth_getTransactionCount", "rpcParams": ["0x0", "latest"]] // The decoder is going to be used to try and decode the response in case it's a hex or any other data type that needs decoding // You can pass in nil and get the raw response from the blockchain let decoder = ["returnTypes": ["uint256"]] let query = try? PocketEth.createQuery(params: queryParams, decoder: decoder)
Queries are reads from a blockchain. They create requests that conform to the Pocket Node API. This returns a Query object. The params field is a generic dictionary defined by each plugin for parameters needed to create a Query for a specific blockchain. The decoder field is an optional, generic dictionary that specifies the return types for any Query.
The Pocket iOS SDK contains a generic interface that allows developers to build specific plugins to the blockchain of their choice. Each plugin contains its own metadata specific to the featured blockchain. All queries and transactions conform to the expectations of Pocket Nodes.
The SDK’s two main interactions:
- sendTransaction for writes.
- executeQuery for reads to a given blockchain (Ethereum in this case).
Tavern smart contracts
Deployed using Zeppelin OS, this set of smart contracts allows Ethereum developers to create questing platforms for their user-facing apps. A Quest is defined as a task for users to guess Quest answers based on Quest names and hints provided by Quest creators.
Tavern smart contracts integrate easily with Ether, and token contracts such as ERC-721, ERC-20. This allows developers to hand-pick programmable cryptocurrency rewards for gamers!
Here are the quick and simple steps for getting your Tavern Quest set up:
- Create and deploy your own TavernQuestReward, which the Tavern contract will use to identify your DApp Quests from other DApps. Use the TavernQuestReward interface here in your contract to be compatible with Tavern.
- Any given quest must have more than 1 valid answer.
- Tavern uses Merkle trees to securely disguise and prove Quest answers.
- Read more about Merkle trees here.
Creating a Quest
The first step is to provide a list of valid answers for the Quest. For example, Banano Quest uses all the possible GPS coordinates in a specified radius as valid answers for an AR BANANO finding experience. The valid answers can be anything — They can be virtual coordinates from Decentraland or words to recreate desired gameshow format, like Jeopardy.
Merkle tree: Hiding the answers in plain sight
Placing the coordinates within a Merkle tree allows the game to securely hide the coordinates from all users. This is accomplished by hashing each answer of the Quest coordinates into leaves of a Merkle tree. The entire tree is placed into the smart contract, except for the lowest level that gets inputted from the client itself. When the client attempts to complete the quest, the contract takes the hashed Merkle leaf and is verified by the Tavern contract.
Submit a transaction through the following function in the Tavern contract to ensure secure encryption of the answers using a Merkle tree:
function createQuest(address _tokenAddress, string _name, string _hint, uint _maxWinners, bytes32 _merkleRoot, string _merkleBody, string _metadata) public payable
_merkleRoot parameter must match up to the Merkle root the corresponding answer’s Merkle tree.
_merkleBody parameter can be used to store every level below the root, except the lowest level as that would equate to the Quest creator storing the possible answers in the Tavern contract Quest repository.
The function is payable with the purpose of being able to assign an Ether prize to the winners of the Quest, in which case the _maxWinners parameter must be greater than 0.
Pocket, INC operates the Tavern contract and withholds 10% of all Quests created on the contracts specified in the addresses above.
If you would prefer to operate your own custom Tavern contract you’re able to do so by deploying the Tavern contract to your preferred Ethereum network!
Validating a Quest
In the case of a Quest being marked invalid by the TavernQuestReward contract, it can be revalidated by calling:
function validateQuest(address _tokenAddress, uint _questIndex) public
Claiming a Quest reward
If TavernQuestReward does not provide the appropriate reward to the user upon proof submission, further reward claims can be done by calling:
function claimReward(address _tokenAddress, uint _questIndex) public
Fetching Quest related data from the Tavern contract
The Tavern contract exposes multiple getter methods that allow for easy retrieval of all Quest information necessary to create your DApp UI and UX.
Unpeeling a bunch of tools to discover what works for you!
Banano Quest is a fully open source application that you can view on our Github. All of our code is open source, and free for you to use and remix. We hope you see how simple it is to create an application like Banano Quest, and serves as inspiration for your future DApps.
Pocket Network tools support blockchain integration, allowing developers to focus on awe-inspiring ideas on the front end. Banano Quest serves as a proof of concept geared directly towards developer and user onboarding. Cultivating interactive userbases through the deployment of non-fungible token reward systems has the potential to enhance consumer/producer relationships greatly. Ethereum’s web3, along with other blockchain networks, serve as a reimagined alternatives to current centralized application networks.
The experimentation and implementation that takes place in the open source community at large from here on out is an exciting environment for the Pocket team.
We strive along the path of our quest to build the infrastructure and tools necessary to support innovative DApp development in the future and wish you the best as you pursue blockchain decentralized application success!
Ways in which you can help or find out more about us: