Code Monkey home page Code Monkey logo

marketplace-legacy's Introduction

Marketplace

Decentraland's LAND Marketplace

Running the project

The core technologies of the marketplace are:

Once those dependencies are installed you can configure each part of the project.

The backend lives on the /src folder and the front on the /webapp folder.

Keep in mind that both sides use dotenv via decentraland-commons to configure the environment. As such, you'll need to create your own .env files, following the .env.examples located on each folder.

First of all, you'll need to run npm install on both directories. Once that's done, you can move to configuring each part:

Back-end

  • Creating the DB user
    Create a PostgreSQL named marketplace. You can do it running $ createuser marketplace on the terminal or by running the query CREATE USER marketplace;
  • Creating the database
    You'll need to create a marketplace database. You can do it running $ createdb -O marketplace marketplace on the terminal or by running the query CREATE DATABASE marketplace OWNER marketplace;. You can create a marketplace_test database if you want to run tests against it.
  • Adding the .env files
    Create a .env file on the /src folder and fill it following the .env.example file found there. You can skip most variables as they have a default value. There are some notable exceptions like CONNECTION_STRING which might look something like CONNECTION_STRING="postgres://localhost:5432/marketplace"
  • Migrate the database
    Once you have your database you can go ahead and run the database migrations. To do it, simply run npm run migrate up. We use node-pg-migrate behind the scenes and every argument after migrate will be forwarded to it. You environment will be picked up automatically from the /src/.env file, but you can override the CONNECTION_STRING by explicitly adding it like this CONNECTION_STRING='' npm run migrate up
  • Running the initialize script
    Just run npm run init-db. Once it finishes seeding the database, the script will prompt you to add the latest data from the Blockchain to the database. You'll need to have a Ethereum node for this to work (see below). If you want to run that later, you can use npm run renew-blockchain-data.
  • Running an Ethereum node
    If you want to be able to get data from the Ethereum blockchain, you'll need to have a node running on http://localhost:8545. You can use Parity, geth, etc.
  • Running the server
    To run the server, go to the /src folder and run the server.js script like this babel-node server.js
  • Run watchers
    If you want to keep your database up-to-date with the blockchain, you need to run this watcher: npm run monitor-blockchain. Keep in mind that the address you use for each contract will determine the network. For more information in event watching, check here.

If you don't want to install babel-node globally, you can use npx and install it locally.

Front-end

  • Adding the .env files
    Create an .env file on the /webapp folder and fill it following the .env.example file found there. You will need to specify NODE_PATH to be src/, REACT_APP_API_URL to be http://localhost:5000/v1 (unless you changed the default server configuration, if so point to the right host:port) and REACT_APP_MANA_TOKEN_CONTRACT_ADDRESS to Ropsten's MANAToken address: 0x2a8fd99c19271f4f04b1b7b9c4f7cf264b626edb.
  • Running the front-end
    You will need to first have the server running (see above). After that just jump into the webapp folder $ cd webapp and start the local development $ npm start

Shared code

There's a /shared directory where some of the logic shared between backend and frontend lives (i.e. everything related to rendering the map). We have symlinks that point to this directory from the src directories of the server and the UI (src/shared and webapp/src/shared). This symlinks have been versioned in this repo, but if for some reason they don't work (Windows?) you will need to recreate them in order to npm start or npm build this project.

Tests

To run the backend tests simply run npm run test or npm run watch:test. You'll need to create your own .env file for the /specs file mimicking the .env.example file that's in there. We do this so you can for example use a dedicated database CONNECTION_STRING="postgres://localhost:5432/marketplace_test". Remember that if you're using a test database, you'll need to migrate it. You can run CONNECTION_STRING="postgres://localhost:5432/marketplace_test" npm run migrate up to do so.

Migrations

To keep your database up to date, you'll need to run npm run migrate up each time a new migration is introduced. Your database version lives on the pgmigrations. Check node-pg-migrate for more info.

Seed

If you need some test data to test the marketplace, you can use the seed for quick features. Run npm run seed generate MODEL_NAME -- --amount NUMBER, (which will look something like this npm run seed generate Publication -- --amount 2) and follow the prompts

Translate

You can translate automatically from English to the other locales by running the command npm run translate, this command will compare all the other locales to en.json and if it finds any missing translation it will use Google Translate to add it to the corresponding locale.

API

We have documentation for our HTTP API that can be found here.

marketplace-legacy's People

Contributors

abarmat avatar adrabenche avatar cazala avatar decentraliser avatar eijigard avatar eordano avatar fmiras avatar m-sossich avatar moliva avatar nachomazzara avatar nicosantangelo avatar oscnet avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

marketplace-legacy's Issues

When running the executeOrder function I get new BigNumber() not a number

So after feeding data into my executeOrder function from the marketplace API I'm running into this error:
BigNumber Error: new BigNumber() not a number: 25,150

I'm using executeOrder on the marketplace contract by feeding the asset_id (25,150 in this case) as the first argument and the price in MANA (5000 in this case) as the second argument. Is this the proper way to use this function?

Error attempting to authorize contract for MANA

i have an issue with confirming approvals for the marketplace to operate my mana and land on my behalf. i'm using metamask and have some eth balance so this is definitely not an issue with not sufficient funds but each an every transaction is failing. i was changing gas limit and gas price but without any success. do you know by any chance how to fix this? thank you in advance for any help.

FR: Ability to select an address other than the default on Ledger wallet

After successfully connecting my Ledger to the market it gives me the option to select the derivation path, but it does not allow me to specify an address on the wallet. It appears to only allow use of the first address, and in my case that is not the address where my MANA or ETH are stored.

It would be nice if I could select a different wallet address rather than have to move coins around.

i tried to transfer land, but get an error

Error: Error: [ethjs-rpc] rpc error with payload {"id":6980037569661,"jsonrpc":"2.0","params":["0xf8c90c8506fc23ac008261a894f87e31496a0439aa21e79f97bf1b6c2174e19a19c19ac77c02bc2b38b8ab712af79c9934a24a0258d3e1156dcaed25707c30d3ff75149ce66cb0b4e1194a32f8daea8daedd328"],"method":"eth_sendRawTransaction"} Error: intrinsic gas too low at TransactionStateManger. (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/scripts/background.js:2216:39) at TransactionStateManger.g (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/scripts/background.js:69757:16) at TransactionStateManger.EventEmitter.emit (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/scripts/background.js:69673:17) at TransactionStateManger._setTxStatus (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/scripts/background.js:5488:14) at TransactionStateManger.setTxStatusFailed (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/scripts/background.js:5448:12) at TransactionController._callee6$ (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/scripts/background.js:2479:37) at tryCatch (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/scripts/background.js:20399:40) at Generator.invoke [as _invoke] (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/scripts/background.js:20633:22) at Generator.prototype.(anonymous function) [as throw] (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/scripts/background.js:20451:21) at step (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/scripts/background.js:18078:30) at chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/scripts/background.js:18091:13 at
TRANSFER

Search filters (has road access)

Some search filters would be nice. For example: has road access, neighbours district, has neighbour for sale (multiple plots).

Coding Guidelines Proposal

This is just a proposal to keep code consistent. It's intended to be a living document, most of the conventions that I'm writing here are the ones we are already using, but I just wanted to have them written down. Nothing is written in stone tho, if there's something you don't like lets use this issue to discuss it.

1. Performance

1.1 Using PureComponents

We should use PureComponents for all our components, except when they depend on the context. They work in the same way as regular Components but they implement a shouldComponentUpdate() with a shallow prop and state comparison. This can save tons of unnecessary renders.

ie:

const Stateless = () => {
  console.log('stateless')
  return <p>Stateless</p>
}

class Pure extends React.PureComponent {
  render() {
    console.log('pure')
    return <p>Pure</p>
  }
}

You will notice that the Stateless component triggers its render function on every keystroke while the pure doesn't:

pure-stateless

1.2 Avoid creating stuff inside the render() function

The render() function is one of the most called functions, so we should try to minimize the memory footprint by not creating objects or functions. Also, since we use PureComponents if we create new objects, that will trigger unnecessary renders in the components down the tree because it will make the shallow props comparison to fail.

BAD:

class Options extends React.PureComponent {
  render() {
    const options = ['A', 'B', 'C']
    return <select options={options}>
  }
}

GOOD:

const options = ['A', 'B', 'C']
class Options extends React.PureComponent {
  render() {
    return <select options={options}>
  }
}

Same thing applies for functions:

BAD:

class Input extends React.PureComponent {
  ...
  render() {
    return <input value={this.state.value} onChange={e => this.setState({ value: e.target.value }}>
  }
}

GOOD:

class Input extends React.PureComponent {
  ...
  handleChange = e => this.setState({ value: e.target.value }}
  render() {
    return <input value={this.state.value} onChange={this.handleChange}>
  }
}

1.3 Use memoized selectors

Using memoized selectors (like reselect) helps preventing unnecessary computation and since the
reference is memoized (it returns the same reference), when we combine this with
PureComponent that will also save tons of unnecessary renders.

BAD:

export const getList = state => {
  const books = getBooks(state)
  const authors = getAuthors(state)
  return Object.keys(books)
  .map(bookId => {
    const book = books[bookId]    
    return {
      ...book,
      author: authors[book.authorId]
    }
  })
}

GOOD:

export const getList = createSelector(
  getBooks,
  getAuthors,
  (books, authors) => Object.keys(books)
    .map(bookId => {
      const book = books[bookId]
      return {
        ...book,
        author: authors[book.authorId]
      }
    })
)

2. Naming conventions and file structure

2.1 Components

Naming conventions:

  • callback props: start with on + the name of the event, ie: onMouseMove, onOpen, onChange.

  • boolean props: start with is or has, ie: isLoading, hasError.

  • handlers: start with handle + the name of the event, ie: handleMouseMove, handleOpen, handleChange.

File structure:

Each file contains a single component which is exported as default

2.2 Containers

Containers have no jsx, they just import the component they will connect, they have two functions mapState and mapDispatch (optionally mergeProps if needed), and finally they export the HOC as default, ie:

import { connect } from 'react-redux'
import Component from './Component'

const mapState = state => {
...
}

const mapDispatch = dispatch => {
...
}

export default connect(mapState, mapDispatch)(Component)

2.3 Reducer

File structure

  1. Start with an INITIAL_STATE

  2. Export a function reducer as default

  3. Finally export selectors

For selector we use lambdas, we use get as prefix unless the return value is a boolean, in that case we use is/has. Unless the state is too simple, add a getState selector that returns the root of the state of this reducer, and let the other selectors depend on it (so it's easier to refactor the shape of the application state later).

Example:

import { SOMETHING } from './actions'

const INITIAL_STATE = {
  something: 1
}

export default function reducer(state = INITIAL_STATE, action) {
  switch(action.type) {
    case SOMETHIG:
      return {
        …state,
        something: action.value
    }
    case default:
      return state
  }
}

// --

export const getState => state => state.path.to.reducer
export const getSomething = state => getState(state).something

2.4 Actions

Export all action types as constants at the beginning, then all the action creators as functions

Example:

const SOMETHING = 'Something'

function doSomething(value) {
  return {
    type: SOMETHING,
    value
  } 
}

For async actions, use the prefix _REQUEST, _SUCCESS and _FAILURE

export const FETCH_SOMETHING_REQUEST = '[Request] Something'
export const FETCH_SOMETHING_SUCCESS = '[Success] Something'
export const FETCH_SOMETHING_FAILURE = '[Failure] Something'

2.5 Sagas

export your saga as default, then place all the handlers below

import { 
  FETCH_SOMETHING_REQUEST,
  FETCH_SOMETHING_SUCCESS,
  FETCH_SOMETHING_FAILURE
} from './actions'

export default function* saga() {
  yield takeLatest(FETCH_SOMETHING_REQUEST, handleFetchSomething)
}

function* handleFetchSomething(action) {
  try {
    const something = yield call(() => fetch(...))
    yield put({ type: FETCH_SOMETHING_SUCCESS, something })
  } catch (error) {
    yield put({ type: FETCH_SOMETHING_FAILURE, error: error.message })
  }
}

The pattern that we use to trigger actions from a different domain is always puting the action, never takeing it.

BAD:

// modules/something/sagas.js
import { LOGIN_SUCCESS } from 'modules/login/actions'

export default function* saga() {
  yield takeLatest(LOGIN_SUCCESS, handleLoginSuccess)
}

function* handleLoginSuccess(action) {
  yield put({ type: FETCH_SOMETHING_REQUEST })
}

GOOD:

// modules/login/sagas.js
import { FETCH_SOMETHING_REQUEST } from 'modules/login/actions'

export default function* saga() {
  yield takeLatest(LOGIN_REQUEST, handleLoginRequest)
}

function* handleLoginRequest(action) {
  try {
    ...
    yield put({ type: LOGIN_SUCCESS })
    yield put({ type: FETCH_SOMETHING_REQUEST })
  } catch (error) {
    yield put({ type: LOGIN_FAILURE, error: error.message })
  }
}

Error connecting Ledger to market on Firefox

Running Firefox 59.0.1 (64-bit) on Windows 10. When attempting to connect to a Ledger from the sign-in page receive an error in the console, market just redirects back to the login page repeatedly. Tried on Chrome and I'm able to use the Ledger successfully. Previously I had been using MetaMask on Firefox successfully. I disabled MetaMask and restarted Firefox, but still was unable to connect.

Console error:
[Ethereum] Error trying to connect Ethereum wallet: Could not get a valid provider for web3
rollbar.min.js:2:19646
Error trying to connect to Ethereum for the 3th time
Error: Could not connect to Ethereum
Stack trace:
e/<@https://market.decentraland.org/static/js/main.263ad06c.js:1:359121
r@https://market.decentraland.org/static/js/main.263ad06c.js:1:1560812
c/<@https://market.decentraland.org/static/js/main.263ad06c.js:1:1561860
s/</e[t]@https://market.decentraland.org/static/js/main.263ad06c.js:1:1560988
r@https://market.decentraland.org/static/js/main.263ad06c.js:1:358290
r/<@https://market.decentraland.org/static/js/main.263ad06c.js:1:358388
C/</<@https://market.decentraland.org/static/js/main.263ad06c.js:1:1314804
C/<@https://market.decentraland.org/static/js/main.263ad06c.js:1:1314674
c@https://market.decentraland.org/static/js/main.263ad06c.js:1:366167
rollbar.min.js:2:19646
action [Failure] Connect Wallet @ 20:40:22.174

[Failure] Buy LAND

Continuing the saga of Kubi and his Ledger, after successfully authorizing the contract I attempted to buy some land. After clicking CONFIRM on the Buy LAND screen I get the following error:

{type: "[Failure] Buy LAND", error: "gas required exceeds allowance or always failing transaction", @@redux-saga/SAGA_ACTION: true}

My derivation path is still set to m/44'/60'/0'/0, which worked for authorizing the contract, and I have ETH for gas on the address being used. I did not see a transaction prompt pop up on the Ledger.

API not returning all transactions

Hi,

I fetched all publications from the API with the call GET /parcels, and while sample checking I noticed that some transactions are not here.

For example this famous transaction on the land 39, 62 when it had been sold for 25 MANA.
This transaction is supposed to be in the block 5,666,187

However, the API call GET /parcels does not return a transaction for this block, and returns no transaction for this particular LAND (see here)

But by using the call GET /parcels/:x/:y , all transactions from this LAND are here.
https://api.decentraland.org/parcels/39/62/publications

Is that normal that the API call GET /parcels does not return all transactions ?

Thanks

When a user hasn't authorized LAND he doesn't get a warning before buying

When a user hasn't authorized LAND he doesn't get a warning before buying, leading to failed transactions (we should disable the UI and show a warning with an explanation and a link to the settings page)

I think we used to do this but now it's not working, that's why i'm labeling this as a bug.

Metadata format for the LANDRegistry

  • Evaluate alternatives for the string metadata for each parcel of LAND (csv, json vs others).
  • Should have some form of versioning if we decided to upgrade in the future.
  • Should take into account that storing data in Ethereum has high costs and we should keep it minimal.
  • Provide a clear definition of the format so third-parties can use.

Error attempting to authorize contract for MANA

Attempting to authorize the marketplace contract for MANA using a Ledger. Running Chrome 64.0.3282.186.

{type: "[Failure] Approve MANA", error: "To get multiple accounts your derivation path must follow pattern 44'/60|61'/x'/n ", @@redux-saga/SAGA_ACTION: true}

I do have some ETH and tokens on a different address on the Ledger, but I've moved MANA and ETH onto the default address (that shows up in the market settings). My MANA balance shows up properly in the top right of the market.

My derivation path is m/44'/60'/0' for Ledger (ETH).

There is no indication of an error displayed on the page, just in the console.

Directory Structure Proposal

The sources of the project follow this structure:

/src
  /modules
    /{domain}
      /actions.js
      /actions.spec.js
      /reducer.js
      /reducer.spec.js
      /sagas.js
      /sagas.spec.js
      /{subdomain}
  /components
    /{component}
      /{component}.js
      /{component}.spec.js
      /{component}.container.js
      /{component}.css
      /index.js
      /{subcomponent}

There are two main branches, /modules and /components.

/modules

This directory contains all the redux modules of the application.

It follows a domain driven structure, where each domain of the application will be represented as a directory, and all the actions (action types, action creators, and thunks/sagas), reducers and selectors (and all their test specs) for that specific domain will live inside.

A domain may contain child domains or subdomains (domains that are only used by or relevant to their parent domain). These will follow the same structure as their parent.

The strutures of the application's redux state tree and the /modules directory tree must be very similar if done right. This will make debugging more intuitive and onboarding new developers easier.

Why?!

Usually when a bug is found, or a refactor is needed, it involves all the redux parts in a domain: changing an action may impact on the reducer, that may also impact on the selectors if the shape of the state is affected, thus requiring updates on the test specs for the three of them.

Keeping all the parts together makes refactoring/fixing/updating code easier. Also, at some point some part of a domain may need to be shared accross projects (ie, the User domain might be shared between apps that use the same authentication system), it is very straight forward to extract a domain as a separate package when all the parts (and their dependencies) live under the same directory.

/components

This directory contains all the React components.

Each component has it's own directory, with a component file, a styles file, and its typings and tests. It ALWAYS has an index.js that exports the component. A component may also have a .container.js file which basically consist of the mapState and mapDispatch functions, and returns the connected HOC.

A component can have child components or subcomponents (components that are only used by or relevant to their parent component). These will follow the same structure as their parent.

Why?!

Why don't we have a separate /components and /containers folders like everyone else?

Why do we need that annoying index.js file??

As the application grows, components grow with them. Sometimes a component needs to be split into smaller components with different responsabilities. When this happens sometimes a container is better off as a regular component with child containers instead:

For example, take this components:

<Container>
  <ComponentA />
  <ComponentB />
  <ComponentC />
</Container>

Say <Container> is now mapping +20 props, that passes down to the three children components, that also pass them down to their children components.

Having so many props and following them down the component tree can make the code difficult to debug and also makes refactors more painful, so it might be smarter to connect the child components in this case and leave the parent and a regular component:

<Component>
  <ContainerA />
  <ContainerB />
  <ContainerC />
</Component>

Now these three containers have a smaller mapped surface than the +20 props parent, and props are not passed downsseveral steps.

This is also more performant since now a change in the store might trigger a re-render of a single container, instead of re-rendering the only parent container with its three children.

Now, since each component has a .container.js file we can just copy the parent's one to each of the children's directory, and strip out the unnecesary props.

Now is when that index.js file pays off, on the children components we just point it from the component file, to the .container.js file, and we do the oposite on the parent component. And everything keeps working as before, but we have cleaner, more performant code. Easy refactor.

This helps the application to stay healthy and scalable as it grows.

Having the .container.js separated from the component itself makes the component easier to test (we just need to test the un-connected component, no need to mock a redux store). And also makes it easy to mock data and develop components when the redux modules that it uses are not ready yet (you just mock the mapState and mapDispatch results).

Error while moving around the map

While dragging around the map multiple times I got the error in the screenshot. I did it multiple times but not sure how to reproduce accurately yet.

count parcels for sell isnt correct

Hi.

I have on one address 45 parcels, all on sale. but page "on sale" show only 35. But if I check and count it one by one on atlas page, its all on sale. Same situation on another adresses.

[Feature Request] The Marketplace: Auction Sell

Dear Decentraland developers and enthusiasts,

I think it would be great if we could auction our lands. This would be much easier than relisting again and again until we find a reasonable (hopefully best) price for our land.

Auction could work like this:

  1. A seller puts a particular parcel to auction with some deadline.
  2. Some buyers bid.
  3. When the deadline is reached highest bidder buys.
  • A seller also can set a price for immediate sale.
  • A seller can set minimum bid increase rate (e.g. minimum increase should be 1.1x)
  • A seller can set a rule such as deadline = max(deadline, now+5hours)

What do you think?

cant to start webapp

When trying to launch webapp

Failed to compile
./src/Routes.js
Module not found: Can't resolve 'components/GoogleAnalytics' in '/Users/hsbs/DCL/marketplace1/webapp/src'
This error occurred during the build time and cannot be dismissed.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.