commit
be91171194
@ -1,52 +0,0 @@ |
|||||||
<html> |
|
||||||
<head> |
|
||||||
<title>MetaMask</title> |
|
||||||
<style> |
|
||||||
*{ |
|
||||||
padding: 0; |
|
||||||
margin: 0; |
|
||||||
box-sizing: border-box; |
|
||||||
} |
|
||||||
img{ |
|
||||||
display: block; |
|
||||||
} |
|
||||||
html, body{ |
|
||||||
display: flex; |
|
||||||
justify-content: center; |
|
||||||
align-items: center; |
|
||||||
width: 100%; |
|
||||||
height: 100%; |
|
||||||
} |
|
||||||
.app{ |
|
||||||
position: relative; |
|
||||||
width: 100%; |
|
||||||
height: auto; |
|
||||||
overflow: hidden; |
|
||||||
} |
|
||||||
img{ |
|
||||||
display: block; |
|
||||||
width: 100%; |
|
||||||
height: auto; |
|
||||||
} |
|
||||||
h2{ |
|
||||||
display: block; |
|
||||||
width: 100%; |
|
||||||
overflow: hidden; |
|
||||||
position: absolute; |
|
||||||
bottom: 20%; |
|
||||||
left: 0; |
|
||||||
color: #1b243d; |
|
||||||
text-align: center; |
|
||||||
} |
|
||||||
h2 > a{ |
|
||||||
color: #1b243d; |
|
||||||
} |
|
||||||
</style> |
|
||||||
</head> |
|
||||||
<body> |
|
||||||
<div class="app"> |
|
||||||
<img src="./images/404.png" alt=""> |
|
||||||
<h2>Powered by <a href="https://www.portal.network/">Portal Network</a></h2> |
|
||||||
</div> |
|
||||||
</body> |
|
||||||
</html> |
|
@ -1,79 +0,0 @@ |
|||||||
<html> |
|
||||||
<head> |
|
||||||
<title>MetaMask Error</title> |
|
||||||
<link href="https://fonts.googleapis.com/css?family=Rokkitt" rel="stylesheet"> |
|
||||||
<style> |
|
||||||
*{ |
|
||||||
padding: 0; |
|
||||||
margin: 0; |
|
||||||
box-sizing: border-box; |
|
||||||
} |
|
||||||
img{ |
|
||||||
display: block; |
|
||||||
} |
|
||||||
html, body{ |
|
||||||
display: flex; |
|
||||||
justify-content: center; |
|
||||||
align-items: center; |
|
||||||
width: 100%; |
|
||||||
height: 100%; |
|
||||||
} |
|
||||||
@keyframes logoAmin{ |
|
||||||
from {transform: scale(1);} |
|
||||||
50%{transform: scale(1.1);} |
|
||||||
to {transform: scale(1);} |
|
||||||
} |
|
||||||
.errorBox{ |
|
||||||
width: 70%; |
|
||||||
height: auto; |
|
||||||
overflow: hidden; |
|
||||||
background-image: url("./images/deadface.png"); |
|
||||||
background-repeat: no-repeat; |
|
||||||
background-position: 100% 50%; |
|
||||||
background-size: auto 90%; |
|
||||||
padding: 5px; |
|
||||||
} |
|
||||||
.errorBox > img{ |
|
||||||
width: 100px; |
|
||||||
height: auto; |
|
||||||
margin-bottom: 25px; |
|
||||||
animation: logoAmin 1s infinite linear; |
|
||||||
} |
|
||||||
.errorBox > h1, .errorBox > h2{ |
|
||||||
letter-spacing: 2px; |
|
||||||
} |
|
||||||
.errorBox > h1{ |
|
||||||
color: #9b9b9b; |
|
||||||
font-size: 40px; |
|
||||||
} |
|
||||||
.errorBox > h2{ |
|
||||||
color: #1b243d; |
|
||||||
font-size: 20px; |
|
||||||
padding-top: 5px; |
|
||||||
} |
|
||||||
.errorBox > h2 >a{ |
|
||||||
color: #1b243d; |
|
||||||
} |
|
||||||
.errorBox > h2 >a:hover{ |
|
||||||
color: #44588e; |
|
||||||
} |
|
||||||
|
|
||||||
.errorBox > h1 > span{ |
|
||||||
color: #33559f; |
|
||||||
} |
|
||||||
|
|
||||||
</style> |
|
||||||
</head> |
|
||||||
<body> |
|
||||||
<div class="errorBox"> |
|
||||||
<img src="./images/logo.png" alt=""> |
|
||||||
<h1><span id="name"></span> not found</h1> |
|
||||||
<h2>Powered by <a href="https://www.portal.network/">Portal Network</a></h2> |
|
||||||
</div> |
|
||||||
<script> |
|
||||||
let index = location.href.lastIndexOf("?name=") |
|
||||||
let name = location.href.slice(index + 6) |
|
||||||
document.getElementById("name").innerHTML = name |
|
||||||
</script> |
|
||||||
</body> |
|
||||||
</html> |
|
After Width: | Height: | Size: 2.5 KiB |
@ -1,205 +0,0 @@ |
|||||||
const ObservableStore = require('obs-store') |
|
||||||
const extend = require('xtend') |
|
||||||
const log = require('loglevel') |
|
||||||
|
|
||||||
// every ten minutes
|
|
||||||
const POLLING_INTERVAL = 600000 |
|
||||||
|
|
||||||
class CurrencyController { |
|
||||||
|
|
||||||
/** |
|
||||||
* Controller responsible for managing data associated with the currently selected currency. |
|
||||||
* |
|
||||||
* @typedef {Object} CurrencyController |
|
||||||
* @param {object} opts Overrides the defaults for the initial state of this.store |
|
||||||
* @property {array} opts.initState initializes the the state of the CurrencyController. Can contain an |
|
||||||
* currentCurrency, conversionRate and conversionDate properties |
|
||||||
* @property {string} currentCurrency A 2-4 character shorthand that describes a specific currency, currently |
|
||||||
* selected by the user |
|
||||||
* @property {number} conversionRate The conversion rate from ETH to the selected currency. |
|
||||||
* @property {string} conversionDate The date at which the conversion rate was set. Expressed in in milliseconds |
|
||||||
* since midnight of January 1, 1970 |
|
||||||
* @property {number} conversionInterval The id of the interval created by the scheduleConversionInterval method. |
|
||||||
* Used to clear an existing interval on subsequent calls of that method. |
|
||||||
* @property {string} nativeCurrency The ticker/symbol of the native chain currency |
|
||||||
* |
|
||||||
*/ |
|
||||||
constructor (opts = {}) { |
|
||||||
const initState = extend({ |
|
||||||
currentCurrency: 'usd', |
|
||||||
conversionRate: 0, |
|
||||||
conversionDate: 'N/A', |
|
||||||
nativeCurrency: 'ETH', |
|
||||||
}, opts.initState) |
|
||||||
this.store = new ObservableStore(initState) |
|
||||||
} |
|
||||||
|
|
||||||
//
|
|
||||||
// PUBLIC METHODS
|
|
||||||
//
|
|
||||||
|
|
||||||
/** |
|
||||||
* A getter for the nativeCurrency property |
|
||||||
* |
|
||||||
* @returns {string} A 2-4 character shorthand that describes the specific currency |
|
||||||
* |
|
||||||
*/ |
|
||||||
getNativeCurrency () { |
|
||||||
return this.store.getState().nativeCurrency |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* A setter for the nativeCurrency property |
|
||||||
* |
|
||||||
* @param {string} nativeCurrency The new currency to set as the nativeCurrency in the store |
|
||||||
* |
|
||||||
*/ |
|
||||||
setNativeCurrency (nativeCurrency) { |
|
||||||
this.store.updateState({ |
|
||||||
nativeCurrency, |
|
||||||
ticker: nativeCurrency, |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* A getter for the currentCurrency property |
|
||||||
* |
|
||||||
* @returns {string} A 2-4 character shorthand that describes a specific currency, currently selected by the user |
|
||||||
* |
|
||||||
*/ |
|
||||||
getCurrentCurrency () { |
|
||||||
return this.store.getState().currentCurrency |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* A setter for the currentCurrency property |
|
||||||
* |
|
||||||
* @param {string} currentCurrency The new currency to set as the currentCurrency in the store |
|
||||||
* |
|
||||||
*/ |
|
||||||
setCurrentCurrency (currentCurrency) { |
|
||||||
this.store.updateState({ currentCurrency }) |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* A getter for the conversionRate property |
|
||||||
* |
|
||||||
* @returns {string} The conversion rate from ETH to the selected currency. |
|
||||||
* |
|
||||||
*/ |
|
||||||
getConversionRate () { |
|
||||||
return this.store.getState().conversionRate |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* A setter for the conversionRate property |
|
||||||
* |
|
||||||
* @param {number} conversionRate The new rate to set as the conversionRate in the store |
|
||||||
* |
|
||||||
*/ |
|
||||||
setConversionRate (conversionRate) { |
|
||||||
this.store.updateState({ conversionRate }) |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* A getter for the conversionDate property |
|
||||||
* |
|
||||||
* @returns {string} The date at which the conversion rate was set. Expressed in milliseconds since midnight of |
|
||||||
* January 1, 1970 |
|
||||||
* |
|
||||||
*/ |
|
||||||
getConversionDate () { |
|
||||||
return this.store.getState().conversionDate |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* A setter for the conversionDate property |
|
||||||
* |
|
||||||
* @param {number} conversionDate The date, expressed in milliseconds since midnight of January 1, 1970, that the |
|
||||||
* conversionRate was set |
|
||||||
* |
|
||||||
*/ |
|
||||||
setConversionDate (conversionDate) { |
|
||||||
this.store.updateState({ conversionDate }) |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Updates the conversionRate and conversionDate properties associated with the currentCurrency. Updated info is |
|
||||||
* fetched from an external API |
|
||||||
* |
|
||||||
*/ |
|
||||||
async updateConversionRate () { |
|
||||||
let currentCurrency, nativeCurrency |
|
||||||
try { |
|
||||||
currentCurrency = this.getCurrentCurrency() |
|
||||||
nativeCurrency = this.getNativeCurrency() |
|
||||||
// select api
|
|
||||||
let apiUrl |
|
||||||
if (nativeCurrency === 'ETH') { |
|
||||||
// ETH
|
|
||||||
apiUrl = `https://api.infura.io/v1/ticker/eth${currentCurrency.toLowerCase()}` |
|
||||||
} else { |
|
||||||
// ETC
|
|
||||||
apiUrl = `https://min-api.cryptocompare.com/data/price?fsym=${nativeCurrency.toUpperCase()}&tsyms=${currentCurrency.toUpperCase()}` |
|
||||||
} |
|
||||||
// attempt request
|
|
||||||
let response |
|
||||||
try { |
|
||||||
response = await fetch(apiUrl) |
|
||||||
} catch (err) { |
|
||||||
log.error(new Error(`CurrencyController - Failed to request currency from Infura:\n${err.stack}`)) |
|
||||||
return |
|
||||||
} |
|
||||||
// parse response
|
|
||||||
let rawResponse |
|
||||||
let parsedResponse |
|
||||||
try { |
|
||||||
rawResponse = await response.text() |
|
||||||
parsedResponse = JSON.parse(rawResponse) |
|
||||||
} catch (err) { |
|
||||||
log.error(new Error(`CurrencyController - Failed to parse response "${rawResponse}"`)) |
|
||||||
return |
|
||||||
} |
|
||||||
// set conversion rate
|
|
||||||
if (nativeCurrency === 'ETH') { |
|
||||||
// ETH
|
|
||||||
this.setConversionRate(Number(parsedResponse.bid)) |
|
||||||
this.setConversionDate(Number(parsedResponse.timestamp)) |
|
||||||
} else { |
|
||||||
// ETC
|
|
||||||
if (parsedResponse[currentCurrency.toUpperCase()]) { |
|
||||||
this.setConversionRate(Number(parsedResponse[currentCurrency.toUpperCase()])) |
|
||||||
this.setConversionDate(parseInt((new Date()).getTime() / 1000)) |
|
||||||
} else { |
|
||||||
this.setConversionRate(0) |
|
||||||
this.setConversionDate('N/A') |
|
||||||
} |
|
||||||
} |
|
||||||
} catch (err) { |
|
||||||
// reset current conversion rate
|
|
||||||
log.warn(`MetaMask - Failed to query currency conversion:`, nativeCurrency, currentCurrency, err) |
|
||||||
this.setConversionRate(0) |
|
||||||
this.setConversionDate('N/A') |
|
||||||
// throw error
|
|
||||||
log.error(new Error(`CurrencyController - Failed to query rate for currency "${currentCurrency}":\n${err.stack}`)) |
|
||||||
return |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Creates a new poll, using setInterval, to periodically call updateConversionRate. The id of the interval is |
|
||||||
* stored at the controller's conversionInterval property. If it is called and such an id already exists, the |
|
||||||
* previous interval is clear and a new one is created. |
|
||||||
* |
|
||||||
*/ |
|
||||||
scheduleConversionInterval () { |
|
||||||
if (this.conversionInterval) { |
|
||||||
clearInterval(this.conversionInterval) |
|
||||||
} |
|
||||||
this.conversionInterval = setInterval(() => { |
|
||||||
this.updateConversionRate() |
|
||||||
}, POLLING_INTERVAL) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
module.exports = CurrencyController |
|
@ -1,161 +0,0 @@ |
|||||||
const EthQuery = require('ethjs-query') |
|
||||||
const assert = require('assert') |
|
||||||
const Mutex = require('await-semaphore').Mutex |
|
||||||
/** |
|
||||||
@param opts {Object} |
|
||||||
@param {Object} opts.provider a ethereum provider |
|
||||||
@param {Function} opts.getPendingTransactions a function that returns an array of txMeta |
|
||||||
whosee status is `submitted` |
|
||||||
@param {Function} opts.getConfirmedTransactions a function that returns an array of txMeta |
|
||||||
whose status is `confirmed` |
|
||||||
@class |
|
||||||
*/ |
|
||||||
class NonceTracker { |
|
||||||
|
|
||||||
constructor ({ provider, blockTracker, getPendingTransactions, getConfirmedTransactions }) { |
|
||||||
this.provider = provider |
|
||||||
this.blockTracker = blockTracker |
|
||||||
this.ethQuery = new EthQuery(provider) |
|
||||||
this.getPendingTransactions = getPendingTransactions |
|
||||||
this.getConfirmedTransactions = getConfirmedTransactions |
|
||||||
this.lockMap = {} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
@returns {Promise<Object>} with the key releaseLock (the gloabl mutex) |
|
||||||
*/ |
|
||||||
async getGlobalLock () { |
|
||||||
const globalMutex = this._lookupMutex('global') |
|
||||||
// await global mutex free
|
|
||||||
const releaseLock = await globalMutex.acquire() |
|
||||||
return { releaseLock } |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @typedef NonceDetails |
|
||||||
* @property {number} highestLocallyConfirmed - A hex string of the highest nonce on a confirmed transaction. |
|
||||||
* @property {number} nextNetworkNonce - The next nonce suggested by the eth_getTransactionCount method. |
|
||||||
* @property {number} highestSuggested - The maximum between the other two, the number returned. |
|
||||||
*/ |
|
||||||
|
|
||||||
/** |
|
||||||
this will return an object with the `nextNonce` `nonceDetails` of type NonceDetails, and the releaseLock |
|
||||||
Note: releaseLock must be called after adding a signed tx to pending transactions (or discarding). |
|
||||||
|
|
||||||
@param address {string} the hex string for the address whose nonce we are calculating |
|
||||||
@returns {Promise<NonceDetails>} |
|
||||||
*/ |
|
||||||
async getNonceLock (address) { |
|
||||||
// await global mutex free
|
|
||||||
await this._globalMutexFree() |
|
||||||
// await lock free, then take lock
|
|
||||||
const releaseLock = await this._takeMutex(address) |
|
||||||
try { |
|
||||||
// evaluate multiple nextNonce strategies
|
|
||||||
const nonceDetails = {} |
|
||||||
const networkNonceResult = await this._getNetworkNextNonce(address) |
|
||||||
const highestLocallyConfirmed = this._getHighestLocallyConfirmed(address) |
|
||||||
const nextNetworkNonce = networkNonceResult.nonce |
|
||||||
const highestSuggested = Math.max(nextNetworkNonce, highestLocallyConfirmed) |
|
||||||
|
|
||||||
const pendingTxs = this.getPendingTransactions(address) |
|
||||||
const localNonceResult = this._getHighestContinuousFrom(pendingTxs, highestSuggested) || 0 |
|
||||||
|
|
||||||
nonceDetails.params = { |
|
||||||
highestLocallyConfirmed, |
|
||||||
highestSuggested, |
|
||||||
nextNetworkNonce, |
|
||||||
} |
|
||||||
nonceDetails.local = localNonceResult |
|
||||||
nonceDetails.network = networkNonceResult |
|
||||||
|
|
||||||
const nextNonce = Math.max(networkNonceResult.nonce, localNonceResult.nonce) |
|
||||||
assert(Number.isInteger(nextNonce), `nonce-tracker - nextNonce is not an integer - got: (${typeof nextNonce}) "${nextNonce}"`) |
|
||||||
|
|
||||||
// return nonce and release cb
|
|
||||||
return { nextNonce, nonceDetails, releaseLock } |
|
||||||
} catch (err) { |
|
||||||
// release lock if we encounter an error
|
|
||||||
releaseLock() |
|
||||||
throw err |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
async _globalMutexFree () { |
|
||||||
const globalMutex = this._lookupMutex('global') |
|
||||||
const releaseLock = await globalMutex.acquire() |
|
||||||
releaseLock() |
|
||||||
} |
|
||||||
|
|
||||||
async _takeMutex (lockId) { |
|
||||||
const mutex = this._lookupMutex(lockId) |
|
||||||
const releaseLock = await mutex.acquire() |
|
||||||
return releaseLock |
|
||||||
} |
|
||||||
|
|
||||||
_lookupMutex (lockId) { |
|
||||||
let mutex = this.lockMap[lockId] |
|
||||||
if (!mutex) { |
|
||||||
mutex = new Mutex() |
|
||||||
this.lockMap[lockId] = mutex |
|
||||||
} |
|
||||||
return mutex |
|
||||||
} |
|
||||||
|
|
||||||
async _getNetworkNextNonce (address) { |
|
||||||
// calculate next nonce
|
|
||||||
// we need to make sure our base count
|
|
||||||
// and pending count are from the same block
|
|
||||||
const blockNumber = await this.blockTracker.getLatestBlock() |
|
||||||
const baseCountBN = await this.ethQuery.getTransactionCount(address, blockNumber) |
|
||||||
const baseCount = baseCountBN.toNumber() |
|
||||||
assert(Number.isInteger(baseCount), `nonce-tracker - baseCount is not an integer - got: (${typeof baseCount}) "${baseCount}"`) |
|
||||||
const nonceDetails = { blockNumber, baseCount } |
|
||||||
return { name: 'network', nonce: baseCount, details: nonceDetails } |
|
||||||
} |
|
||||||
|
|
||||||
_getHighestLocallyConfirmed (address) { |
|
||||||
const confirmedTransactions = this.getConfirmedTransactions(address) |
|
||||||
const highest = this._getHighestNonce(confirmedTransactions) |
|
||||||
return Number.isInteger(highest) ? highest + 1 : 0 |
|
||||||
} |
|
||||||
|
|
||||||
_getHighestNonce (txList) { |
|
||||||
const nonces = txList.map((txMeta) => { |
|
||||||
const nonce = txMeta.txParams.nonce |
|
||||||
assert(typeof nonce, 'string', 'nonces should be hex strings') |
|
||||||
return parseInt(nonce, 16) |
|
||||||
}) |
|
||||||
const highestNonce = Math.max.apply(null, nonces) |
|
||||||
return highestNonce |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
@typedef {object} highestContinuousFrom |
|
||||||
@property {string} - name the name for how the nonce was calculated based on the data used |
|
||||||
@property {number} - nonce the next suggested nonce |
|
||||||
@property {object} - details the provided starting nonce that was used (for debugging) |
|
||||||
*/ |
|
||||||
/** |
|
||||||
@param txList {array} - list of txMeta's |
|
||||||
@param startPoint {number} - the highest known locally confirmed nonce |
|
||||||
@returns {highestContinuousFrom} |
|
||||||
*/ |
|
||||||
_getHighestContinuousFrom (txList, startPoint) { |
|
||||||
const nonces = txList.map((txMeta) => { |
|
||||||
const nonce = txMeta.txParams.nonce |
|
||||||
assert(typeof nonce, 'string', 'nonces should be hex strings') |
|
||||||
return parseInt(nonce, 16) |
|
||||||
}) |
|
||||||
|
|
||||||
let highest = startPoint |
|
||||||
while (nonces.includes(highest)) { |
|
||||||
highest++ |
|
||||||
} |
|
||||||
|
|
||||||
return { name: 'local', nonce: highest, details: { startPoint, highest } } |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
module.exports = NonceTracker |
|
@ -1,2 +1,2 @@ |
|||||||
module.exports = |
module.exports = |
||||||
[{'constant': true, 'inputs': [{'name': 'interfaceID', 'type': 'bytes4'}], 'name': 'supportsInterface', 'outputs': [{'name': '', 'type': 'bool'}], 'payable': false, 'type': 'function'}, {'constant': true, 'inputs': [{'name': 'node', 'type': 'bytes32'}, {'name': 'contentTypes', 'type': 'uint256'}], 'name': 'ABI', 'outputs': [{'name': 'contentType', 'type': 'uint256'}, {'name': 'data', 'type': 'bytes'}], 'payable': false, 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'node', 'type': 'bytes32'}, {'name': 'x', 'type': 'bytes32'}, {'name': 'y', 'type': 'bytes32'}], 'name': 'setPubkey', 'outputs': [], 'payable': false, 'type': 'function'}, {'constant': true, 'inputs': [{'name': 'node', 'type': 'bytes32'}], 'name': 'content', 'outputs': [{'name': 'ret', 'type': 'bytes32'}], 'payable': false, 'type': 'function'}, {'constant': true, 'inputs': [{'name': 'node', 'type': 'bytes32'}], 'name': 'addr', 'outputs': [{'name': 'ret', 'type': 'address'}], 'payable': false, 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'node', 'type': 'bytes32'}, {'name': 'contentType', 'type': 'uint256'}, {'name': 'data', 'type': 'bytes'}], 'name': 'setABI', 'outputs': [], 'payable': false, 'type': 'function'}, {'constant': true, 'inputs': [{'name': 'node', 'type': 'bytes32'}], 'name': 'name', 'outputs': [{'name': 'ret', 'type': 'string'}], 'payable': false, 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'node', 'type': 'bytes32'}, {'name': 'name', 'type': 'string'}], 'name': 'setName', 'outputs': [], 'payable': false, 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'node', 'type': 'bytes32'}, {'name': 'hash', 'type': 'bytes32'}], 'name': 'setContent', 'outputs': [], 'payable': false, 'type': 'function'}, {'constant': true, 'inputs': [{'name': 'node', 'type': 'bytes32'}], 'name': 'pubkey', 'outputs': [{'name': 'x', 'type': 'bytes32'}, {'name': 'y', 'type': 'bytes32'}], 'payable': false, 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'node', 'type': 'bytes32'}, {'name': 'addr', 'type': 'address'}], 'name': 'setAddr', 'outputs': [], 'payable': false, 'type': 'function'}, {'inputs': [{'name': 'ensAddr', 'type': 'address'}], 'payable': false, 'type': 'constructor'}, {'anonymous': false, 'inputs': [{'indexed': true, 'name': 'node', 'type': 'bytes32'}, {'indexed': false, 'name': 'a', 'type': 'address'}], 'name': 'AddrChanged', 'type': 'event'}, {'anonymous': false, 'inputs': [{'indexed': true, 'name': 'node', 'type': 'bytes32'}, {'indexed': false, 'name': 'hash', 'type': 'bytes32'}], 'name': 'ContentChanged', 'type': 'event'}, {'anonymous': false, 'inputs': [{'indexed': true, 'name': 'node', 'type': 'bytes32'}, {'indexed': false, 'name': 'name', 'type': 'string'}], 'name': 'NameChanged', 'type': 'event'}, {'anonymous': false, 'inputs': [{'indexed': true, 'name': 'node', 'type': 'bytes32'}, {'indexed': true, 'name': 'contentType', 'type': 'uint256'}], 'name': 'ABIChanged', 'type': 'event'}, {'anonymous': false, 'inputs': [{'indexed': true, 'name': 'node', 'type': 'bytes32'}, {'indexed': false, 'name': 'x', 'type': 'bytes32'}, {'indexed': false, 'name': 'y', 'type': 'bytes32'}], 'name': 'PubkeyChanged', 'type': 'event'}] |
[{'constant': false, 'inputs': [{'name': 'node', 'type': 'bytes32'}, {'name': 'hash', 'type': 'bytes32'}], 'name': 'setContent', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [{'name': 'node', 'type': 'bytes32'}], 'name': 'content', 'outputs': [{'name': '', 'type': 'bytes32'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [{'name': 'interfaceID', 'type': 'bytes4'}], 'name': 'supportsInterface', 'outputs': [{'name': '', 'type': 'bool'}], 'payable': false, 'stateMutability': 'pure', 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'node', 'type': 'bytes32'}, {'name': 'key', 'type': 'string'}, {'name': 'value', 'type': 'string'}], 'name': 'setText', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [{'name': 'node', 'type': 'bytes32'}, {'name': 'contentTypes', 'type': 'uint256'}], 'name': 'ABI', 'outputs': [{'name': 'contentType', 'type': 'uint256'}, {'name': 'data', 'type': 'bytes'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'node', 'type': 'bytes32'}, {'name': 'x', 'type': 'bytes32'}, {'name': 'y', 'type': 'bytes32'}], 'name': 'setPubkey', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'node', 'type': 'bytes32'}, {'name': 'hash', 'type': 'bytes'}], 'name': 'setContenthash', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [{'name': 'node', 'type': 'bytes32'}], 'name': 'addr', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [{'name': 'node', 'type': 'bytes32'}, {'name': 'key', 'type': 'string'}], 'name': 'text', 'outputs': [{'name': '', 'type': 'string'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'node', 'type': 'bytes32'}, {'name': 'contentType', 'type': 'uint256'}, {'name': 'data', 'type': 'bytes'}], 'name': 'setABI', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [{'name': 'node', 'type': 'bytes32'}], 'name': 'name', 'outputs': [{'name': '', 'type': 'string'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'node', 'type': 'bytes32'}, {'name': 'name', 'type': 'string'}], 'name': 'setName', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [{'name': 'node', 'type': 'bytes32'}], 'name': 'contenthash', 'outputs': [{'name': '', 'type': 'bytes'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [{'name': 'node', 'type': 'bytes32'}], 'name': 'pubkey', 'outputs': [{'name': 'x', 'type': 'bytes32'}, {'name': 'y', 'type': 'bytes32'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'node', 'type': 'bytes32'}, {'name': 'addr', 'type': 'address'}], 'name': 'setAddr', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'inputs': [{'name': 'ensAddr', 'type': 'address'}], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'constructor'}, {'anonymous': false, 'inputs': [{'indexed': true, 'name': 'node', 'type': 'bytes32'}, {'indexed': false, 'name': 'a', 'type': 'address'}], 'name': 'AddrChanged', 'type': 'event'}, {'anonymous': false, 'inputs': [{'indexed': true, 'name': 'node', 'type': 'bytes32'}, {'indexed': false, 'name': 'name', 'type': 'string'}], 'name': 'NameChanged', 'type': 'event'}, {'anonymous': false, 'inputs': [{'indexed': true, 'name': 'node', 'type': 'bytes32'}, {'indexed': true, 'name': 'contentType', 'type': 'uint256'}], 'name': 'ABIChanged', 'type': 'event'}, {'anonymous': false, 'inputs': [{'indexed': true, 'name': 'node', 'type': 'bytes32'}, {'indexed': false, 'name': 'x', 'type': 'bytes32'}, {'indexed': false, 'name': 'y', 'type': 'bytes32'}], 'name': 'PubkeyChanged', 'type': 'event'}, {'anonymous': false, 'inputs': [{'indexed': true, 'name': 'node', 'type': 'bytes32'}, {'indexed': false, 'name': 'indexedKey', 'type': 'string'}, {'indexed': false, 'name': 'key', 'type': 'string'}], 'name': 'TextChanged', 'type': 'event'}, {'anonymous': false, 'inputs': [{'indexed': true, 'name': 'node', 'type': 'bytes32'}, {'indexed': false, 'name': 'hash', 'type': 'bytes'}], 'name': 'ContenthashChanged', 'type': 'event'}] |
||||||
|
@ -0,0 +1,71 @@ |
|||||||
|
## Creating Metrics Events |
||||||
|
|
||||||
|
The `metricsEvent` method is made available to all components via context. This is done in `metamask-extension/ui/app/helpers/higher-order-components/metametrics/metametrics.provider.js`. As such, it can be called in all components by first adding it to the context proptypes: |
||||||
|
|
||||||
|
``` |
||||||
|
static contextTypes = { |
||||||
|
t: PropTypes.func, |
||||||
|
metricsEvent: PropTypes.func, |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
and then accessing it on `this.context`. |
||||||
|
|
||||||
|
Below is an example of a metrics event call: |
||||||
|
|
||||||
|
``` |
||||||
|
this.context.metricsEvent({ |
||||||
|
eventOpts: { |
||||||
|
category: 'Navigation', |
||||||
|
action: 'Main Menu', |
||||||
|
name: 'Switched Account', |
||||||
|
}, |
||||||
|
}) |
||||||
|
``` |
||||||
|
|
||||||
|
### Base Schema |
||||||
|
|
||||||
|
Every `metricsEvent` call is passed an object that must have an `eventOpts` property. This property is an object that itself must have three properties: |
||||||
|
- category: categorizes events according to the schema we have set up in our matomo.org instance |
||||||
|
- action: usually describes the page on which the event takes place, or sometimes a significant subsections of a page |
||||||
|
- name: a very specific descriptor of the event |
||||||
|
|
||||||
|
### Implicit properties |
||||||
|
|
||||||
|
All metrics events send the following data when called: |
||||||
|
- network |
||||||
|
- environmentType |
||||||
|
- activeCurrency |
||||||
|
- accountType |
||||||
|
- numberOfTokens |
||||||
|
- numberOfAccounts |
||||||
|
|
||||||
|
These are added to the metrics event via the metametrics provider. |
||||||
|
|
||||||
|
### Custom Variables |
||||||
|
|
||||||
|
Metrics events can include custom variables. These are included within the `customVariables` property that is a first-level property within first param passed to `metricsEvent`. |
||||||
|
|
||||||
|
For example: |
||||||
|
``` |
||||||
|
this.context.metricsEvent({ |
||||||
|
eventOpts: { |
||||||
|
category: 'Settings', |
||||||
|
action: 'Custom RPC', |
||||||
|
name: 'Error', |
||||||
|
}, |
||||||
|
customVariables: { |
||||||
|
networkId: newRpc, |
||||||
|
chainId, |
||||||
|
}, |
||||||
|
}) |
||||||
|
``` |
||||||
|
|
||||||
|
Custom variables can have custom property names and values can be strings or numbers. |
||||||
|
|
||||||
|
**To include a custom variable, there are a set of necessary steps you must take.** |
||||||
|
|
||||||
|
1. First you must declare a constant equal to the desired name of the custom variable property in `metamask-extension/ui/app/helpers/utils/metametrics.util.js` under `//Custom Variable Declarations` |
||||||
|
1. Then you must add that name to the `customVariableNameIdMap` declaration |
||||||
|
1. The id must be between 1 and 5 |
||||||
|
1. There can be no more than 5 custom variables assigned ids on a given url |
File diff suppressed because it is too large
Load Diff
@ -1,78 +0,0 @@ |
|||||||
const assert = require('assert') |
|
||||||
const nock = require('nock') |
|
||||||
const CurrencyController = require('../../../../app/scripts/controllers/currency') |
|
||||||
|
|
||||||
describe('currency-controller', function () { |
|
||||||
var currencyController |
|
||||||
|
|
||||||
beforeEach(function () { |
|
||||||
currencyController = new CurrencyController() |
|
||||||
}) |
|
||||||
|
|
||||||
describe('currency conversions', function () { |
|
||||||
describe('#setCurrentCurrency', function () { |
|
||||||
it('should return USD as default', function () { |
|
||||||
assert.equal(currencyController.getCurrentCurrency(), 'usd') |
|
||||||
}) |
|
||||||
|
|
||||||
it('should be able to set to other currency', function () { |
|
||||||
assert.equal(currencyController.getCurrentCurrency(), 'usd') |
|
||||||
currencyController.setCurrentCurrency('JPY') |
|
||||||
var result = currencyController.getCurrentCurrency() |
|
||||||
assert.equal(result, 'JPY') |
|
||||||
}) |
|
||||||
}) |
|
||||||
|
|
||||||
describe('#getConversionRate', function () { |
|
||||||
it('should return undefined if non-existent', function () { |
|
||||||
var result = currencyController.getConversionRate() |
|
||||||
assert.ok(!result) |
|
||||||
}) |
|
||||||
}) |
|
||||||
|
|
||||||
describe('#updateConversionRate', function () { |
|
||||||
it('should retrieve an update for ETH to USD and set it in memory', function (done) { |
|
||||||
this.timeout(15000) |
|
||||||
nock('https://api.infura.io') |
|
||||||
.get('/v1/ticker/ethusd') |
|
||||||
.reply(200, '{"base": "ETH", "quote": "USD", "bid": 288.45, "ask": 288.46, "volume": 112888.17569277, "exchange": "bitfinex", "total_volume": 272175.00106721005, "num_exchanges": 8, "timestamp": 1506444677}') |
|
||||||
|
|
||||||
assert.equal(currencyController.getConversionRate(), 0) |
|
||||||
currencyController.setCurrentCurrency('usd') |
|
||||||
currencyController.updateConversionRate() |
|
||||||
.then(function () { |
|
||||||
var result = currencyController.getConversionRate() |
|
||||||
assert.equal(typeof result, 'number') |
|
||||||
done() |
|
||||||
}).catch(function (err) { |
|
||||||
done(err) |
|
||||||
}) |
|
||||||
}) |
|
||||||
|
|
||||||
it('should work for JPY as well.', function () { |
|
||||||
this.timeout(15000) |
|
||||||
assert.equal(currencyController.getConversionRate(), 0) |
|
||||||
|
|
||||||
nock('https://api.infura.io') |
|
||||||
.get('/v1/ticker/ethjpy') |
|
||||||
.reply(200, '{"base": "ETH", "quote": "JPY", "bid": 32300.0, "ask": 32400.0, "volume": 247.4616071, "exchange": "kraken", "total_volume": 247.4616071, "num_exchanges": 1, "timestamp": 1506444676}') |
|
||||||
|
|
||||||
|
|
||||||
var promise = new Promise( |
|
||||||
function (resolve) { |
|
||||||
currencyController.setCurrentCurrency('jpy') |
|
||||||
currencyController.updateConversionRate().then(function () { |
|
||||||
resolve() |
|
||||||
}) |
|
||||||
}) |
|
||||||
|
|
||||||
promise.then(function () { |
|
||||||
var result = currencyController.getConversionRate() |
|
||||||
assert.equal(typeof result, 'number') |
|
||||||
}).catch(function (done, err) { |
|
||||||
done(err) |
|
||||||
}) |
|
||||||
}) |
|
||||||
}) |
|
||||||
}) |
|
||||||
}) |
|
@ -1,238 +0,0 @@ |
|||||||
const assert = require('assert') |
|
||||||
const NonceTracker = require('../../../../../app/scripts/controllers/transactions/nonce-tracker') |
|
||||||
const MockTxGen = require('../../../../lib/mock-tx-gen') |
|
||||||
const providerResultStub = {} |
|
||||||
|
|
||||||
describe('Nonce Tracker', function () { |
|
||||||
let nonceTracker, pendingTxs, confirmedTxs |
|
||||||
|
|
||||||
describe('#getNonceLock', function () { |
|
||||||
|
|
||||||
describe('with 3 confirmed and 1 pending', function () { |
|
||||||
beforeEach(function () { |
|
||||||
const txGen = new MockTxGen() |
|
||||||
confirmedTxs = txGen.generate({ status: 'confirmed' }, { count: 3 }) |
|
||||||
pendingTxs = txGen.generate({ status: 'submitted' }, { count: 1 }) |
|
||||||
nonceTracker = generateNonceTrackerWith(pendingTxs, confirmedTxs, '0x1') |
|
||||||
}) |
|
||||||
|
|
||||||
it('should return 4', async function () { |
|
||||||
this.timeout(15000) |
|
||||||
const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') |
|
||||||
assert.equal(nonceLock.nextNonce, '4', `nonce should be 4 got ${nonceLock.nextNonce}`) |
|
||||||
await nonceLock.releaseLock() |
|
||||||
}) |
|
||||||
|
|
||||||
it('should use localNonce if network returns a nonce lower then a confirmed tx in state', async function () { |
|
||||||
this.timeout(15000) |
|
||||||
const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') |
|
||||||
assert.equal(nonceLock.nextNonce, '4', 'nonce should be 4') |
|
||||||
await nonceLock.releaseLock() |
|
||||||
}) |
|
||||||
}) |
|
||||||
|
|
||||||
describe('sentry issue 476304902', function () { |
|
||||||
beforeEach(function () { |
|
||||||
const txGen = new MockTxGen() |
|
||||||
pendingTxs = txGen.generate({ status: 'submitted' }, { |
|
||||||
fromNonce: 3, |
|
||||||
count: 29, |
|
||||||
}) |
|
||||||
nonceTracker = generateNonceTrackerWith(pendingTxs, [], '0x3') |
|
||||||
}) |
|
||||||
|
|
||||||
it('should return 9', async function () { |
|
||||||
this.timeout(15000) |
|
||||||
const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') |
|
||||||
assert.equal(nonceLock.nextNonce, '32', `nonce should be 32 got ${nonceLock.nextNonce}`) |
|
||||||
await nonceLock.releaseLock() |
|
||||||
}) |
|
||||||
}) |
|
||||||
|
|
||||||
describe('issue 3670', function () { |
|
||||||
beforeEach(function () { |
|
||||||
const txGen = new MockTxGen() |
|
||||||
pendingTxs = txGen.generate({ status: 'submitted' }, { |
|
||||||
fromNonce: 6, |
|
||||||
count: 3, |
|
||||||
}) |
|
||||||
nonceTracker = generateNonceTrackerWith(pendingTxs, [], '0x6') |
|
||||||
}) |
|
||||||
|
|
||||||
it('should return 9', async function () { |
|
||||||
this.timeout(15000) |
|
||||||
const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') |
|
||||||
assert.equal(nonceLock.nextNonce, '9', `nonce should be 9 got ${nonceLock.nextNonce}`) |
|
||||||
await nonceLock.releaseLock() |
|
||||||
}) |
|
||||||
}) |
|
||||||
|
|
||||||
describe('with no previous txs', function () { |
|
||||||
beforeEach(function () { |
|
||||||
nonceTracker = generateNonceTrackerWith([], []) |
|
||||||
}) |
|
||||||
|
|
||||||
it('should return 0', async function () { |
|
||||||
this.timeout(15000) |
|
||||||
const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') |
|
||||||
assert.equal(nonceLock.nextNonce, '0', `nonce should be 0 returned ${nonceLock.nextNonce}`) |
|
||||||
await nonceLock.releaseLock() |
|
||||||
}) |
|
||||||
}) |
|
||||||
|
|
||||||
describe('with multiple previous txs with same nonce', function () { |
|
||||||
beforeEach(function () { |
|
||||||
const txGen = new MockTxGen() |
|
||||||
confirmedTxs = txGen.generate({ status: 'confirmed' }, { count: 1 }) |
|
||||||
pendingTxs = txGen.generate({ |
|
||||||
status: 'submitted', |
|
||||||
txParams: { nonce: '0x01' }, |
|
||||||
}, { count: 5 }) |
|
||||||
|
|
||||||
nonceTracker = generateNonceTrackerWith(pendingTxs, confirmedTxs, '0x0') |
|
||||||
}) |
|
||||||
|
|
||||||
it('should return nonce after those', async function () { |
|
||||||
this.timeout(15000) |
|
||||||
const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') |
|
||||||
assert.equal(nonceLock.nextNonce, '2', `nonce should be 2 got ${nonceLock.nextNonce}`) |
|
||||||
await nonceLock.releaseLock() |
|
||||||
}) |
|
||||||
}) |
|
||||||
|
|
||||||
describe('when local confirmed count is higher than network nonce', function () { |
|
||||||
beforeEach(function () { |
|
||||||
const txGen = new MockTxGen() |
|
||||||
confirmedTxs = txGen.generate({ status: 'confirmed' }, { count: 3 }) |
|
||||||
nonceTracker = generateNonceTrackerWith([], confirmedTxs, '0x1') |
|
||||||
}) |
|
||||||
|
|
||||||
it('should return nonce after those', async function () { |
|
||||||
this.timeout(15000) |
|
||||||
const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') |
|
||||||
assert.equal(nonceLock.nextNonce, '3', `nonce should be 3 got ${nonceLock.nextNonce}`) |
|
||||||
await nonceLock.releaseLock() |
|
||||||
}) |
|
||||||
}) |
|
||||||
|
|
||||||
describe('when local pending count is higher than other metrics', function () { |
|
||||||
beforeEach(function () { |
|
||||||
const txGen = new MockTxGen() |
|
||||||
pendingTxs = txGen.generate({ status: 'submitted' }, { count: 2 }) |
|
||||||
nonceTracker = generateNonceTrackerWith(pendingTxs, []) |
|
||||||
}) |
|
||||||
|
|
||||||
it('should return nonce after those', async function () { |
|
||||||
this.timeout(15000) |
|
||||||
const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') |
|
||||||
assert.equal(nonceLock.nextNonce, '2', `nonce should be 2 got ${nonceLock.nextNonce}`) |
|
||||||
await nonceLock.releaseLock() |
|
||||||
}) |
|
||||||
}) |
|
||||||
|
|
||||||
describe('when provider nonce is higher than other metrics', function () { |
|
||||||
beforeEach(function () { |
|
||||||
const txGen = new MockTxGen() |
|
||||||
pendingTxs = txGen.generate({ status: 'submitted' }, { count: 2 }) |
|
||||||
nonceTracker = generateNonceTrackerWith(pendingTxs, [], '0x05') |
|
||||||
}) |
|
||||||
|
|
||||||
it('should return nonce after those', async function () { |
|
||||||
this.timeout(15000) |
|
||||||
const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') |
|
||||||
assert.equal(nonceLock.nextNonce, '5', `nonce should be 5 got ${nonceLock.nextNonce}`) |
|
||||||
await nonceLock.releaseLock() |
|
||||||
}) |
|
||||||
}) |
|
||||||
|
|
||||||
describe('when there are some pending nonces below the remote one and some over.', function () { |
|
||||||
beforeEach(function () { |
|
||||||
const txGen = new MockTxGen() |
|
||||||
pendingTxs = txGen.generate({ status: 'submitted' }, { count: 5 }) |
|
||||||
nonceTracker = generateNonceTrackerWith(pendingTxs, [], '0x03') |
|
||||||
}) |
|
||||||
|
|
||||||
it('should return nonce after those', async function () { |
|
||||||
this.timeout(15000) |
|
||||||
const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') |
|
||||||
assert.equal(nonceLock.nextNonce, '5', `nonce should be 5 got ${nonceLock.nextNonce}`) |
|
||||||
await nonceLock.releaseLock() |
|
||||||
}) |
|
||||||
}) |
|
||||||
|
|
||||||
describe('when there are pending nonces non sequentially over the network nonce.', function () { |
|
||||||
beforeEach(function () { |
|
||||||
const txGen = new MockTxGen() |
|
||||||
txGen.generate({ status: 'submitted' }, { count: 5 }) |
|
||||||
// 5 over that number
|
|
||||||
pendingTxs = txGen.generate({ status: 'submitted' }, { count: 5 }) |
|
||||||
nonceTracker = generateNonceTrackerWith(pendingTxs, [], '0x00') |
|
||||||
}) |
|
||||||
|
|
||||||
it('should return nonce after network nonce', async function () { |
|
||||||
this.timeout(15000) |
|
||||||
const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') |
|
||||||
assert.equal(nonceLock.nextNonce, '0', `nonce should be 0 got ${nonceLock.nextNonce}`) |
|
||||||
await nonceLock.releaseLock() |
|
||||||
}) |
|
||||||
}) |
|
||||||
|
|
||||||
describe('When all three return different values', function () { |
|
||||||
beforeEach(function () { |
|
||||||
const txGen = new MockTxGen() |
|
||||||
confirmedTxs = txGen.generate({ status: 'confirmed' }, { count: 10 }) |
|
||||||
pendingTxs = txGen.generate({ |
|
||||||
status: 'submitted', |
|
||||||
nonce: 100, |
|
||||||
}, { count: 1 }) |
|
||||||
// 0x32 is 50 in hex:
|
|
||||||
nonceTracker = generateNonceTrackerWith(pendingTxs, confirmedTxs, '0x32') |
|
||||||
}) |
|
||||||
|
|
||||||
it('should return nonce after network nonce', async function () { |
|
||||||
this.timeout(15000) |
|
||||||
const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') |
|
||||||
assert.equal(nonceLock.nextNonce, '50', `nonce should be 50 got ${nonceLock.nextNonce}`) |
|
||||||
await nonceLock.releaseLock() |
|
||||||
}) |
|
||||||
}) |
|
||||||
|
|
||||||
describe('Faq issue 67', function () { |
|
||||||
beforeEach(function () { |
|
||||||
const txGen = new MockTxGen() |
|
||||||
confirmedTxs = txGen.generate({ status: 'confirmed' }, { count: 64 }) |
|
||||||
pendingTxs = txGen.generate({ |
|
||||||
status: 'submitted', |
|
||||||
}, { count: 10 }) |
|
||||||
// 0x40 is 64 in hex:
|
|
||||||
nonceTracker = generateNonceTrackerWith(pendingTxs, [], '0x40') |
|
||||||
}) |
|
||||||
|
|
||||||
it('should return nonce after network nonce', async function () { |
|
||||||
this.timeout(15000) |
|
||||||
const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') |
|
||||||
assert.equal(nonceLock.nextNonce, '74', `nonce should be 74 got ${nonceLock.nextNonce}`) |
|
||||||
await nonceLock.releaseLock() |
|
||||||
}) |
|
||||||
}) |
|
||||||
}) |
|
||||||
}) |
|
||||||
|
|
||||||
function generateNonceTrackerWith (pending, confirmed, providerStub = '0x0') { |
|
||||||
const getPendingTransactions = () => pending |
|
||||||
const getConfirmedTransactions = () => confirmed |
|
||||||
providerResultStub.result = providerStub |
|
||||||
const provider = { |
|
||||||
sendAsync: (_, cb) => { cb(undefined, providerResultStub) }, |
|
||||||
} |
|
||||||
const blockTracker = { |
|
||||||
getCurrentBlock: () => '0x11b568', |
|
||||||
getLatestBlock: async () => '0x11b568', |
|
||||||
} |
|
||||||
return new NonceTracker({ |
|
||||||
provider, |
|
||||||
blockTracker, |
|
||||||
getPendingTransactions, |
|
||||||
getConfirmedTransactions, |
|
||||||
}) |
|
||||||
} |
|
Loading…
Reference in new issue