1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 09:52:26 +01:00

Merge pull request #6021 from MetaMask/i5943-shapeshift-tx

Order shapeshift transactions by time within the transactions list
This commit is contained in:
Dan J Miller 2019-01-25 14:39:18 -03:30 committed by GitHub
commit ab9c20db5b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 1029 additions and 51 deletions

File diff suppressed because one or more lines are too long

View File

@ -635,7 +635,7 @@ describe('MetaMask', function () {
await confirmButton.click() await confirmButton.click()
await delay(largeDelayMs) await delay(largeDelayMs)
driver.wait(async () => { await driver.wait(async () => {
const confirmedTxes = await findElements(driver, By.css('.transaction-list__completed-transactions .transaction-list-item')) const confirmedTxes = await findElements(driver, By.css('.transaction-list__completed-transactions .transaction-list-item'))
return confirmedTxes.length === 4 return confirmedTxes.length === 4
}, 10000) }, 10000)
@ -695,7 +695,7 @@ describe('MetaMask', function () {
await confirmButton.click() await confirmButton.click()
await delay(regularDelayMs) await delay(regularDelayMs)
driver.wait(async () => { await driver.wait(async () => {
const confirmedTxes = await findElements(driver, By.css('.transaction-list__completed-transactions .transaction-list-item')) const confirmedTxes = await findElements(driver, By.css('.transaction-list__completed-transactions .transaction-list-item'))
return confirmedTxes.length === 5 return confirmedTxes.length === 5
}, 10000) }, 10000)
@ -727,7 +727,7 @@ describe('MetaMask', function () {
await confirmButton.click() await confirmButton.click()
await delay(regularDelayMs) await delay(regularDelayMs)
driver.wait(async () => { await driver.wait(async () => {
const confirmedTxes = await findElements(driver, By.css('.transaction-list__completed-transactions .transaction-list-item')) const confirmedTxes = await findElements(driver, By.css('.transaction-list__completed-transactions .transaction-list-item'))
return confirmedTxes.length === 6 return confirmedTxes.length === 6
}, 10000) }, 10000)
@ -911,7 +911,7 @@ describe('MetaMask', function () {
await driver.wait(until.elementTextMatches(txValues[0], /-50\s*TST/), 10000) await driver.wait(until.elementTextMatches(txValues[0], /-50\s*TST/), 10000)
} }
driver.wait(async () => { await driver.wait(async () => {
const confirmedTxes = await findElements(driver, By.css('.transaction-list__completed-transactions .transaction-list-item')) const confirmedTxes = await findElements(driver, By.css('.transaction-list__completed-transactions .transaction-list-item'))
return confirmedTxes.length === 1 return confirmedTxes.length === 1
}, 10000) }, 10000)
@ -962,26 +962,29 @@ describe('MetaMask', function () {
const [gasPriceInput, gasLimitInput] = await findElements(driver, By.css('.advanced-tab__gas-edit-row__input')) const [gasPriceInput, gasLimitInput] = await findElements(driver, By.css('.advanced-tab__gas-edit-row__input'))
await gasPriceInput.clear() await gasPriceInput.clear()
await delay(tinyDelayMs) await delay(tinyDelayMs)
await gasPriceInput.sendKeys(Key.BACK_SPACE)
await gasPriceInput.sendKeys(Key.BACK_SPACE)
await gasPriceInput.sendKeys('10') await gasPriceInput.sendKeys('10')
await delay(tinyDelayMs) await delay(tinyDelayMs)
await gasLimitInput.clear() await gasLimitInput.clear()
await delay(tinyDelayMs) await delay(tinyDelayMs)
await gasLimitInput.sendKeys(Key.chord(Key.CONTROL, 'a')) await gasLimitInput.sendKeys(Key.chord(Key.CONTROL, 'a'))
await gasLimitInput.sendKeys(Key.BACK_SPACE)
await gasLimitInput.sendKeys(Key.BACK_SPACE)
await gasLimitInput.sendKeys(Key.BACK_SPACE)
await gasLimitInput.sendKeys(Key.BACK_SPACE)
await gasLimitInput.sendKeys(Key.BACK_SPACE)
await gasLimitInput.sendKeys('60000') await gasLimitInput.sendKeys('60000')
await gasLimitInput.sendKeys(Key.chord(Key.CONTROL, 'e')) await gasLimitInput.sendKeys(Key.chord(Key.CONTROL, 'e'))
// Needed for different behaviour of input in different versions of firefox
const gasLimitInputValue = await gasLimitInput.getAttribute('value')
if (gasLimitInputValue === '600001') {
await gasLimitInput.sendKeys(Key.BACK_SPACE)
}
const save = await findElement(driver, By.css('.page-container__footer-button')) const save = await findElement(driver, By.css('.page-container__footer-button'))
await save.click() await save.click()
await driver.wait(until.stalenessOf(gasModal)) await driver.wait(until.stalenessOf(gasModal))
const gasFeeInputs = await findElements(driver, By.css('.confirm-detail-row__primary')) const gasFeeInputs = await findElements(driver, By.css('.confirm-detail-row__primary'))
assert.equal(await gasFeeInputs[0].getText(), '0.0006') const renderedGasFee = await gasFeeInputs[0].getText()
assert.equal(renderedGasFee, '0.0006')
}) })
it('submits the transaction', async function () { it('submits the transaction', async function () {
@ -991,7 +994,7 @@ describe('MetaMask', function () {
}) })
it('finds the transaction in the transactions list', async function () { it('finds the transaction in the transactions list', async function () {
driver.wait(async () => { await driver.wait(async () => {
const confirmedTxes = await findElements(driver, By.css('.transaction-list__completed-transactions .transaction-list-item')) const confirmedTxes = await findElements(driver, By.css('.transaction-list__completed-transactions .transaction-list-item'))
return confirmedTxes.length === 2 return confirmedTxes.length === 2
}, 10000) }, 10000)
@ -1036,7 +1039,7 @@ describe('MetaMask', function () {
await driver.switchTo().window(extension) await driver.switchTo().window(extension)
await delay(regularDelayMs) await delay(regularDelayMs)
driver.wait(async () => { await driver.wait(async () => {
const pendingTxes = await findElements(driver, By.css('.transaction-list__pending-transactions .transaction-list-item')) const pendingTxes = await findElements(driver, By.css('.transaction-list__pending-transactions .transaction-list-item'))
return pendingTxes.length === 1 return pendingTxes.length === 1
}, 10000) }, 10000)
@ -1116,7 +1119,7 @@ describe('MetaMask', function () {
}) })
it('finds the transaction in the transactions list', async function () { it('finds the transaction in the transactions list', async function () {
driver.wait(async () => { await driver.wait(async () => {
const confirmedTxes = await findElements(driver, By.css('.transaction-list__completed-transactions .transaction-list-item')) const confirmedTxes = await findElements(driver, By.css('.transaction-list__completed-transactions .transaction-list-item'))
return confirmedTxes.length === 3 return confirmedTxes.length === 3
}, 10000) }, 10000)

View File

@ -16,7 +16,7 @@ QUnit.test('renders list items successfully', (assert) => {
global.ethQuery = global.ethQuery || {} global.ethQuery = global.ethQuery || {}
global.ethQuery.getTransactionCount = (_, cb) => { global.ethQuery.getTransactionCount = (_, cb) => {
cb(null, '0x3') cb(null, '0x4')
} }
async function runTxListItemsTest (assert, done) { async function runTxListItemsTest (assert, done) {
@ -30,25 +30,29 @@ async function runTxListItemsTest (assert, done) {
metamaskLogo[0].click() metamaskLogo[0].click()
const txListItems = await queryAsync($, '.transaction-list-item') const txListItems = await queryAsync($, '.transaction-list-item')
assert.equal(txListItems.length, 7, 'all tx list items are rendered') assert.equal(txListItems.length, 8, 'all tx list items are rendered')
const approvedTx = txListItems[0] const unapprovedMsg = txListItems[0]
const approvedTxRenderedStatus = await findAsync($(approvedTx), '.transaction-list-item__status')
assert.equal(approvedTxRenderedStatus[0].textContent, 'pending', 'approvedTx has correct label')
const unapprovedMsg = txListItems[1]
const unapprovedMsgDescription = await findAsync($(unapprovedMsg), '.transaction-list-item__action') const unapprovedMsgDescription = await findAsync($(unapprovedMsg), '.transaction-list-item__action')
assert.equal(unapprovedMsgDescription[0].textContent, 'Signature Request', 'unapprovedMsg has correct description') assert.equal(unapprovedMsgDescription[0].textContent, 'Signature Request', 'unapprovedMsg has correct description')
const shapeShiftTx = txListItems[4] const approvedTx = txListItems[2]
const shapeShiftTxStatus = await findAsync($(shapeShiftTx), '.flex-column div:eq(1)') const approvedTxRenderedStatus = await findAsync($(approvedTx), '.transaction-list-item__status')
assert.equal(shapeShiftTxStatus[0].textContent, 'No deposits received', 'shapeShiftTx has correct status') assert.equal(approvedTxRenderedStatus[0].textContent, 'pending', 'approvedTx has correct label')
const rejectedTx = txListItems[5] const confirmedTokenTx1 = txListItems[4]
const rejectedTxRenderedStatus = await findAsync($(rejectedTx), '.transaction-list-item__status') const confirmedTokenTx1Address = await findAsync($(confirmedTokenTx1), '.transaction-list-item__status')
assert.equal(rejectedTxRenderedStatus[0].textContent, 'Rejected', 'rejectedTx has correct label') assert.equal(confirmedTokenTx1Address[0].textContent, 'Confirmed', 'confirmedTokenTx has correct status')
const confirmedTokenTx = txListItems[6] const shapeShiftTx1 = txListItems[5]
const confirmedTokenTxAddress = await findAsync($(confirmedTokenTx), '.transaction-list-item__status') const shapeShiftTx1Status = await findAsync($(shapeShiftTx1), '.flex-column div:eq(1)')
assert.equal(confirmedTokenTxAddress[0].textContent, 'Confirmed', 'confirmedTokenTx has correct address') assert.equal(shapeShiftTx1Status[0].textContent, 'No deposits received', 'shapeShiftTx has correct status')
const confirmedTokenTx2 = txListItems[6]
const confirmedTokenTx2Address = await findAsync($(confirmedTokenTx2), '.transaction-list-item__status')
assert.equal(confirmedTokenTx2Address[0].textContent, 'Confirmed', 'confirmedTokenTx has correct status')
const shapeShiftTx2 = txListItems[7]
const shapeShiftTx2Address = await findAsync($(shapeShiftTx2), '.flex-column div:eq(1)')
assert.equal(shapeShiftTx2Address[0].textContent, 'No deposits received', 'shapeShiftTx has correct status')
} }

View File

@ -83,7 +83,7 @@ const insertOrderedNonce = (nonces, nonceToInsert) => {
for (let i = 0; i < nonces.length; i++) { for (let i = 0; i < nonces.length; i++) {
const nonce = nonces[i] const nonce = nonces[i]
if (Number(hexToDecimal(nonce)) < Number(hexToDecimal(nonceToInsert))) { if (Number(hexToDecimal(nonce)) > Number(hexToDecimal(nonceToInsert))) {
insertIndex = i insertIndex = i
break break
} }
@ -138,17 +138,17 @@ const insertTransactionByTime = (transactions, transaction) => {
* @param {transactionGroup[]} transactionGroups - Array of transactionGroup objects. * @param {transactionGroup[]} transactionGroups - Array of transactionGroup objects.
* @param {transactionGroup} transactionGroup - transactionGroup object to be inserted into the * @param {transactionGroup} transactionGroup - transactionGroup object to be inserted into the
* array of transactionGroups. * array of transactionGroups.
* @returns {transactionGroup[]}
*/ */
const insertTransactionGroupByTime = (transactionGroups, transactionGroup) => { const insertTransactionGroupByTime = (transactionGroups, transactionGroup) => {
const { primaryTransaction: { time } = {} } = transactionGroup const { primaryTransaction: { time: groupToInsertTime } = {} } = transactionGroup
let insertIndex = transactionGroups.length let insertIndex = transactionGroups.length
for (let i = 0; i < transactionGroups.length; i++) { for (let i = 0; i < transactionGroups.length; i++) {
const txGroup = transactionGroups[i] const txGroup = transactionGroups[i]
const { primaryTransaction: { time } = {} } = txGroup
if (txGroup.time > time) { if (time > groupToInsertTime) {
insertIndex = i insertIndex = i
break break
} }
@ -157,6 +157,22 @@ const insertTransactionGroupByTime = (transactionGroups, transactionGroup) => {
transactionGroups.splice(insertIndex, 0, transactionGroup) transactionGroups.splice(insertIndex, 0, transactionGroup)
} }
/**
* @name mergeShapeshiftTransactionGroups
* @private
* @description Inserts (mutates) shapeshift transactionGroups into an array of nonce-ordered
* transactionGroups by time. Shapeshift transactionGroups need to be sorted by time within the list
* of transactions as they do not have nonces.
* @param {transactionGroup[]} orderedTransactionGroups - Array of transactionGroups ordered by
* nonce.
* @param {transactionGroup[]} shapeshiftTransactionGroups - Array of shapeshift transactionGroups
*/
const mergeShapeshiftTransactionGroups = (orderedTransactionGroups, shapeshiftTransactionGroups) => {
shapeshiftTransactionGroups.forEach(shapeshiftGroup => {
insertTransactionGroupByTime(orderedTransactionGroups, shapeshiftGroup)
})
}
/** /**
* @name nonceSortedTransactionsSelector * @name nonceSortedTransactionsSelector
* @description Returns an array of transactionGroups sorted by nonce in ascending order. * @description Returns an array of transactionGroups sorted by nonce in ascending order.
@ -166,11 +182,12 @@ export const nonceSortedTransactionsSelector = createSelector(
transactionsSelector, transactionsSelector,
(transactions = []) => { (transactions = []) => {
const unapprovedTransactionGroups = [] const unapprovedTransactionGroups = []
const shapeshiftTransactionGroups = []
const orderedNonces = [] const orderedNonces = []
const nonceToTransactionsMap = {} const nonceToTransactionsMap = {}
transactions.forEach(transaction => { transactions.forEach(transaction => {
const { txParams: { nonce } = {}, status, type, time: txTime } = transaction const { txParams: { nonce } = {}, status, type, time: txTime, key } = transaction
if (typeof nonce === 'undefined') { if (typeof nonce === 'undefined') {
const transactionGroup = { const transactionGroup = {
@ -181,7 +198,11 @@ export const nonceSortedTransactionsSelector = createSelector(
hasCancelled: false, hasCancelled: false,
} }
insertTransactionGroupByTime(unapprovedTransactionGroups, transactionGroup) if (key === 'shapeshift') {
shapeshiftTransactionGroups.push(transactionGroup)
} else {
insertTransactionGroupByTime(unapprovedTransactionGroups, transactionGroup)
}
} else if (nonce in nonceToTransactionsMap) { } else if (nonce in nonceToTransactionsMap) {
const nonceProps = nonceToTransactionsMap[nonce] const nonceProps = nonceToTransactionsMap[nonce]
insertTransactionByTime(nonceProps.transactions, transaction) insertTransactionByTime(nonceProps.transactions, transaction)
@ -224,6 +245,7 @@ export const nonceSortedTransactionsSelector = createSelector(
}) })
const orderedTransactionGroups = orderedNonces.map(nonce => nonceToTransactionsMap[nonce]) const orderedTransactionGroups = orderedNonces.map(nonce => nonceToTransactionsMap[nonce])
mergeShapeshiftTransactionGroups(orderedTransactionGroups, shapeshiftTransactionGroups)
return unapprovedTransactionGroups.concat(orderedTransactionGroups) return unapprovedTransactionGroups.concat(orderedTransactionGroups)
} }
) )
@ -237,9 +259,7 @@ export const nonceSortedTransactionsSelector = createSelector(
export const nonceSortedPendingTransactionsSelector = createSelector( export const nonceSortedPendingTransactionsSelector = createSelector(
nonceSortedTransactionsSelector, nonceSortedTransactionsSelector,
(transactions = []) => ( (transactions = []) => (
transactions transactions.filter(({ primaryTransaction }) => primaryTransaction.status in pendingStatusHash)
.filter(({ primaryTransaction }) => primaryTransaction.status in pendingStatusHash)
.reverse()
) )
) )
@ -252,9 +272,9 @@ export const nonceSortedPendingTransactionsSelector = createSelector(
export const nonceSortedCompletedTransactionsSelector = createSelector( export const nonceSortedCompletedTransactionsSelector = createSelector(
nonceSortedTransactionsSelector, nonceSortedTransactionsSelector,
(transactions = []) => ( (transactions = []) => (
transactions.filter(({ primaryTransaction }) => { transactions
return !(primaryTransaction.status in pendingStatusHash) .filter(({ primaryTransaction }) => !(primaryTransaction.status in pendingStatusHash))
}) .reverse()
) )
) )