RigoBlock / contracts

[DEPRECATED] directory of our contracts
Apache License 2.0
1 stars 0 forks source link

Uniformity on eventful output #25

Closed wnz99 closed 6 years ago

wnz99 commented 6 years ago

This is an example of code to get all the transaction on a Vault or Drago:

  // Getting last transactions
  getTransactions = (vaultAddress, contract, accounts) => {
    const { api } = this.context
    var sourceLogClass = this.constructor.name
    const logToEvent = (log) => {
      const key = api.util.sha3(JSON.stringify(log))
      const { blockNumber, logIndex, transactionHash, transactionIndex, params, type } = log
      var ethvalue = (log.event === 'BuyGabcoin') ? formatEth(params.amount.value, null, api) : formatEth(params.revenue.value, null, api);
      var drgvalue = (log.event === 'SellGabcoin') ? formatCoins(params.amount.value, null, api) : formatCoins(params.revenue.value, null, api);
      // let ethvalue = null
      // let drgvalue = null     
      // if ((log.event === 'BuyDrago')) {
      //   ethvalue = formatEth(params.amount.value,null,api)
      //   drgvalue = formatCoins(params.revenue.value,null,api)     
      // }
      // if ((log.event === 'SellDrago')) {
      //   ethvalue = formatEth(params.revenue.value,null,api)
      //   drgvalue = formatCoins(params.amount.value,null,api)     
      // }
      return {
        type: log.event,
        state: type,
        blockNumber,
        logIndex,
        transactionHash,
        transactionIndex,
        params,
        key,
        ethvalue,
        drgvalue
      }
    }

    // Getting all buyDrago and selDrago events since block 0.
    // dragoFactoryEventsSignatures accesses the contract ABI, gets all the events and for each creates a hex signature
    // to be passed to getAllLogs. Events are indexed and filtered by topics
    // more at: http://solidity.readthedocs.io/en/develop/contracts.html?highlight=event#events

    // The second param of the topics array is the drago address
    // The third param of the topics array is the from address
    // The third param of the topics array is the to address
    //
    //  https://github.com/RigoBlock/Books/blob/master/Solidity_01_Events.MD

    const hexVaultAddress = '0x' + vaultAddress.substr(2).padStart(64, '0')
    const hexAccounts = accounts.map((account) => {
      const hexAccount = '0x' + account.address.substr(2).padStart(64, '0')
      return hexAccount
    })
    const options = {
      fromBlock: 0,
      toBlock: 'pending',
    }
    const eventsFilterBuy = {
      topics: [
        [contract.hexSignature.BuyGabcoin],
        [hexVaultAddress],
        hexAccounts,
        null
      ]
    }
    const eventsFilterSell = {
      topics: [
        [contract.hexSignature.SellGabcoin],
        [hexVaultAddress],
        null,
        hexAccounts
      ]
    }
    const buyVaultEvents = contract
      .getAllLogs(eventsFilterBuy)
      .then((vaultTransactionsLog) => {
        const buyLogs = vaultTransactionsLog.map(logToEvent)
        return buyLogs
      }
      )
    const sellVaultEvents = contract
      .getAllLogs(eventsFilterSell)
      .then((vaultTransactionsLog) => {
        const sellLogs = vaultTransactionsLog.map(logToEvent)
        return sellLogs
      }
      )
    Promise.all([buyVaultEvents, sellVaultEvents])
      .then((logs) => {
        const allLogs = [...logs[0], ...logs[1]]
        return allLogs
      })
      .then((vaultTransactionsLog) => {
        // Creating an array of promises that will be executed to add timestamp to each entry
        // Doing so because for each entry we need to make an async call to the client
        // For additional refernce: https://stackoverflow.com/questions/39452083/using-promise-function-inside-javascript-array-map
        var promises = vaultTransactionsLog.map((log) => {
          return api.eth
            .getBlockByNumber(log.blockNumber.c[0])
            .then((block) => {
              log.timestamp = block.timestamp
              return log
            })
            .catch((error) => {
              // Sometimes Infura returns null for api.eth.getBlockByNumber, therefore we are assigning a fake timestamp to avoid
              // other issues in the app.
              log.timestamp = new Date()
              return log
            })
        })
        Promise.all(promises).then((results) => {
          this.setState({
            vaultTransactionsLogs: results,
            loading: false,
          })
        })
          .then(() => {
            console.log(`${sourceLogClass} -> Transactions list loaded`);
            this.setState({
              loading: false,
            })
          })
      })
  }

This section sets the filters on topics (the code is not exactly as above, here we also have the created event):

          // Filter for create events
          const eventsFilterCreate = {
            topics: [ 
              [dragoApi.contract.vaulteventful.hexSignature.GabcoinCreated], 
              null, 
              null,
              hexAccounts
            ]
          }
          // Filter for buy events
          const eventsFilterBuy = {
            topics: [ 
              [dragoApi.contract.vaulteventful.hexSignature.BuyGabcoin], 
              null, 
              hexAccounts,
              null
            ]
          }
          // Filter for sell events
          const eventsFilterSell = {
            topics: [ 
              [dragoApi.contract.vaulteventful.hexSignature.SellGabcoin], 
              null, 
              null,
              hexAccounts
            ]
          }

The sell and create events have the user account address as 4th parameter, while the buy event has got it as 3rd.

Because of this reason, 2 separate RPC are required if we need to get both event types. With something like this:

    const buyVaultEvents = contract
      .getAllLogs(eventsFilterBuy)
      .then((vaultTransactionsLog) => {
        const buyLogs = vaultTransactionsLog.map(logToEvent)
        return buyLogs
      }
      )
    const sellVaultEvents = contract
      .getAllLogs(eventsFilterSell)
      .then((vaultTransactionsLog) => {
        const sellLogs = vaultTransactionsLog.map(logToEvent)
        return sellLogs
      }
      )
    Promise.all([buyVaultEvents, sellVaultEvents])
      .then((logs) => {
        const allLogs = [...logs[0], ...logs[1]]
        return allLogs
      })

It would be preferable that the account address parameter be uniform among the events, so that we can get all the events with a single RPC call and then sort them client side.

Topics can be set as follow:

            topics: [ 
              [A,B], 
              null, 
              null,
              [C]
            ]

[A,B] equals to A AND B, so we can set something like:

            topics: [ 
              [buy,sell], 
              null, 
              null,
              [account]
            ]

This would return all buy and sell for that specific account.

gabririgo commented 6 years ago

buy and sell functions are absolutely identical in solidity, why do we have this behavior?

event BuyDrago(address indexed drago, address indexed from, address indexed to, uint256 amount, uint256 revenue);

event SellDrago(address indexed drago, address indexed from, address indexed to, uint256 amount, uint256 revenue);

gabririgo commented 6 years ago

the order of address from and address to in inverted as input in the function, need to spend a bit of time and understand what was the rationale and amend

gabririgo commented 6 years ago

this can be fixed by inverting the order of _who and msg.sender in SellDrago(_targetDrago, msg.sender, _who, _amount, _revenue); probably was to be able to display data in current ui please let me know if there's other events that need to be modified, besides the sell event

gabririgo commented 6 years ago

inverted and fixed, on its way to deploy