Skip to content

Commit

Permalink
WIP: Improve TransactionV2 implementation (#349)
Browse files Browse the repository at this point in the history
* Add from field to SendTx type

* add amount to claim rewards transactions

* convert to units in string coin reducer

* fix typo

* add multidenom string coinreducer for claim amount

* Add UnknownTx to schema

* Add BlockV2 type which returns TransactionV2 txs

* Add blockV2 query that returns TransactionV2 txs

* kill handling claim rewards amount

* Update lib/reducers/cosmosV0-reducers.js

Co-Authored-By: Fabian <[email protected]>

* Update lib/reducers/cosmosV0-reducers.js

Co-Authored-By: Fabian <[email protected]>

* Cleanup

* lint

* Support claim rewards from multiple validators

* Fix, cleanup

Co-authored-by: Ana G. <[email protected]>
Co-authored-by: Fabian <[email protected]>
  • Loading branch information
3 people authored Feb 26, 2020
1 parent c6d5c48 commit fbc5c71
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 16 deletions.
2 changes: 1 addition & 1 deletion lib/message-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const lunieMessageTypes = {
UNSTAKE: `UnstakeTx`,
VOTE: `VoteTx`,
DEPOSIT: `DepositTx`,
WITHDRAW_DELEGATION_REWARDS: `ClaimRewardsTx`,
CLAIM_REWARDS: `ClaimRewardsTx`,
SUBMIT_PROPOSAL: `SubmitProposalTx`,
UNKNOWN: `UnknownTx`
}
Expand Down
36 changes: 25 additions & 11 deletions lib/reducers/cosmosV0-reducers.js
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ function formatTransactionsReducer(txs, reducers) {
return reversedTxs.map(tx => transactionReducer(tx, reducers))
}

function transactionReducerV2(transaction, reducers) {
function transactionReducerV2(transaction, reducers, stakingDenom) {
// TODO check if this is anywhere not an array
let fees
if (Array.isArray(transaction.tx.value.fee.amount)) {
Expand All @@ -451,7 +451,13 @@ function transactionReducerV2(transaction, reducers) {
type: getMessageType(type),
hash: transaction.txhash,
height: transaction.height,
details: transactionDetailsReducer(getMessageType(type), value, reducers),
details: transactionDetailsReducer(
getMessageType(type),
value,
reducers,
transaction,
stakingDenom
),
timestamp: transaction.timestamp,
memo: transaction.tx.value.memo,
fees,
Expand All @@ -460,13 +466,15 @@ function transactionReducerV2(transaction, reducers) {
return returnedMessages
}

function transactionsReducerV2(txs, reducers) {
function transactionsReducerV2(txs, reducers, stakingDenom) {
const duplicateFreeTxs = uniqWith(txs, (a, b) => a.txhash === b.txhash)
const sortedTxs = sortBy(duplicateFreeTxs, ['timestamp'])
const reversedTxs = reverse(sortedTxs)
// here we filter out all transactions related to validators
return reversedTxs.reduce((collection, transaction) => {
return collection.concat(transactionReducerV2(transaction, reducers))
return collection.concat(
transactionReducerV2(transaction, reducers, stakingDenom)
)
}, [])
}

Expand Down Expand Up @@ -537,7 +545,7 @@ function getMessageType(type) {
case 'MsgUndelegate':
return lunieMessageTypes.UNSTAKE
case 'MsgWithdrawDelegationReward':
return lunieMessageTypes.WITHDRAW_DELEGATION_REWARDS
return lunieMessageTypes.CLAIM_REWARDS
case 'MsgSubmitProposal':
return lunieMessageTypes.SUBMIT_PROPOSAL
case 'MsgVote':
Expand All @@ -550,7 +558,7 @@ function getMessageType(type) {
}

// function to map cosmos messages to our details format
function transactionDetailsReducer(type, message, reducers) {
function transactionDetailsReducer(type, message, reducers, transaction) {
let details
switch (type) {
case lunieMessageTypes.SEND:
Expand All @@ -565,8 +573,8 @@ function transactionDetailsReducer(type, message, reducers) {
case lunieMessageTypes.UNSTAKE:
details = unstakeDetailsReducer(message, reducers)
break
case lunieMessageTypes.WITHDRAW_DELEGATION_REWARDS:
details = claimRewardsDetailsReducer(message, reducers)
case lunieMessageTypes.CLAIM_REWARDS:
details = claimRewardsDetailsReducer(transaction.tx.value.msg)
break
case lunieMessageTypes.SUBMIT_PROPOSAL:
details = submitProposalDetailsReducer(message, reducers)
Expand All @@ -589,6 +597,7 @@ function transactionDetailsReducer(type, message, reducers) {

function sendDetailsReducer(message, reducers) {
return {
from: [message.from_address],
to: [message.to_address],
amount: reducers.coinReducer(message.amount[0])
}
Expand Down Expand Up @@ -616,10 +625,15 @@ function unstakeDetailsReducer(message, reducers) {
}
}

function claimRewardsDetailsReducer(message, reducers) {
function claimRewardsDetailsReducer(messages) {
return {
from: [message.validator_address],
amount: reducers.coinReducer(message.amount)
from: messages
.filter(msg => msg.type.split(`/`)[1] === `MsgWithdrawDelegationReward`)
.map(msg => msg.value.validator_address),
amount: {
amount: 0,
denom: ``
}
}
}

Expand Down
5 changes: 5 additions & 0 deletions lib/resolvers.js
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,11 @@ const resolvers = {
cacheControl.setCacheHint({ maxAge })
return remoteFetch(dataSources, networkId).getBlockByHeight(height)
},
blockV2: (_, { networkId, height }, { dataSources }, { cacheControl }) => {
const maxAge = height ? 60 : 10
cacheControl.setCacheHint({ maxAge })
return remoteFetch(dataSources, networkId).getBlockByHeightV2(height)
},
network: (_, { id }) => {
const network = networkMap[id]
if (network.id === 'local-cosmos-hub-testnet') {
Expand Down
20 changes: 19 additions & 1 deletion lib/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,16 @@ const typeDefs = gql`
proposer_address: String
}
type BlockV2 @cacheControl(maxAge: 10) {
networkId: String!
height: Int
hash: String
chainId: String
time: String
transactions: [TransactionV2]
proposer_address: String
}
type Maintenance {
id: Int!
message: String
Expand Down Expand Up @@ -166,12 +176,13 @@ const typeDefs = gql`
| SubmitProposalTx
| VoteTx
| DepositTx
| UnknownTx
type TransactionV2 {
type: String!
hash: String!
height: Int!
details: TransactionDetails
details: TransactionDetails!
timestamp: String!
memo: String
fees: [Coin]!
Expand All @@ -180,6 +191,7 @@ const typeDefs = gql`
type SendTx {
amount: Coin!
from: [String]!
to: [String]!
}
Expand All @@ -197,6 +209,7 @@ const typeDefs = gql`
type UnstakeTx {
amount: Coin!
from: [String]!
liquidDate: String
}
type ClaimRewardsTx {
Expand All @@ -221,6 +234,10 @@ const typeDefs = gql`
amount: Coin!
}
type UnknownTx {
blockExplorerLink: String
}
type GovernanceParameters {
depositDenom: String
votingThreshold: Float
Expand Down Expand Up @@ -270,6 +287,7 @@ const typeDefs = gql`
type Query {
block(networkId: String!, height: Int): Block
blockV2(networkId: String!, height: Int): BlockV2
proposal(networkId: String!, id: Int!): Proposal
proposals(networkId: String!): [Proposal]
validators(
Expand Down
33 changes: 31 additions & 2 deletions lib/source/cosmosV0-source.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ class CosmosV0API extends RESTDataSource {
return this.getRetry(url)
}

async getStakinDenom() {
async getStakingDenom() {
const stakingParameters = await this.query('/staking/parameters')
return stakingParameters.bond_denom
}
Expand Down Expand Up @@ -125,6 +125,17 @@ class CosmosV0API extends RESTDataSource {
: []
}

async getTransactionsV2ByHeight(height) {
const txs = await this.loadPaginatedTxs(`txs?tx.height=${height}`)
return Array.isArray(txs)
? this.reducers.transactionsReducerV2(
txs,
this.reducers,
this.getStakingDenom()
)
: []
}

async getValidatorSigningInfos(validators) {
const signingInfos = await Promise.all(
validators.map(({ consensus_pubkey }) =>
Expand Down Expand Up @@ -337,6 +348,24 @@ class CosmosV0API extends RESTDataSource {
return this.reducers.blockReducer(this.networkId, block, transactions)
}

async getBlockByHeightV2(blockHeight) {
let block, transactions
if (blockHeight) {
const response = await Promise.all([
this.getRetry(`blocks/${blockHeight}`),
this.getTransactionsV2ByHeight(blockHeight)
])
block = response[0]
transactions = response[1]
} else {
block = await this.getRetry(`blocks/latest`)
transactions = await this.getTransactionsV2ByHeight(
block.block_meta.header.height
)
}
return this.reducers.blockReducer(this.networkId, block, transactions)
}

async getBalancesFromAddress(address) {
this.checkAddress(address)
const response = await this.query(`bank/balances/${address}`)
Expand Down Expand Up @@ -476,7 +505,7 @@ class CosmosV0API extends RESTDataSource {
delegatorAddress,
validatorsDictionary
),
this.getStakinDenom()
this.getStakingDenom()
])
const rewards = await this.getRewards(
delegatorAddress,
Expand Down
3 changes: 2 additions & 1 deletion lib/source/cosmosV2-source.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ class CosmosV2API extends CosmosV0API {
this.loadPaginatedTxs(`/txs?transfer.recipient=${address}`)
]).then(([senderTxs, recipientTxs]) => [].concat(senderTxs, recipientTxs))

return this.reducers.transactionsReducerV2(txs, this.reducers)
const stakingDenom = await this.getStakingDenom()
return this.reducers.transactionsReducerV2(txs, this.reducers, stakingDenom)
}

extractInvolvedAddresses(transaction) {
Expand Down

0 comments on commit fbc5c71

Please sign in to comment.