PetFriendResolver, a PoC of Snowflake Resolver, Part II — Adapting to ERC 1484

Javier Zafra
5 min readDec 12, 2018

--

In my first post, I introduced what Snowflake dashboard is, and what is the expected functionality to implement in PetFriend DApp. Lot of progress done in DApp since last post, as you can see in this screenshots:

1. Account details view
2. Pet details main view, and next, the lost pet list
3. Lost Pets list view

Changes in snowflake contract

Recently, an update of Snowflake contract has been submitted, making it compliant with ERC 1484. Changes include using EIN instead HydroId as standard identity number for snowflake owners. As said in ERC 1484, “EINs are incrementing uint identifiers starting at 1”. From solidity contract point of view, the EIN is uint type, while HydroId is string type, making much more efficient to work with uint than strings in the contract code. Mayor changes include updating to 0.50.0 solidity compiler, and for DApp frontend, the proposal of using React Hooks with “functional components” instead using react State and class Components. This required a little adaptation of my main App js (index.js), that now has been renamed to PetFriendResolver.js, and has become a function instead a class.

Using ExtraData parameters on sign-up

This new snowflake dashboard also supports extraData params passing to resolver when new snowflake is registered. ExtraData params allow passing inital state to registration of a snowflake to resolver, like account or contact information. New code in contract is like this:

// implement signup function
function onAddition(uint ein, uint, bytes memory extraData)
public
senderIsSnowflake()
returns (bool) {
SnowflakeInterface snowflake = SnowflakeInterface(snowflakeAddress);
snowflake.withdrawSnowflakeBalanceFrom(ein, owner(), signUpFee);
//update the mapping owners
(string memory contactName, string memory contactData) = abi.decode(extraData, (string, string));
owners[ein].contactName = contactName;
owners[ein].contactData = contactData;
// emit StatusSignUp(ein);
return true;
}

Extradata must be encoded using abi functions before sending to contract, and must be “sended” to register form by calling sendExtraData() function:

function handleClick(){ 
var extradata = context.web3js.eth.abi.encodeParameters([‘string’,’string’], [contactName, contactData]);
sendExtraData(extradata);
}

Deposit and withdraw flow between Resolver and registered Snowflake

This DApp implements reward mechanism with this algorithm:

  1. When pet owner put a reward, funds from snowflake are sended to resolver and are escrowed in the resolver, until someone claim it.
  2. When pet owner change reward (by modifing report form), funds are updated, making new deposit (or withdraw if needed) until match new reward from previus value.
  3. When pet owner cancel report, funds are withdraw again from resolver to snowflake.
  4. When any claims the reward after found a pet, and pet owner confirm the reward, funds are transferred from resolver to claimer snowflake funds.

These use cases are basic examples of fund transaction between resolver and registered snowflake. Next you can see the contract method used to put a new report, including code to deposit funds from snowflake(owner) to resolver:

//new LostReport
function putLostReport(uint ownerId, string memory petId, string memory sceneDesc, uint reward )
public
_onlyPetOwner(petId)
//_petExists(petId)
_canReward(ownerId,reward)
_reportNotActive(petId)
returns (bool){
//1. report dont exists
require(bytes(lostReports[petId].sceneDesc).length==0,”Lost Report already exists.”);
//2. create new struct, assign to storate mapping
//persist on storage
lostReports[petId].sceneDesc = sceneDesc;
lostReports[petId].reward = reward;
lostReports[petId].status = Status.Pending;
lostReportKeys.insert(petId);

//escrow reward from snowflake to resolver
SnowflakeInterface snowflake = SnowflakeInterface(snowflakeAddress);
snowflake.withdrawSnowflakeBalanceFrom(ownerId, address(this), reward.mul(10**18));

//emitFundsChanged(ownerId, petId, Status.Pending, FundMovement.Withdraw);
emitEventV2(petId, lostReports[petId]);
return true;
}

The code used to send the reward to claimer is:

function confirmReward(uint ownerId, string memory petId) 
public
_onlyPetOwner(petId)
_reportStatusMustBe(petId,Status.Found)
returns (bool){
//change state to Closed
lostReports[petId].status = Status.Rewarded;
//transfer previously deposited funds from resolver to claimer transferHydroBalanceTo(lostReports[petId].claimerEin,lostReports[petId].reward.mul(10**18)); //LostReportChanged event
emitEventV2(petId, lostReports[petId]);

//delete all struct elements for hydroOwnerId
delete lostReports[petId];
//delete key
lostReportKeys.remove(petId);

return true;
}

This very basic example uses two methods:

withdrawSnowflakeBalanceFrom(uint UIN, address To, uint quantity) 

is a method included in Snowflake interface, and is used to escrow reward funds from pet owner’s snowflake funds to petOwnerResolver funds. In addition:

 transferHydroBalanceTo(uint EIN, uint quantity)

is a method of SnowflakeResolver (thus, inherited in PetFriendResolver), used to withdraw previous escrow from resolver funds to snowflake funds.

Easter Egg: Deploying to Azure

Actually I’m working with Microsoft Azure ecosystem, and I decided to give Azure a try to deploying my local dashboard online, where other people can see the results and give me feedback. I started googling and got some good links to do the process of deploying a node.js app over Azure. Here is an abstract of followed steps:

  1. Prerrequisites: You must have an Azure account; there are free accounts for developers, just get one! Also you must have a zip file with your node.js app compressed files.
  2. After registration, go to Azure Portal, and open a Cloud Shell console; you have to click cloud shell icon as shown in this screenshot:
“Cloud Shell” icon in Azure Portal

Then, execute this commands in order, waiting for console response:

az group create — name myResourceGroup — location “France Central”az appservice plan create — name myAppServicePlan — resource-group myResourceGroup — sku FREEaz webapp create — resource-group myResourceGroup — plan myAppServicePlan — name PetFriendResolverapp config appsettings set — resource-group myResourceGroup — name PetFriendResolver — setting WEBSITE_NODE_DEFAULT_VERSION=8.11.1

Then, yo can access admin portal for your deployed application:

http://<your_app_name>.scm.azurewebsites.net

Next step is upload App zip; open this url:

http://<your_app_name>.scm.azurewebsites.net/ZipDeployUI

You can drag and drop the zip with your application to this window, to deploy inmediately over the last deployed app (last app is deleted before deployment).

And, at last, you can explore your application in : <appname>.azurewebsites.net:

Running our DApp over Azure!

At last…

PetFriend DApp has evolved from a paper idea to implementation, and now It is fully functional in Rinkeby network. Thought this is a PoC, and not optimized for mainnet network (because of transaction costs), it can be a good starting point to introduce yourself developing DApps for snowflake dashboard. Making this Dapp was a very good experience for me to develop over Ethereum blockchain, learn Solidity, put it a Front-End (answering “What is react.js?”), push it to snowflake dashboard, and learn a lot in the process.

You can see source code of contract here, and DApp frontent source code here.

Lot of thanks to Hydro Project and specially to Noah Zinsmeister and Anurag Angara, from Hydrogen Team, for their helping to make this possible. Bye!

--

--

Javier Zafra

Profesional developer, very interested in blockchain and crypto world.