swarmcity/SwarmCityConcept

As a user, I can see all my transactions so I can feel secure about my history being correct.

Closed this issue · 19 comments

Abstract:

At any given time, we want the user to be able to see their transaction history. It is found in the /my-wallet view. In this iteration, transaction history is a list of items. Each item is a transaction on Ethereum’s Rinkeby network.

This should result in the user having a feeling of security and control, as the log always represents the history of past transactions.

How it works:

The API has a txHistory topic.

The client registers with the txHistory topic by sending its publicKey and the lastblock, which indicates the state of the client's local redux.
Lastblock defaults to the block when we deployed SWT token contract.

The API returns to the client the current txHistory for that pubkey from lastblock up to the current block.

The API emits to the client an update message on each new transaction ( filtered on the pubkey that was given during the registration)
Either this is a new transaction - or it is an update of the state existing transaction. The primary key is the transactionhash.

Jobs:

transactionLogIndexer

  • Is a job on the workernode that monitors the SWT contract and creates an index (LevelDB) containing the history grouped per publicKey.
  • The SWT token contract transactions are cached in a local levelDB database which emits updates on
    • reads the new mined Txes ( existing blockHeader scheduler can be re-used for this )
    • web3.eth.subscribe('pendingTransactions') => reading the pending TXes
  • The raw data is formatted to the data model described below (API).
  • The union of these 2 types of event, filtered on the user's publicKey, is this user's txHistory.

API:

  • Provides topic txHistory to subscribe to. The response of the registration contains the subscriptionId and the complete history from the cache, starting from the provided lastBlock. Sorting of these items is newest first.
  • Emits txHistoryChanged events to the client whenever a new history item for this publicKey comes in.
  • Allows clients to unsubscribe from the topic*
    *a socket disconnect unsubscribes the client from this topic.

API documentation

txHistory topic

subscribe:

/**
 * @request
 * Represents the client request
 * @param {string} publicKey - The publickey of the user
 * @param {number} lastBlock - The last block time the client has in redux
 */

{
    publicKey: <String>,
    lastBlock: <Number>,
}

subscription returns:

/**
 * Represents the txHistoryChanged response
 * @response
 * @param {number} response - The HTTP response code
 * @param {string} subscriptionId - The SubscriptionID 
 * @param {array} txHistory - Array of items 
 */
 
{ 
    response: <Number>,   
    subscriptionId: <String>,
    txHistory: <Array of historyItems>
}
Events

txHistoryChanged

/**
 * Represents a txHistory change
 * @response
 */
{
    subscriptionId: <String>,
    txHistoryChanges: <Array of historyItems>
}

txHistoryChanges can be updates or new inserts ( primary key is txhash ). An update could be an existing pending txhash changing state from pending to success.

historyItem model:

Each historyItem has following properties:

'transactionHash': '0x....' ( primary key )
'dateTime': <timestamp>
'direction': <'in'/'out'>
'amount': <in token units> ( 1e18 = 1 SWT )
'from': '0x....' 
'to': '0x....'
'block': <blocknumber where tx was mined>
'status': <0 => success , 1 => failure, 2 => pending>

What it looks like in front end:

route: /my-wallet
image

In the wallet-view, we see the transaction history at the bottom. It's a list, ordered by newest first.
It consists of historyItems. A historyItem has 3 states: 1.pending, 2.confirmed, 3.rejected.

1. Pending
The transaction has been sent to the node, but not mined yet.

It contains:

  • relative time derrived from timestamp or when the tx is older than 24 hrs, format time dd/MMM/yyyy - hh:mm
    • eg. A few minutes ago
    • eg. 12 Mar 2018 - 23:22
  • '+' or '-', indicating the direction
  • the amount (in its fullest form: show all determing digits - remove trailing 0's) + "SWT"
    • eg. 7 SWT
    • eg. 1.23 SWT
    • eg. 0.0023 SWT
  • loading dots (blue)
  • Copy describing the tx, depending on direction:
    • “Sending to” + publicKey of receiver
    • “Receiving from” + publicKey* of sender

link "show on etherscan" that links to this transaction on external (Rinkeby) explorer
image

2. Confirmed
The transaction has been mined and included in a block.

It contains:

  • relative time derrived from timestamp or when the tx is older than 24 hrs, format time dd/MMM/yyyy - hh:mm
    • eg. A few minutes ago
    • eg. 12 Mar 2018 - 23:22
  • Copy describing the tx, depending on direction:
    • “-” and the amount (in its fullest form: show all determing digits - remove trailing 0's) and “SWT” and “to” and publicKey of receiver
    • “+” and the amount (in its fullest form: show all determing digits - remove trailing 0's) and “SWT” and “from” and publicKey of sender
  • link "show on etherscan" that links to this transaction on external (Rinkeby) explorer

image

image

3. Rejected
The transaction has been mined but rejected by the network.

  • relative time derrived from timestamp or when the tx is older than 24 hrs, format time dd/MMM/yyyy - hh:mm
    • eg. A few minutes ago
    • eg. 12 Mar 2018 - 23:22
  • Copy describing the tx, depending on direction:
    • “Failed:” and “-” and the amount (in its fullest form: show all determing digits - remove trailing 0's) and “SWT” and “to” and publicKey of receiver and “failed.”
    • “Failed:” and “+” and the amount (in its fullest form: show all determing digits - remove trailing 0's) and “SWT” and “from” and publicKey of sender and “failed.”
  • link "show on etherscan" that links to this transaction on external (Rinkeby) explorer

image

Documentation / references

Example:

var subscription = web3.eth.subscribe('pendingTransactions', function(error, result){
    if (!error)
        console.log(result);
})
.on("data", function(transaction){
    console.log(transaction);
});

// unsubscribes the subscription
subscription.unsubscribe(function(error, success){
    if(success)
        console.log('Successfully unsubscribed!');
});

pending transactions: http://web3js.readthedocs.io/en/1.0/web3-eth-subscribe.html#subscribe-pendingtransactions

new blocks: http://web3js.readthedocs.io/en/1.0/web3-eth-subscribe.html#subscribe-newblockheaders

Since a txHistory Item only has two possible states, either success or failure, I assume pending transactions have to be processed on the front-end. I propose on front-end, at transaction creation, we fill the client-side txHistoryArray with a historyItem with the same data as one would expect to receive from the API.

Whenever the API triggers txHistoryChanged with a historyItem with the same tx hash, we can replace the pending item with the success/failure one.

Question: Since a user refresh will drop the pending item from txHistory, do we want to copy this update to localStorage? Please advise.

UPDATE: It has been decided:

  • Pending transactions are now handled by the API, no need for front-end logic on this.
  • Page refresh/subscription closing will still drop pending items, but is issue for later
bkawk commented

In the design, it clearly shows a name for who the transaction is with, yet in the history item model, there is no name being returned.

The number 44 SWT as shown in the design looks nice, I would like to see how this will look with 18 decimal places to ensure it still looks good on a mobile device.

Changed in the epic:

  • Topic pending transactions:
    After discussing we decided to change histroyItem model to: 'status': <0 => pending , 1 => success, 2 => failed>
    For now we are not taking into account the user disconnecting during pending transactions.

  • In the design, it clearly shows a name for who the transaction is with, yet in the history item model, there is no name being returned. => changed to publicKey

  • The number 44 SWT as shown in the design looks nice, I would like to see how this will look with 18 decimal places to ensure it still looks good on a mobile device. is described in issue swarmcity/SwarmCityDapp#574

This is EPIC documentation. It will be great for a wiki and for the community later!

bkawk commented

Please can we maintain correct case and full names
pubkey => publicKey
lastblock => lastBlock

19/3: issue is clear for dev, ready for execution

Please confirm/correct my assumption:

Currently the spec says the list should be ordered by 'newest first'.

Should I make an exception for pending transactions, i.e. putting them always first, regardless if newer transactions have been confirmed after older pending ones?

If so, should this be handled front-end or at API level? (I would prefer at API level).

@faffydee Can I get the color/font schemes your prefer for the different states?

@xardass let's make it as described in the spec, newest first.

further clarification: There is no need on the front-end to count confirmations to flag a transaction as successful.

I think there is no quick and easy way to get the failed transactions, since failed transactions don't generate events. For example, this code returns only 113 events, which doesn't match what can be seen on etherscan.

Also it seems that there is some more inconsistency that I would like to analalize about what is shown in etherscan.

Some of the missing transactions between what returns getPastEvents and what appears in etherscan is due to the used version of minime.
In this version the transfer event is not generated when the amount transferred is 0, as if it happens in new versions of minime.
Example: 0x6ea1a80d557b2756389ea16e448111155cb3184f6f1e8c7de62771cf1a68f606

@eduadiez Rinkeby SWT does not have to match the tokencontract version on mainnet.
It's more important for the bridging later that we have a rinkeby SWT token contract that does generate the events.

As far as I know these are the events we can get in:

  • Pending transaction
  • Successful transaction
  • Failed transaction (out-of-gas)

@eduadiez Is this correct?

My suggestion is in this iteration we leave out "failed transactions". Other people are looking into creating an open source block explorer we later will be able to use.

BvL13 commented

@kingflurkel I agree to leave it out. Please change the description and delete all parts that cover failed/rejected transactions.
This would be in:
historyItem model
'status': <0 => success , 1 => failure, 2 => pending>

What it looks like in front end:
3. Rejected

Thank you.

@BvL13 Below the updated epic.
Changes:

  • I removed the rejected/failed references
  • I changed publicKey to address so we use the correct Ethereum word

As a user, I can see all my transactions so I can feel secure about my history being correct.

Abstract:

At any given time, we want the user to be able to see their transaction history. It is found in the /my-wallet view. In this iteration, transaction history is a list of items. Each item is a pending or successful transaction.

This should result in the user having a feeling of security and control, as the log always represents the history of past transactions.

How it works:

The API has a txHistory topic.

The client registers with the txHistory topic by sending its address and the lastblock, which indicates the state of the client's local redux.
Lastblock defaults to the block when we deployed SWT token contract.

The API returns to the client the current txHistory for that address from lastblock up to the current block.

The API emits to the client an update message on each new transaction ( filtered on the address that was given during the registration)
Either this is a new transaction - or it is an update of the state existing transaction. The primary key is the transactionhash.

Jobs:

transactionLogIndexer

  • Is a job on the workernode that monitors the SWT contract and creates an index (LevelDB) containing the history grouped per address.
  • The SWT token contract transactions are cached in a local levelDB database which emits updates on
    • reads the new mined Txes ( existing blockHeader scheduler can be re-used for this )
    • web3.eth.subscribe('pendingTransactions') => reading the pending TXes
  • The raw data is formatted to the data model described below (API).
  • The union of these 2 types of event, filtered on the user's address, is this user's txHistory.

API:

  • Provides topic txHistory to subscribe to. The response of the registration contains the subscriptionId and the complete history from the cache, starting from the provided lastBlock. Sorting of these items is newest first.
  • Emits txHistoryChanged events to the client whenever a new history item for this address comes in.
  • Allows clients to unsubscribe from the topic*
    *a socket disconnect unsubscribes the client from this topic.

API documentation

txHistory topic

subscribe:

/**
 * @request
 * Represents the client request
 * @param {string} address - The address of the user
 * @param {number} lastBlock - The last block time the client has in redux
 */

{
    address: <String>,
    lastBlock: <Number>,
}

subscription returns:

/**
 * Represents the txHistoryChanged response
 * @response
 * @param {number} response - The HTTP response code
 * @param {string} subscriptionId - The SubscriptionID 
 * @param {array} txHistory - Array of items 
 */
 
{ 
    response: <Number>,   
    subscriptionId: <String>,
    txHistory: <Array of historyItems>
}
Events

txHistoryChanged

/**
 * Represents a txHistory change
 * @response
 */
{
    subscriptionId: <String>,
    txHistoryChanges: <Array of historyItems>
}

txHistoryChanges can be updates or new inserts ( primary key is txhash ). An update could be an existing pending txhash changing state from pending to success.

historyItem model:

Each historyItem has following properties:

'transactionHash': '0x....' ( primary key )
'dateTime': <timestamp>
'direction': <'in'/'out'>
'amount': <in token units> ( 1e18 = 1 SWT )
'from': '0x....' 
'to': '0x....'
'block': <blocknumber where tx was mined>
'status': <0 => pending, 1 => success>

What it looks like in front end:

route: /my-wallet
image

In the wallet-view, we see the transaction history at the bottom. It's a list, ordered by newest first.
It consists of historyItems. A historyItem has 3 states: 1.pending, 2.confirmed, 3.rejected.

1. Pending
The transaction has been sent to the node, but not mined yet.

It contains:

  • relative time derrived from timestamp or when the tx is older than 24 hrs, format time dd/MMM/yyyy - hh:mm
    • eg. A few minutes ago
    • eg. 12 Mar 2018 - 23:22
  • '+' or '-', indicating the direction
  • the amount (in its fullest form: show all determing digits - remove trailing 0's) + "SWT"
    • eg. 7 SWT
    • eg. 1.23 SWT
    • eg. 0.0023 SWT
  • loading dots (blue)
  • Copy describing the tx, depending on direction:
    • “Sending to” + address of receiver
    • “Receiving from” + address* of sender

link "show on etherscan" that links to this transaction on external (Rinkeby) explorer
image

2. Confirmed
The transaction has been mined and included in a block.

It contains:

  • relative time derrived from timestamp or when the tx is older than 24 hrs, format time dd/MMM/yyyy - hh:mm
    • eg. A few minutes ago
    • eg. 12 Mar 2018 - 23:22
  • Copy describing the tx, depending on direction:
    • “-” and the amount (in its fullest form: show all determing digits - remove trailing 0's) and “SWT” and “to” and publicKey of receiver
    • “+” and the amount (in its fullest form: show all determing digits - remove trailing 0's) and “SWT” and “from” and publicKey of sender
  • link "show on etherscan" that links to this transaction on external (Rinkeby) explorer

image

image

Documentation / references

Example:

var subscription = web3.eth.subscribe('pendingTransactions', function(error, result){
    if (!error)
        console.log(result);
})
.on("data", function(transaction){
    console.log(transaction);
});

// unsubscribes the subscription
subscription.unsubscribe(function(error, success){
    if(success)
        console.log('Successfully unsubscribed!');
});

pending transactions: http://web3js.readthedocs.io/en/1.0/web3-eth-subscribe.html#subscribe-pendingtransactions

new blocks: http://web3js.readthedocs.io/en/1.0/web3-eth-subscribe.html#subscribe-newblockheaders

Update: The API only sends back a list of successful transactions. Failed and pending tx's are not being processed by the API at this moment, although tx items do get a code '0' flagging them as succesful (so we can add the other codes later).

On front-end, at transaction creation, we fill the client-side txHistoryArray with a historyItem with the same data as one would expect to receive from the API, except with code '2': pending.

The API will return an object with all the user's transaction data on every update of this array. Whenever the client gets an update of this Array, it will replace the pending tx's with txHash as key.

@eduadiez do you think it is possible to order the list of HistoryItems according to their txHash? So I can use this txHash as key for checking if the same one already exists (as a pending tranasction on the front-end). We might need to rewrite the Epic accordingly to reflect this need.

The front-end now defaults to state 'success', so we don't need to add a status success from the API anymore. Only for future implementation, if we add failed/pending tx's we then can add an extra property to identify those.