From e36e5597aca634bbdc970fbe156f9f90a90f7421 Mon Sep 17 00:00:00 2001 From: Jared Flatow Date: Mon, 3 Aug 2020 17:59:50 -0700 Subject: [PATCH] Toni's changes to poster (#129) * Fix poster towork with latest mocked pair (#125) * Add multiple deltas for assets Add multiple deltas for assets Co-authored-by: Antonina Norair --- poster/src/index.ts | 51 ++++++++++++++++++++-------- poster/src/mainnet_uniswap_mocker.ts | 2 +- poster/src/post_with_retries.ts | 7 ++-- poster/src/poster.ts | 12 ++++--- poster/tests/poster_test.ts | 8 ++--- 5 files changed, 53 insertions(+), 27 deletions(-) diff --git a/poster/src/index.ts b/poster/src/index.ts index 57196817..26d708d7 100644 --- a/poster/src/index.ts +++ b/poster/src/index.ts @@ -3,6 +3,19 @@ import { main } from './poster'; import Web3 from 'web3'; import yargs from 'yargs'; +// default price delta triggering an update for the supported asset in % +const defaultDeltas = { + 'ETH': 1, + 'BTC': 1, + 'DAI': 0.5, + 'REP': 1.5, + 'ZRX': 1.5, + 'BAT': 1.5, + 'KNC': 1.5, + 'LINK': 1.5, + 'COMP': 1.5 +} + async function run() { const parsed = yargs .env('POSTER') @@ -14,11 +27,11 @@ async function run() { .option('timeout', {alias: 't', description: 'how many seconds to wait before retrying with more gas', type: 'number', default: 180}) .option('gas-limit', {alias: 'g', description: 'how much gas to send', type: 'number', default: 4000000}) .option('gas-price', {alias: 'gp', description: 'gas price', type: 'number'}) - .option('price-delta', {alias: 'd', description: 'the min required difference between new and previous asset price for price update on blockchain', type: 'number', default: 1}) .option('asset', {alias: 'a', description: 'A list of supported token names for posting prices', type: 'array', default: ['BTC', 'ETH', 'DAI', 'REP', 'ZRX', 'BAT', 'KNC', 'LINK', 'COMP']}) + .option('price-deltas', {alias: 'd', description: 'the min required difference between new and previous asset price for the update on blockchain', type: 'string', default: JSON.stringify(defaultDeltas)}) .option('testnet-world', {alias: 'tw', description: 'An option to use mocked uniswap token pairs with data from mainnet', type: 'boolean', default: false}) - .option('testnet-uniswap-pairs', {alias: 'tup', description: 'A list of uniswap testnet pairs for all assets', type: 'array'}) - .option('mainnet-uniswap-pairs', {alias: 'mup', description: 'A list of uniswap mainnet pairs for all assets', type: 'array'}) + .option('testnet-uniswap-pairs', {alias: 'tup', description: 'A list of uniswap testnet pairs for all assets', type: 'string'}) + .option('mainnet-uniswap-pairs', {alias: 'mup', description: 'A list of uniswap mainnet pairs for all assets', type: 'string'}) .help() .alias('help', 'h') @@ -33,21 +46,31 @@ async function run() { const timeout = parsed['timeout']; const gas_limit = parsed['gas-limit']; const gas_price = parsed['gas-price']; - const price_delta = parsed['price-delta']; + const price_deltas = JSON.parse(parsed['price-deltas']); const assets = parsed['asset']; - // parameters for testnets only + // check that price deltas are set up for all assets, otherwise set default delta value + assets.forEach(asset => { + if (price_deltas[asset] == undefined) { + price_deltas[asset] = defaultDeltas[asset]; + } + }); + + console.log(`Posting with price deltas = `, price_deltas); + + // parameters only for testnets that mock uniswap mainnet const mocked_world = parsed['testnet-world']; - const testnet_pairs = parsed['testnet-uniswap-pairs']; - const mainnet_pairs = parsed['mainnet-uniswap-pairs']; + const testnet_pairs = JSON.parse(parsed['testnet-uniswap-pairs'] || '{}'); + const mainnet_pairs = JSON.parse(parsed['mainnet-uniswap-pairs'] || '{}'); + console.log(`Configuring using testnet and mainnet uniswap pairs:`, testnet_pairs, mainnet_pairs); const pairs = {testnet: {}, mainnet: {}}; if (mocked_world) { - if (testnet_pairs.length != mainnet_pairs.length || testnet_pairs.length != assets.length) { - throw new TypeError("For each asset mainnet and testnet pairs should be provided, all lengths should match") - } - assets.forEach((asset, index) => { - pairs['testnet'][asset] = testnet_pairs[index]; - pairs['mainnet'][asset] = mainnet_pairs[index]; + assets.forEach(asset => { + if (!testnet_pairs[asset] || !mainnet_pairs[asset]) { + throw new TypeError(`For each asset mainnet and testnet pairs should be provided, ${asset} asset is not properly configured`) + } + pairs['testnet'][asset] = testnet_pairs[asset]; + pairs['mainnet'][asset] = mainnet_pairs[asset]; }); } @@ -64,7 +87,7 @@ async function run() { web3.eth.transactionConfirmationBlocks = 10; } - await main(sources, poster_key, view_address, view_function, gas_limit, gas_price, price_delta, assets, mocked_world, pairs, web3); + await main(sources, poster_key, view_address, view_function, gas_limit, gas_price, price_deltas, assets, mocked_world, pairs, web3); let success_log = { message: "Price Feed Poster run completed successfully", diff --git a/poster/src/mainnet_uniswap_mocker.ts b/poster/src/mainnet_uniswap_mocker.ts index 33036ad6..95d51169 100644 --- a/poster/src/mainnet_uniswap_mocker.ts +++ b/poster/src/mainnet_uniswap_mocker.ts @@ -55,7 +55,7 @@ async function mockUniswapTokenPair(symbol: string, senderKey: string, pairs, ga console.log(`Mocking uniswap token pair for ${symbol} with results--> ${reserve0} ${reserve1} ${blockTimestampLast} ${cumulativePrice0} ${cumulativePrice1}`); - const functionSig = "update(uint256,uint256,uint256,uint256,uint256)"; + const functionSig = "update(uint112,uint112,uint32,uint256,uint256)"; const trxData = buildTrxData(reserve0, reserve1, blockTimestampLast, cumulativePrice0, cumulativePrice1, functionSig); const trx = { data: trxData, diff --git a/poster/src/post_with_retries.ts b/poster/src/post_with_retries.ts index 85222490..d906a8ff 100644 --- a/poster/src/post_with_retries.ts +++ b/poster/src/post_with_retries.ts @@ -36,6 +36,10 @@ async function postWithRetries(transaction: TransactionConfig, signerKey: string console.log(`Posting from account: ${pubKey.address}`); + // TODO: Why manual nonce management? + let nonce = await web3.eth.getTransactionCount(pubKey.address) + transaction.nonce = nonce + try { return await signAndSend(transaction, signerKey, web3); } catch (e) { @@ -55,9 +59,6 @@ async function postWithRetries(transaction: TransactionConfig, signerKey: string // Sleep for some time before retrying await (new Promise(okay => setTimeout(okay, SLEEP_DURATION))); - let nonce = await web3.eth.getTransactionCount(pubKey.address) - transaction.nonce = nonce - return postWithRetries(transaction, signerKey, web3, retries - 1, attempt + 1); } else { throw new Error(`Failed to run Open Price Feed poster after ${attempt} attempt(s): error=\`${e.toString()}\``); diff --git a/poster/src/poster.ts b/poster/src/poster.ts index fd8c8794..1ac932e1 100644 --- a/poster/src/poster.ts +++ b/poster/src/poster.ts @@ -22,14 +22,14 @@ export async function main( functionSig: string, gas: number, gasPrice: number | undefined, - delta: number, + deltas, assets: string[], mocked_world: boolean, pairs, web3: Web3) { const payloads = await fetchPayloads(sources); - const feedItems = await filterPayloads(payloads, viewAddress, assets, delta, web3); + const feedItems = await filterPayloads(payloads, viewAddress, assets, deltas, web3); if (feedItems.length > 0) { // If gas price was not defined, fetch average one from Compound API @@ -39,7 +39,9 @@ export async function main( // mock uniswap mainnet pairs price if (mocked_world) { - await mockUniswapTokenPairs(assets, senderKey, pairs, gas, gasPrice, web3); + // Mock only pairs that will be updated + const updateAssets = feedItems.map(item => item.symbol) + await mockUniswapTokenPairs(updateAssets, senderKey, pairs, gas, gasPrice, web3); } const trxData = buildTrxData(feedItems, functionSig); @@ -61,7 +63,7 @@ export async function filterPayloads( payloads: OpenPriceFeedPayload[], viewAddress: string, supportedAssets: string[], - delta: number, + deltas, web3: Web3): Promise { const dataAddress = await getDataAddress(viewAddress, web3); @@ -96,7 +98,7 @@ export async function filterPayloads( }; })).then((feedItems) => { return feedItems.filter(({message, signature, symbol, price, prev}) => { - return !inDeltaRange(delta, price, prev); + return !inDeltaRange(deltas[symbol], price, prev); }); }); })); diff --git a/poster/tests/poster_test.ts b/poster/tests/poster_test.ts index 8823d4ea..1674b504 100644 --- a/poster/tests/poster_test.ts +++ b/poster/tests/poster_test.ts @@ -211,7 +211,7 @@ describe('filtering payloads', () => { mockMessages(transformPayloads(payloads)); mockPrevPrices({ 'BTC': 9149090000, 'ETH': 229435000, 'DAI': 1003372, 'REP': 16884999, 'ZRX': 357704, 'BAT': 260992, 'KNC': 1156300, 'LINK': 4704680 }); - const feedItems = await filterPayloads(payloads, '0x0', ['BTC', 'ETH', 'DAI', 'REP', 'ZRX', 'BAT', 'KNC', 'LINK', 'COMP'], 1, new Web3()); + const feedItems = await filterPayloads(payloads, '0x0', ['BTC', 'ETH', 'DAI', 'REP', 'ZRX', 'BAT', 'KNC', 'LINK', 'COMP'], {BTC: 1, ETH: 1, DAI: 1, REP: 1, ZRX: 1, BAT: 1, KNC: 1, LINK: 1, COMP: 1}, new Web3()); expect(feedItems).toEqual([ { dataType: "type", @@ -249,7 +249,7 @@ describe('filtering payloads', () => { ]; mockMessages(transformPayloads(payloads)); - const feedItems = await filterPayloads(payloads, '0x0', ['BTC', 'ETH', 'DAI', 'REP', 'BAT', 'KNC', 'LINK', 'COMP'], 1, new Web3()); + const feedItems = await filterPayloads(payloads, '0x0', ['BTC', 'ETH', 'DAI', 'REP', 'BAT', 'KNC', 'LINK', 'COMP'], {BTC: 1, ETH: 1, DAI: 1, REP: 1, ZRX: 1, BAT: 1, KNC: 1, LINK: 1, COMP: 1}, new Web3()); expect(feedItems).toEqual([ { message: '0x1', @@ -297,7 +297,7 @@ describe('filtering payloads', () => { ] mockMessages(transformPayloads(payloads)); - const feedItems = await filterPayloads(payloads, '0x0', [], 1, new Web3()); + const feedItems = await filterPayloads(payloads, '0x0', [], {}, new Web3()); expect(feedItems).toEqual([]); }) @@ -324,7 +324,7 @@ describe('filtering payloads', () => { ]; mockMessages(transformPayloads(payloads)); - const feedItems = await filterPayloads(payloads, '0x0', ['BTC', 'ETH', 'DAI', 'REP', 'ZRX', 'BAT', 'KNC', 'LINK', 'COMP'], 0, new Web3()); + const feedItems = await filterPayloads(payloads, '0x0', ['BTC', 'ETH', 'DAI', 'REP', 'ZRX', 'BAT', 'KNC', 'LINK', 'COMP'], {BTC: 0, ETH: 0, DAI: 0, REP: 0, ZRX: 0, BAT: 0, KNC: 0, LINK: 0, COMP: 0}, new Web3()); expect(feedItems).toEqual([ { message: '0x1',