oceanprotocol-archive / bounties

🎣 Bounties for Ocean Protocol
Apache License 2.0
11 stars 0 forks source link

Bounty : Bonding Curves UX #2

Closed innopreneur closed 5 years ago

innopreneur commented 5 years ago

Bonding Curves UX bounty

How can you help?

We are looking for some help to create a React-based UX for Bonding Curves. Main aim is create a reusable React component named BondingCurve.js which can be plugged to any react application in Ocean Protocol Ecosystem. This component will interact with Ethereum Smart Contract (to read data) and will plot graphs/charts based on the data read from the Smart Contract.

What needs to be done?

Create a React standalone application (preferably using Create-React-App v2 starter kit) that has one reusable component - BondingCurve.js (apart from bootstrapped App.js).

Specifications about BondingCurve.js :

sample bonding curve

Implementation Details

Note - All the smart contracts needed to query prices and supply, are already present in this repo. And this is the same repo where the PR for the finished work should be submitted. You can use Ganache as your local blockchain network to deploy smart contracts and test UX.

1. plotting BC as "price vs. supply"

Take a look at this test -


contract('BondingCurve', (accounts) => {
    describe('Test User stories', () => {
        it('Should query the price of drops at different supply', async () => {
            const token = await Token.deployed()
            const market = await BondingCurve.deployed()
            const scale = 1e18

            const assetId = 1
            const assetPrice = 100 * scale
            // 1. register dataset
            await market.register(assetId, assetPrice, { from: accounts[0] })
            // get initial fund and approve withdraw
            await market.requestTokens(10000 * scale, { from: accounts[0] })
            await token.approve(market.address, 10000 * scale, { from: accounts[0] })

            let i
            let supply
            let receipt
            // each time buy drops with 0.1 Ocean token up to 5000 Ocean Token
            // list price history along the amount of drops
            const drops_supply_range = 10000
            for (i = 0; i < 100000; i++) {
                receipt = await market.buyDrops(assetId, 50 * scale, { from: accounts[0] })
                supply = await market.dropsSupply(assetId, { from: accounts[0] })
                //console.log(  '[' + i + '] drops supply :=' + supply.toNumber() + ' drops :=' + receipt.logs[0].args._drops.toNumber()  + ' with ocn cost :=' + receipt.logs[0].args._ocn.toNumber() / scale )
                console.log( '[' + i + '] drops supply :=' + supply.toNumber() + ' with price :=' + receipt.logs[0].args._price.toNumber() / scale + ' Ocean token per drop')
                if ( supply > drops_supply_range){
                  break;
                }
            }

            const drops = await market.dropsBalance(assetId, { from: accounts[0] })
            await market.sellDrops(assetId, drops.valueOf(), { from: accounts[0] })
        })

The key part is following for-loop, which sweep the supply from 0 to limit (i.e., 10000). It will keep buying bonded tokens with 50 Ocean tokens each time. Then, query the current supply amount and print it out. You can keep them into two arrays for plotting.

const drops_supply_range = 10000
for (i = 0; i < 100000; i++) {
      receipt = await market.buyDrops(assetId, 50 * scale, { from: accounts[0] })
     supply = await market.dropsSupply(assetId, { from: accounts[0] })
      console.log( '[' + i + '] drops supply :=' + supply.toNumber() + ' with price :=' + receipt.logs[0].args._price.toNumber() / scale + ' Ocean token per drop')
      if ( supply > drops_supply_range){
            break;
      }
}

2. plot BC as "price vs. time"


        it('Should walk through typical user story', async () => {
            // const marketPlace = await Market.deployed();
            const token = await Token.deployed()
            const market = await BondingCurve.deployed()
            const scale = 1e18

            const assetId = 1
            const assetPrice = 100 * scale
            // 1. register dataset
            await market.register(assetId, assetPrice, { from: accounts[0] })

            // 2. provider request initial tokens 2000
            await market.requestTokens(2000 * scale, { from: accounts[0] })
            const bal1 = await token.balanceOf.call(accounts[0])
            // assert.equal(bal1.toNumber(), 2000,"User should have 2000 OCN tokens now.");
            console.log(`User has ${bal1.toNumber() /scale} Ocean tokens now.`)

            // 3. provider transfer OCN tokens into Market and buy drops
            // here the number of Ocean tokens needs to scale down by 1e18
            const ntokens = 10 * scale
            // calculate number of OCN tokens required for tx
            await token.approve(market.address, 2000 * scale, { from: accounts[0] })

            let tx = await market.buyDrops(assetId, ntokens, { from: accounts[0] })
            console.log('user[0] buy drops at effective price :=' + tx.logs[0].args._price.toNumber() / scale + ' Ocean token per drop')
            const bal2 = await token.balanceOf.call(accounts[0])
            console.log(`provider has balance of OCN := ${bal2.valueOf() / scale }`)
            // assert.equal(bal2.toNumber(), 2000 - ntokens,"User should have 1875 OCN tokens now.");
            const drops1 = await market.dropsBalance(assetId, { from: accounts[0] })
            console.log(`User [0] should have ${drops1.toNumber()} drops now.`)

            // another use purchase drops
            await market.requestTokens(2000 * scale, { from: accounts[1] })
            await token.approve(market.address, ntokens, { from: accounts[1] })
            // transfer 100 OCN tokens to market and buy drops
            tx = await market.buyDrops(assetId, ntokens, { from: accounts[1] })
            console.log('user[1] buy drops at effective price :=' + tx.logs[0].args._price.toNumber() / scale + ' Ocean token per drop')
            const drops2 = await market.dropsBalance(assetId, { from: accounts[1] })
            console.log(`User [1] should have ${drops2.toNumber()} drops now.`)

            // 7. provider sell Drops for Ocean TOKENS
            tx = await market.sellDrops(assetId, drops1.valueOf(), { from: accounts[0] })
            console.log('user[0] sell drops at effective price :=' + tx.logs[0].args._price.toNumber() / scale + ' Ocean token per drop')
            // user get his Ocean tokens after withdraw
            await market.withdraw({ from: accounts[0] })
            const tokenBalance1 = await token.balanceOf.call(accounts[0])
            console.log(`user[0] balance of Ocean tokens := ${tokenBalance1.toNumber() / scale} (5 Ocean tokens as profit)`)
        })

In this case, you only need to listen to the event of "buyDrops" and "sellDrops" and log the price at each time of the transaction. Then plot them out in the graph with corresponding timestamp.

let tx = await market.buyDrops(assetId, ntokens, { from: accounts[0] })
console.log('user[0] buy drops at effective price :=' + tx.logs[0].args._price.toNumber() / scale + ' Ocean token per drop')

tx = await market.sellDrops(assetId, drops1.valueOf(), { from: accounts[0] })
console.log('user[0] sell drops at effective price :=' + tx.logs[0].args._price.toNumber() / scale + ' Ocean token per drop')

Tech stack should include following -

The Pull Requests must be sent to this repository: https://github.com/oceanprotocol/bondingCurvesUX

We are expecting submitted code to go in this subrepo - https://github.com/oceanprotocol/bondingCurvesUX/tree/master/client

We are very happy when

When all below changes are merged with master branch

Seen this problem before?

Any help solving this is welcome. Feel free to leave any comments and help someone else to solve it. We might airdrop tokens to someone even if not directly completing bounty.

Questions & Reviews

Pull requests will be reviewed by one of the maintainers or long-term contributors. In case of any additional questions feel free to ask in this thread and we will do our best to add the missing info :)

Reward

This bounty is valued at Reward Amount PROCN tokens. Once the project was reviewed and merged in the master branch, you will receive the reward. PROCN is a proto-Ocean token. Bounty hunters that earn PROCN will be able to convert them 1:1 to Ocean tokens on network launch (currently Ocean Token is valued at 0.20 EUR). Network launch is expected to happen by Mar 31, 2019. Until then PROCN will be locked and non-transferrable in the ETH wallet to which it is delivered to.

diminator commented 5 years ago

2. (sample bonding curve chart)

Not sure if this one makes sense? Maybe you can point to trent's blogpost? Or do you want to show the interactiveness?

diminator commented 5 years ago
  • Chart.js - for plotting charts (timeline and bonding curve)

I would leave some freedom here - there's also react-vis and others

diminator commented 5 years ago
  • Unit test code coverage is > 80%

Hmmm - this is always a PITA on frontend

diminator commented 5 years ago
  • Charts shows data point details on mouse over

Just say interactive

diminator commented 5 years ago

@kremalicious - you have any suggestions?

gongf05 commented 5 years ago

Hi Manan, the "sample bonding curve chart" needs more love :) it should be price vs. supply. Something like:

screen shot 2018-10-04 at 8 12 30 am

Let me know if you need any help. Thanks!

innopreneur commented 5 years ago
  1. (sample bonding curve chart)

Not sure if this one makes sense? Maybe you can point to trent's blogpost? Or do you want to show the interactiveness?

@diminator I just wanted to show something colorful and interactive. Emphasis was on UX and not model. But, we can use something @gongf05 posted above.

innopreneur commented 5 years ago

@gongf05 Thanks for sample chart. We also need query function and event specifics about the contract. Ideally, when we push out this bounty, hunter should have some Bonding Curve sample contract in Rinkeby to interact with (for data points).

innopreneur commented 5 years ago

@diminator @kremalicious @gongf05 we also need estimated effort in person hours for this to calculate bounty reward. Either we can have a short call for this and closing open issues or each one of you can provide your comments and estimation and we can take average (personally, first option is better). What do you suggest?

gongf05 commented 5 years ago

@innoprenuer I add contracts and testing file in the following branch. You can follow the testing file "test/TestBondingCurve.js" to get data for plotting figures.

https://github.com/oceanprotocol/bounty-contracts/tree/feature/bonding_curves

You should be able to get something like below:

screen shot 2018-10-04 at 3 42 36 pm
gongf05 commented 5 years ago

In the file "https://github.com/oceanprotocol/bounty-contracts/blob/feature/bonding_curves/test/TestBondingCurve.js" , there are two testing for different purpose:

1. plot BC as "price vs. supply"

The key part is following for-loop, which sweep the supply from 0 to limit (i.e., 10000). It will keep buying bonded tokens with 50 Ocean tokens each time. Then, query the current supply amount and print it out. You can keep them into two arrays for plotting.

const drops_supply_range = 10000
for (i = 0; i < 100000; i++) {
      receipt = await market.buyDrops(assetId, 50 * scale, { from: accounts[0] })
     supply = await market.dropsSupply(assetId, { from: accounts[0] })
      console.log( '[' + i + '] drops supply :=' + supply.toNumber() + ' with price :=' + receipt.logs[0].args._price.toNumber() / scale + ' Ocean token per drop')
      if ( supply > drops_supply_range){
            break;
      }
}

2. plot BC as "price vs. time"

In this case, you only need to listen to the event of "buyDrops" and "sellDrops" and log the price at each time of the transaction. Then plot them out in the graph with corresponding timestamp.

let tx = await market.buyDrops(assetId, ntokens, { from: accounts[0] })
console.log('user[0] buy drops at effective price :=' + tx.logs[0].args._price.toNumber() / scale + ' Ocean token per drop')

tx = await market.sellDrops(assetId, drops1.valueOf(), { from: accounts[0] })
console.log('user[0] sell drops at effective price :=' + tx.logs[0].args._price.toNumber() / scale + ' Ocean token per drop')
innopreneur commented 5 years ago

@gongf05 awesome. That's what we needed. Thanks for detailed specs.

kremalicious commented 5 years ago

Some notes:

I would say this will require at least 2 full days, maybe more. All depending on if there's a proper UI design process or if everything is agile designed in the browser

innopreneur commented 5 years ago

@kremalicious Thanks for the review and suggestions. I updated Bounty appropriately incorporating your inputs.

diminator commented 5 years ago

@innoprenuer LGTM - I would also guess 2-3 days

innopreneur commented 5 years ago

@diminator @kremalicious @gongf05 - After considering your estimates and estimating myself, it seems 18 hours are feasible to work out this bounty (since we provided most concise and clear details). So, estimating at the rate of 50 EUR/hr, we arrive at the reward of 4500 PROCN (5 PROCN = 1 EUR).

50 * 5 * 18 = 4500 PROCN = 900 EUR

Also, bounty is now ready to publish. So, I would like you to do final review and once we are all okay with that, we can publish it in Gitcoin.

kremalicious commented 5 years ago

looks awesome, great work also with the pre-setup repo!

innopreneur commented 5 years ago

Thanks for the reviews and help with specs. This bounty is now ready to be published. I am going to close this issue and create a new fresh bounty to be published on Gitcoin (to avoid hunter getting confused with additional comments on this issue.). New relevant issue is published.