AxLabs / grantshares

GrantShares Program 🌱
https://grantshares.io
Apache License 2.0
22 stars 3 forks source link

dApp- Gamefied price forecasting + NEO advanced analytics dashboard (with 3D visualizations) #46

Closed grantshares-dapp[bot] closed 1 year ago

grantshares-dapp[bot] commented 1 year ago

Abstract

For the sake of sharing advanced forecasting and data analysis techniques amongst the NEO community, increasing NEO blockchain usage, and increasing familiarity amongst community members, develop a web-based dApp/game that allows entrants to make predictions on the price of NEO at a future time. Payouts/ prizes would be 100% given back to the community. A complimentary analytics dashboard would be developed which features additional tooling (3D rendering of global node locations with ThreeJS, regression/ seasonal decomposition, daily transaction history, etc.) and gives users a snapshot of where the price is headed.

Proposal Information

Description

How the game works:

At the start of each month, after connecting their wallets, users can place a bet on what the actual price of an asset will be (for now NEO/ GAS) will be at the end of the month (or some future date). As the purpose of this dApp is primarily educational/recreational, buy-in amounts would be low and capped at around 1-3 gas per user (for now).

Note that the target asset does not necessarily have to be NEO, we can also consider related assets such as the price of Bitcoin, ETH, for the future.

All bets will be automatically compiled into a neo-python or neow4j smart contract. The cut-off point for new entries would be about 2 weeks before month- end. At month end, whichever user’s price is closest to the actual price will win the prize pool. The payout structure will be 100% of all submissions received and will be as follows: 1st place: 70%, 2nd place: 20%, 3rd place: 10%.

The backbone of the dApp will be a smart contract that will automatically execute after the prediction date; I will not be able to touch the pot or subsequent dissemination as it will be handled automatically.

Again, the primary purpose of this game is for educational and recreational purposes. It will repeat on a continual, monthly basis and I plan to run it for perpetuity while supporting its dissemination with articles about data science/ forecasting/ economics.

Dashboard description:

The N3 ecosystem already has a small number of dashboards available. They include: neo-dashboard, ndapp, Dora, neodepot, and OneGate. They are quite useful for querying historical information on the NEO blockchain.

Rather than recreate what other dashboards have already done, my dashboard will focus more on analytics/ forecasting/ non-traditional things users may not normally consider. For example, it will feature:

Motivation

Prior to coding, I worked as a CPA with a Big 4 firm and then as a principal research analyst in the energy industry for a number of years. As part of our responsibilities, we had to come up with predictions for a number of important indicators, including oil prices, as well as demand for certain oil extraction equipment. I found that oftentimes, our official oil price forecasts were way off. I wanted to know why, and how our forecasts could improve in accuracy and timing. Thus, I became fascinated with the skill of forecasting- what are the drivers, and how does one know if one has included all of the necessary factors? What are the common errors being made by those in the field? I’ve studied many of the great forecasters, and came to realize that you can count on one hand the number that are consistently accurate.

As the NEO community grows, it is important that its members have a good grasp of cutting edge forecasting and data analytics skills. The gamifying of the forecasting process using very small bets could be a way for NEO users to better understand how forecasting/ data science works and improve their trading and investing skills, while also increasing interaction amongst members. Lastly, developing this dApp will allow me to build my own skill-set in NEO smart contract development.

Goals

1) Enhance the understanding and real-world usage of data analytics (forecasting) and data science techniques amongst the NEO community.

2) Drive increased usage of NEO/ GAS

3) Increase participation / community engagement amongst NEO members

4) Have fun while doing all the above

Deliverables & Roadmap

Specify deliverables in detail, including the following info for each:

Roadmap:

Backend (neo-python, Python, GraphQL, WalletConnect)

Frontend (ReactJS/MaterialUI/Render):

Other

Total working days (~35)

Deliverables Verifiability

1) dApp is successfully launched with features as described above

2) Ads and promotions are placed throughout Reddit, Discord, and Twitter to attract users

3) First monthly competition is held successfully

Budget Plan$

About You / Your Organization

Short-Bio

My name is Rob Liou. I started coding/ data science at my previous job about 3 years ago and have been hooked ever since. Previously, I worked for a Big 4 Accounting Firm as a CPA, and then after my MBA, at a large consulting firm as a principal research analyst in the upstream oil and gas industry, and later at IMA as a research manager/ data engineer. I have an MBA from the University of Michigan and did my undergraduate in economics, accounting, and programming at UCLA.

Portfolio of Projects / Past Experience

After participating in the NEO Frontier Hackathon in 2021 with DDR Store (an "Amazon Store for Market Intelligence"), I was invited to give a demo on the first day of DemoWeek. After the successful demonstration, my project, DDR Store, was later enrolled and launched via the NEO Ecoboost Incubator.

In addition, I have built projects to serve the NEO community in different ways, including:

NEO price regression engine

NEO cycle/ seasonality discovery engine

I've done other analysis of NEO on my personal blog that has been shared with the community to positive feedback.

The NEO analytics dashboard I plan to create would be based on a oil price forecasting engine I created during the Amazon AWS API hackathon held last month.


Proposal Info :clipboard:

[ {
  "target_contract" : "0x6276c1e3a68280bc6c9c00df755fb691be1162ef",
  "method" : "releaseTokens",
  "params" : [ {
    "type" : "Hash160",
    "value" : "ef4073a0f2b305a38ec4050e4d3d28bc40ea63f5"
  }, {
    "type" : "Hash160",
    "value" : "b83c34adfaa1b364c79939142046b508d545256f"
  }, {
    "type" : "Integer",
    "value" : "485"
  } ],
  "call_flags" : 15
} ]

👇 React with 👍 if you liked it, or 👎 if you think this proposal can be enhanced!

robliou commented 1 year ago

Hello guys,

I'm having issue compiling and deploying my smart contract due to type-related errors.

Specifically, I'm trying to understand what is the point of using Byte prefixes in the smart contract? For example, in the sample NEP17 Boa contract, there are these byte-related initializing variables that are set at the top of the contract:

PERSON_B: bytes = b'person b'
ADDRESS_PREFIX: bytes = b'address'
NOT_INITIALIZED: bytes = b'not initialized'
FUNDED_PREFIX: bytes = b'funded'
AMOUNT_PREFIX: bytes = b'amount'
TOKEN_PREFIX: bytes = b'token'

I'm having trouble understanding why are these byte prefixes needed? Are they required for certain variables in a NEO smart contract? If so, which cases (i.e. addresses)?

For example, to use storage.put, this signature is used: storage.put(b'X' + from_address.to_bytes(), amount)

I've looked through various tutorials online but can't seem to find a good answer to this question. I've also asked in Discord but didn't get a clear answer.

Thanks,

@gsmachado @csmuller

EdgeDLT commented 1 year ago

I can't say if it's the only reason, but I can give you at least one justification for it. Using prefixes for dynamically created storage keys gives predictability. That predictability tends to be convenient.

Say for example, I want to look into the storage of a NEP-17 token and view all user balances at some point in time. Let's say the NEP-17 token in question stores balances like this:

BALANCE_PREFIX = b'\x01'

storage.put(BALANCE_PREFIX + from_address.to_bytes(), amount)

Now if I pull the storage records over RPC, I can select all the records prefixed with AQ (they are base64 encoded), drop the prefixes, and have myself a full list of addresses and balances in an instant.

If you did this on the other hand:

storage.put(from_address.to_bytes(), amount)

While that also works for your contract internally, you have made my life much more difficult. Now when I grab the key-values from your contract's storage, I have no idea which keys correlate to balance values and which are irrelevant to me. I'll have to iterate through each entry and check if it is an address.

Two other things to note. First up, putting data into storage costs GAS. More data costs more. In short, shorter key prefixes are better. Secondly, I don't see why a NEP-17 contract would require as many prefixes as you have listed above, those look like they belong in a swap contract to me.

Just to add on to that last one, think about what kind of data your contract stores about a given address. A token contract only stores a balance for each address, that's all it needs to handle transfers. So you could get away with just using the address as a key (even though I'd advise against it, as described above). But if you needed to store say, an auction ID, a holding balance, and a reputation value for each user in a marketplace contract, you can't store them all under that key (unless you wanted to use objects of course, but that would probably be inefficient depending on the use case). So a prefix in that case is a convenient way to store those different values independently while still using the address to derive the key.

robliou commented 1 year ago

Thanks for the explanation, @EdgeDLT .

So essentially the point of prefixes are to help us to classify, sort, and retrieve data that is put into storage, correct?

As for the Byte class itself, are they a necessity when working with types like addresses? What doesn't string suffice for getting/ storing addresses?

For example, given the method below to return an address; we initialize the from_address with a type of UInt160. However, when retrieving it from storage, we need to first convert it to bytes and then convert it to int:

    return storage.get(from_address.to_bytes()).to_int() 

Why the double conversion?

Similarly, when putting from_address into storage,


    storage.put(from_address.to_bytes(), amount)

Even though it's initialized as type UInt160, we have to convert it to bytes before storing it.

Any idea why this is?

Thanks,

EdgeDLT commented 1 year ago

So essentially the point of prefixes are to help us to classify, sort, and retrieve data that is put into storage, correct?

It's one reason for it, I can't say if it's the only reason because I don't know what I don't know.

As for the Byte class itself, are they a necessity when working with types like addresses? What doesn't string suffice for getting/ storing addresses?

I think you're talking about something mostly specific to Boa here really, you'll get the best answers for that on Discord or the Boa Github.

Again, I don't know the "full" answer to your question, but I'll make an observation based on my admittedly limited knowledge. As far as NeoVM is concerned, everything you store is bytes. Whether those bytes resolve to a string, an integer, or some other type is a matter of interpretation. You convert a retrieved value to the type that is useful and correct for your use case, because raw bytes are not usually helpful.

Why the double conversion?

I think there are a couple of misunderstandings here.

First, I don't believe it's actually necessary for you to create a key with from_address.to_bytes(). from_address alone should work just fine (though ideally with an added prefix).

Secondly:

 storage.put(from_address, amount)

Does not put from_address into storage. It puts amount value into storage under key from_address. When you retrieve amount with

storage.get(from_address)

You get bytes back. Since it's an amount, it's probably an integer you are looking for. So actually the line should actually be:

storage.get(from_address).to_int()

So we are not double converting anything. We are retrieving the amount value's bytes, stored under the key from_address, and then interpreting those bytes as an integer with to_int().

cschuchardt88 commented 1 year ago

@EdgeDLT The reason it works like this is because Neo uses a Key-Value Store Database to store all their data. And the type for this is as follows

put(byteArray key, bytesattray value)
get(byteArray key, bytesattray value)
seek(byteArray KeyOrPrefix)
robliou commented 1 year ago

Hey guys,

Just an update from my end. I posted this forecast on reddit the other day (based on the dashboard portion of the project), and it's gotten some positive feedback so far.

As for the game portion of the project, I'm still struggling with creating the smart contract. Luckily, I'm getting some assistance from another user in the community on this (kokahunter).

Cheers,

csmuller commented 1 year ago

Thanks for the update @robliou and good post on Reddit 💪

robliou commented 1 year ago

Hey guys! @gsmachado @csmuller @DylanNNT

It's been awhile! Just wanted to give an update here on our project.

So, I started a new job last month, and this has significantly cut into my time to work on this project. But, I am still determined to complete and execute it well. I also got a lot of help from the community, especially from kokahunter who has been outstanding for the smart contract (would not have been able to get this far without his help).

You can see a preliminary demo of our forecasting app/ game here. This is the figma for how the backend logic works. Basically, the most difficult parts of the app are all completed. Namely, which is that NFT's for each season can easily be minted, the smart contract NFT can take in transfers/ metadata from the front-end successfully, the front-end can retrieve all transfers/ metadata from the NFT and display them, and a winner can be selected from the NFT at season's end with all assets in the NFT transferred to him (in addition to the analytics dashboard that was completed in April).

There is still a number of design/ small issues we need to clear up before deploying to the community. We also need to come up with a marketing/ promotional plan (seasons will likely last only a week or so as opposed to a month). But, hopefully we can complete them in the next few weeks. We are also open to any suggestions you may have.

In the meantime, we have a question: do our smart contract methods need to mirror those of the NEP-11 standard exactly (i.e. use the exact same method name, and fulfill all of the standard's recommendations), or can we take/use from the NEP-11 standard as we see fit while adding/ subtracting things we believe are more relevant to our use case?

As an example, when trying to retrieve tokens from storage, this is the standard NEP-11 method:

public static UInt160 OwnerOf(ByteString tokenId)
{
    StorageMap tokenMap = new(Storage.CurrentContext, Prefix_Token);
    TokenState token = (TokenState)StdLib.Deserialize(tokenMap[tokenId]);
    return token.Owner;
}

Whereas, this is what our custom implementation looks like:

  public static BigInteger RecordCountOf(ByteString name)
  {
      if (name is null) throw new Exception("The argument \"name\" is invalid.");
      StorageMap recordCountMap = new(Storage.CurrentContext, Prefix_RecordCount);
      return (BigInteger)recordCountMap[GetKey(name)];
  }

Is it OK to deploy with the latter method, or do we have to use the former?

Thanks,

csmuller commented 1 year ago

Hey @robliou, Thanks for the update. Great work so far! About the NEP-11 standard: You contract does not have to mirror the NEP-11 standard even if you call the tokens produced by it "NFT". But, if you adhere to the standard it makes your contract or NFTs accessible to any other project that works with the standard. If you don't adhere to it, your NFTs will not be consumable by other software that work with the NEP-11 standard. So, if you don't need your NFTs to be interoperable with other projects than it's fine to deviate from the standard.

roman-khimov commented 1 year ago

I'd say if you're doing some kind of NFT, you better stick to NEP-11 unless you have some very good reasons to deviate. NEP-11 compliance is something expected of a Neo-based NFT, once you're NEP-11 all the other tooling around (like explorers or wallets) can easily work with your contract/tokens via this standard interface, it's a very powerful integration. And it should be pretty easy to do, take NNS contract for example, it handles domain names which have a lot of specifics, yet at the same time any domain is a proper NEP-11 NFT.

robliou commented 1 year ago

@csmuller @roman-khimov

Appreciate your inputs on this topic! We have discussed internally, and will plan to adhere to the NEP-11 standard as much as possible. Shouldn't take too much time from our end.

Also, we hope to push out a promotional version of this app in the next week or so. Hope you can help support us by trying out and partcipating in the first season!

Thanks,