From a73d01b4cace50d6329b132996b5f3ba7b7f1910 Mon Sep 17 00:00:00 2001 From: ponyjackal Date: Thu, 25 Jan 2024 08:48:50 -0800 Subject: [PATCH 1/9] feat: move pure transformers --- src/transformers/_common/blockGasUsage.ts | 14 + src/transformers/_common/contractABI.ts | 33 + .../_common/contractERC1155Detection.ts | 23 + .../_common/contractERC20Detection.ts | 23 + .../_common/contractERC721Detection.ts | 23 + .../_common/contractERC777Detection.ts | 23 + .../_common/contractGnosisSafeDetection.ts | 21 + .../_common/contractGovernanceDetection.ts | 21 + .../_common/contractSelfDestructed.ts | 37 + src/transformers/_common/contractTimestamp.ts | 19 + .../_common/transactionAssetTransfers.ts | 225 +++ .../_common/transactionContractsCreated.ts | 76 + .../_common/transactionDelegateCalls.ts | 17 + .../transactionDerivativesNeighbors.ts | 21 + src/transformers/_common/transactionErrors.ts | 24 + .../_common/transactionNetAssetTransfers.ts | 96 ++ .../_common/transactionParties.ts | 79 + .../_common/transactionProxyUpgrades.ts | 42 + .../_common/transactionSigHash.ts | 16 + .../_common/transactionTimestamp.ts | 13 + src/transformers/ethereum/blockEthPrice.ts | 164 +++ src/transformers/ethereum/blockFork.ts | 27 + .../ethereum/contractPropHouseDetection.ts | 82 ++ .../ethereum/contractUniswapDetection.ts | 112 ++ .../transactionAssetTransfersOldNFTs.ts | 113 ++ src/transformers/ethereum/transactionFees.ts | 40 + src/transformers/ethereum/transactionForks.ts | 14 + src/transformers/helpers/constants.ts | 396 +++++ .../helpers/etherscan_prices.json | 1299 +++++++++++++++++ src/transformers/helpers/reqCache.ts | 57 + src/transformers/helpers/sigMapper.ts | 150 ++ src/transformers/helpers/utils.ts | 208 +++ src/transformers/types.ts | 380 +++++ 33 files changed, 3888 insertions(+) create mode 100644 src/transformers/_common/blockGasUsage.ts create mode 100644 src/transformers/_common/contractABI.ts create mode 100644 src/transformers/_common/contractERC1155Detection.ts create mode 100644 src/transformers/_common/contractERC20Detection.ts create mode 100644 src/transformers/_common/contractERC721Detection.ts create mode 100644 src/transformers/_common/contractERC777Detection.ts create mode 100644 src/transformers/_common/contractGnosisSafeDetection.ts create mode 100644 src/transformers/_common/contractGovernanceDetection.ts create mode 100644 src/transformers/_common/contractSelfDestructed.ts create mode 100644 src/transformers/_common/contractTimestamp.ts create mode 100644 src/transformers/_common/transactionAssetTransfers.ts create mode 100644 src/transformers/_common/transactionContractsCreated.ts create mode 100644 src/transformers/_common/transactionDelegateCalls.ts create mode 100644 src/transformers/_common/transactionDerivativesNeighbors.ts create mode 100644 src/transformers/_common/transactionErrors.ts create mode 100644 src/transformers/_common/transactionNetAssetTransfers.ts create mode 100644 src/transformers/_common/transactionParties.ts create mode 100644 src/transformers/_common/transactionProxyUpgrades.ts create mode 100644 src/transformers/_common/transactionSigHash.ts create mode 100644 src/transformers/_common/transactionTimestamp.ts create mode 100644 src/transformers/ethereum/blockEthPrice.ts create mode 100644 src/transformers/ethereum/blockFork.ts create mode 100644 src/transformers/ethereum/contractPropHouseDetection.ts create mode 100644 src/transformers/ethereum/contractUniswapDetection.ts create mode 100644 src/transformers/ethereum/transactionAssetTransfersOldNFTs.ts create mode 100644 src/transformers/ethereum/transactionFees.ts create mode 100644 src/transformers/ethereum/transactionForks.ts create mode 100644 src/transformers/helpers/constants.ts create mode 100644 src/transformers/helpers/etherscan_prices.json create mode 100644 src/transformers/helpers/reqCache.ts create mode 100644 src/transformers/helpers/sigMapper.ts create mode 100644 src/transformers/helpers/utils.ts create mode 100644 src/transformers/types.ts diff --git a/src/transformers/_common/blockGasUsage.ts b/src/transformers/_common/blockGasUsage.ts new file mode 100644 index 0000000..e22a9f6 --- /dev/null +++ b/src/transformers/_common/blockGasUsage.ts @@ -0,0 +1,14 @@ +import { toBigNumber } from '../helpers/utils'; +import type { RawBlock } from '../types'; + +export function transform(block: RawBlock) { + const gasUsedPercentage = toBigNumber(block.gasUsed) + .multipliedBy(100) + .dividedBy(toBigNumber(block.gasLimit)) + .toString(); + + return { + number: block.number, + gasUsedPercentage, + }; +} diff --git a/src/transformers/_common/contractABI.ts b/src/transformers/_common/contractABI.ts new file mode 100644 index 0000000..cddb9ee --- /dev/null +++ b/src/transformers/_common/contractABI.ts @@ -0,0 +1,33 @@ +import { whatsabi } from '@shazow/whatsabi'; +import type { Contract, RawBlock, TransactionContract } from '../types'; + +export function transform(block: RawBlock): TransactionContract[] { + const results: { hash: string; contracts: Contract[] }[] = []; + + for (const tx of block.transactions) { + if (!tx.contracts) { + continue; + } + + const contracts = tx.contracts + .map((txContract) => { + try { + // Get just the callable selectors + txContract.metadata.whatsAbiSelectors = whatsabi.selectorsFromBytecode(txContract.bytecode); + // Get an ABI-like list of interfaces + txContract.metadata.whatsAbiAbi = whatsabi.abiFromBytecode(txContract.bytecode); + + return txContract; + } catch (e) { + return null; + } + }) + .filter((v) => v); + + if (contracts.length) { + results.push({ hash: tx.hash, contracts }); + } + } + + return results; +} diff --git a/src/transformers/_common/contractERC1155Detection.ts b/src/transformers/_common/contractERC1155Detection.ts new file mode 100644 index 0000000..a416c8f --- /dev/null +++ b/src/transformers/_common/contractERC1155Detection.ts @@ -0,0 +1,23 @@ +import type { Contract, RawBlock, TransactionContract } from '../types'; +import { bytecodeIsERC1155 } from '../helpers/utils'; + +export function transform(block: RawBlock): TransactionContract[] { + const results: { hash: string; contracts: Contract[] }[] = []; + + for (const tx of block.transactions) { + if (!tx.contracts) { + continue; + } + + const contracts = tx.contracts.map((txContract) => { + if (bytecodeIsERC1155(txContract.bytecode)) { + txContract.metadata.tokenMetadata.tokenStandard = 'erc1155'; + } + return txContract; + }); + + results.push({ hash: tx.hash, contracts }); + } + + return results; +} diff --git a/src/transformers/_common/contractERC20Detection.ts b/src/transformers/_common/contractERC20Detection.ts new file mode 100644 index 0000000..86a08d8 --- /dev/null +++ b/src/transformers/_common/contractERC20Detection.ts @@ -0,0 +1,23 @@ +import type { Contract, RawBlock, TransactionContract } from '../types'; +import { bytecodeIsERC20 } from '../helpers/utils'; + +export function transform(block: RawBlock): TransactionContract[] { + const results: { hash: string; contracts: Contract[] }[] = []; + + for (const tx of block.transactions) { + if (!tx.contracts) { + continue; + } + + const contracts = tx.contracts.map((txContract) => { + if (bytecodeIsERC20(txContract.bytecode)) { + txContract.metadata.tokenMetadata.tokenStandard = 'erc20'; + } + return txContract; + }); + + results.push({ hash: tx.hash, contracts }); + } + + return results; +} diff --git a/src/transformers/_common/contractERC721Detection.ts b/src/transformers/_common/contractERC721Detection.ts new file mode 100644 index 0000000..6011301 --- /dev/null +++ b/src/transformers/_common/contractERC721Detection.ts @@ -0,0 +1,23 @@ +import type { Contract, RawBlock, TransactionContract } from '../types'; +import { bytecodeIsERC721 } from '../helpers/utils'; + +export function transform(block: RawBlock): TransactionContract[] { + const results: { hash: string; contracts: Contract[] }[] = []; + + for (const tx of block.transactions) { + if (!tx.contracts) { + continue; + } + + const contracts = tx.contracts.map((txContract) => { + if (bytecodeIsERC721(txContract.bytecode)) { + txContract.metadata.tokenMetadata.tokenStandard = 'erc721'; + } + return txContract; + }); + + results.push({ hash: tx.hash, contracts }); + } + + return results; +} diff --git a/src/transformers/_common/contractERC777Detection.ts b/src/transformers/_common/contractERC777Detection.ts new file mode 100644 index 0000000..dc4ba9b --- /dev/null +++ b/src/transformers/_common/contractERC777Detection.ts @@ -0,0 +1,23 @@ +import type { Contract, RawBlock, TransactionContract } from '../types'; +import { bytecodeIsERC777 } from '../helpers/utils'; + +export function transform(block: RawBlock): TransactionContract[] { + const results: { hash: string; contracts: Contract[] }[] = []; + + for (const tx of block.transactions) { + if (!tx.contracts) { + continue; + } + + const contracts = tx.contracts.map((txContract) => { + if (bytecodeIsERC777(txContract.bytecode)) { + txContract.metadata.tokenMetadata.tokenStandard = 'erc777'; + } + return txContract; + }); + + results.push({ hash: tx.hash, contracts }); + } + + return results; +} diff --git a/src/transformers/_common/contractGnosisSafeDetection.ts b/src/transformers/_common/contractGnosisSafeDetection.ts new file mode 100644 index 0000000..baebb22 --- /dev/null +++ b/src/transformers/_common/contractGnosisSafeDetection.ts @@ -0,0 +1,21 @@ +import type { RawBlock, Contract, TransactionContract } from '../types'; +import { bytecodeIsGnosisSafe } from '../helpers/utils'; + +export function transform(block: RawBlock): TransactionContract[] { + const result: TransactionContract[] = block.transactions + .filter((tx) => tx.contracts?.length > 0) + .map((tx) => { + const contracts: Contract[] = tx.contracts.map((txContract) => { + const contract: Contract = { ...txContract }; + if (bytecodeIsGnosisSafe(txContract.bytecode)) { + contract.metadata.isGnosisSafe = true; + } + + return contract; + }); + + return { hash: tx.hash, contracts }; + }); + + return result; +} diff --git a/src/transformers/_common/contractGovernanceDetection.ts b/src/transformers/_common/contractGovernanceDetection.ts new file mode 100644 index 0000000..38d1889 --- /dev/null +++ b/src/transformers/_common/contractGovernanceDetection.ts @@ -0,0 +1,21 @@ +import type { RawBlock, Contract, TransactionContract } from '../types'; +import { bytecodeIsIGovernor } from '../helpers/utils'; + +export function transform(block: RawBlock): TransactionContract[] { + const result: TransactionContract[] = block.transactions + .filter((tx) => tx.contracts?.length > 0) + .map((tx) => { + const contracts: Contract[] = tx.contracts.map((txContract) => { + const contract: Contract = { ...txContract }; + if (bytecodeIsIGovernor(txContract.bytecode)) { + contract.metadata.isGenericGovernance = true; + } + + return contract; + }); + + return { hash: tx.hash, contracts }; + }); + + return result; +} diff --git a/src/transformers/_common/contractSelfDestructed.ts b/src/transformers/_common/contractSelfDestructed.ts new file mode 100644 index 0000000..fd349b8 --- /dev/null +++ b/src/transformers/_common/contractSelfDestructed.ts @@ -0,0 +1,37 @@ +import { toBigNumber } from '../helpers/utils'; +import type { RawBlock } from '../types'; + +type ContractSelfDestructed = { address: string; refundAddress: string; balance: string }; + +export function transform(block: RawBlock) { + const results: { + contractSelfDestructed: ContractSelfDestructed[]; + hash: string; + }[] = []; + + for (const tx of block.transactions) { + const result = { + contractsCreated: [], + contractSelfDestructed: [], + hash: tx.hash, + }; + + for (let i = 0; i < tx.traces.length; i += 1) { + const trace = tx.traces[i]; + + if (trace.type === 'suicide' && trace.action) { + result.contractSelfDestructed.push({ + address: trace.action.address, + balance: toBigNumber(trace.action.balance).toString(), + refundAddress: trace.action.refundAddress, + }); + } + } + + if (result.contractSelfDestructed.length > 0) { + results.push(result); + } + } + + return results; +} diff --git a/src/transformers/_common/contractTimestamp.ts b/src/transformers/_common/contractTimestamp.ts new file mode 100644 index 0000000..0320ad2 --- /dev/null +++ b/src/transformers/_common/contractTimestamp.ts @@ -0,0 +1,19 @@ +import type { RawBlock, TransactionContract } from '../types'; + +export function transform(block: RawBlock): TransactionContract[] { + const isoTimestamp = new Date(block.timestamp * 1000).toISOString(); + const result: TransactionContract[] = []; + + for (const tx of block.transactions) { + const contracts = tx.contracts.map((txContract) => { + txContract.timestamp = block.timestamp; + txContract.isoTimestamp = isoTimestamp; + + return txContract; + }); + + result.push({ hash: tx.hash, contracts }); + } + + return result; +} diff --git a/src/transformers/_common/transactionAssetTransfers.ts b/src/transformers/_common/transactionAssetTransfers.ts new file mode 100644 index 0000000..3cd1a11 --- /dev/null +++ b/src/transformers/_common/transactionAssetTransfers.ts @@ -0,0 +1,225 @@ +import BigNumber from 'bignumber.js'; +import Web3 from 'web3'; + +import { decodeEVMAddress, toBigNumber } from '../helpers/utils'; +import type { AssetTransfer, RawBlock, RawTransaction } from '../types'; +import { KNOWN_ADDRESSES } from '../helpers/constants'; + +// 1. pull out token transfers from logs +// 2. pull out ETH transfers from traces (this covers tx.value transfers) +// 3. order it all by looking at when contracts where called via traces + +const TRANSFER_SIGNATURES = { + // event Transfer(address indexed from, address indexed to, uint256 value) + ERC20: '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', + + // event Transfer(address indexed from, address indexed to, uint256 indexed tokenId) + ERC721: '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', + + // event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value) + ERC1155_SINGLE: '0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62', + + // event TransferBatch(address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values) + ERC1155_BATCH: '0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb', + + // event Deposit(address indexed dst, uint wad) + WETH_DEPOSIT_ERC20: '0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c', + + // event Withdrawal(address indexed src, uint wad) + WETH_WITHDRAW_ERC20: '0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65', +}; + +// @NOTE: we do *not* need access to an RPC here +// we just need an instance of Web3 in order to decode some log params +const web3 = new Web3(); + +function getTokenTransfers(tx: RawTransaction) { + const txAssetTransfers: AssetTransfer[] = []; + + for (const log of tx.receipt.logs) { + const [signature] = log.topics; + + switch (signature) { + // @NOTE: all of these cases are the same function signature + case TRANSFER_SIGNATURES.ERC20: + case TRANSFER_SIGNATURES.ERC721: { + // if there's a 4th topic (indexed parameter), then it's an ERC721 + if (log.topics.length === 4) { + txAssetTransfers.push({ + asset: log.address, + from: decodeEVMAddress(log.topics[1]), + to: decodeEVMAddress(log.topics[2]), + tokenId: toBigNumber(log.topics[3]).toString(), + type: 'erc721', + }); + } else { + txAssetTransfers.push({ + asset: log.address, + from: decodeEVMAddress(log.topics[1]), + to: decodeEVMAddress(log.topics[2]), + value: toBigNumber(log.data).toString(), + type: 'erc20', + }); + } + continue; + } + + case TRANSFER_SIGNATURES.ERC1155_SINGLE: { + const { tokenId, value } = web3.eth.abi.decodeParameters( + [ + { name: 'tokenId', type: 'uint256' }, + { name: 'value', type: 'uint256' }, + ], + log.data + ) as { tokenId: BigNumber; value: BigNumber }; + + txAssetTransfers.push({ + asset: log.address, + from: decodeEVMAddress(log.topics[2]), + to: decodeEVMAddress(log.topics[3]), + tokenId: tokenId.toString(), + value: value.toString(), + type: 'erc1155', + }); + continue; + } + + case TRANSFER_SIGNATURES.ERC1155_BATCH: { + const { tokenIds, values } = web3.eth.abi.decodeParameters( + [ + { name: 'tokenIds', type: 'uint256[]' }, + { name: 'values', type: 'uint256[]' }, + ], + log.data + ) as { tokenIds: BigNumber[]; values: BigNumber[] }; + + for (let tokenIdx = 0; tokenIdx < tokenIds.length; tokenIdx += 1) { + txAssetTransfers.push({ + asset: log.address, + from: decodeEVMAddress(log.topics[2]), + to: decodeEVMAddress(log.topics[3]), + tokenId: tokenIds[tokenIdx].toString(), + value: values[tokenIdx].toString(), + type: 'erc1155', + }); + } + continue; + } + + case TRANSFER_SIGNATURES.WETH_DEPOSIT_ERC20: { + if (log.address !== KNOWN_ADDRESSES.WETH) { + continue; + } + + txAssetTransfers.push({ + asset: log.address, + from: KNOWN_ADDRESSES.NULL, + to: decodeEVMAddress(log.topics[1]), + value: toBigNumber(log.data).toString(), + type: 'erc20', + }); + continue; + } + + case TRANSFER_SIGNATURES.WETH_WITHDRAW_ERC20: { + if (log.address !== KNOWN_ADDRESSES.WETH) { + continue; + } + + txAssetTransfers.push({ + asset: log.address, + from: decodeEVMAddress(log.topics[1]), + to: KNOWN_ADDRESSES.NULL, + value: toBigNumber(log.data).toString(), + type: 'erc20', + }); + continue; + } + + default: + break; + } + } + + return txAssetTransfers; +} + +export function transform(block: RawBlock) { + const results: { hash: string; assetTransfers: AssetTransfer[] }[] = []; + + for (const tx of block.transactions) { + // don't count transfers for failed txs + if (!tx.receipt.status) { + continue; + } + + // first get all of the token transfers from transaction logs + const tokenTransfers = getTokenTransfers(tx); + + // then group by contract + const tokenTransfersByContract: Record = {}; + for (const transfer of tokenTransfers) { + if (!tokenTransfersByContract[transfer.asset]) { + tokenTransfersByContract[transfer.asset] = []; + } + tokenTransfersByContract[transfer.asset].push(transfer); + } + + // now prepare a final set of *all* asset transfers (including ETH) + const assetTransfers: AssetTransfer[] = []; + + // iterate through the traces + for (const trace of tx.traces) { + // check for ETH transfers + if (trace.action.callType !== 'delegatecall') { + // track contract suicides + if (trace.type === 'suicide' && trace.action.balance && trace.action.balance !== '0x0') { + assetTransfers.push({ + from: trace.action.address, + to: trace.action.refundAddress, + type: 'eth', + value: toBigNumber(trace.action.balance).toString(), + }); + } + // otherwise track ETH transfers + else if (trace.action.value && trace.action.value !== '0x0') { + assetTransfers.push({ + from: trace.action.from, + to: trace.type === 'create' ? trace.result.address : trace.action.to, + type: 'eth', + value: toBigNumber(trace.action.value).toString(), + }); + } + } + + // check if this is a call to one of our asset transfer contracts + if ( + trace.action.callType?.endsWith('call') && + trace.action.to && + tokenTransfersByContract[trace.action.to]?.length > 0 + ) { + assetTransfers.push(...tokenTransfersByContract[trace.action.to]); + delete tokenTransfersByContract[trace.action.to]; + } + } + + if (tokenTransfersByContract[tx.to]?.length > 0) { + assetTransfers.push(...tokenTransfersByContract[tx.to]); + delete tokenTransfersByContract[tx.to]; + } + + for (const leftOverTxfers of Object.values(tokenTransfersByContract)) { + assetTransfers.push(...leftOverTxfers); + } + + if (assetTransfers.length > 0) { + results.push({ + hash: tx.hash, + // @NOTE: current ETL codebase splits out `ethFlow` from `assetTransfers` + assetTransfers, + }); + } + } + + return results; +} diff --git a/src/transformers/_common/transactionContractsCreated.ts b/src/transformers/_common/transactionContractsCreated.ts new file mode 100644 index 0000000..8d13ceb --- /dev/null +++ b/src/transformers/_common/transactionContractsCreated.ts @@ -0,0 +1,76 @@ +import { keccak256 } from 'web3-utils'; +import type { RawBlock, Contract } from '../types'; + +export function transform(block: RawBlock) { + const results: { + contracts: Contract[]; + hash: string; + }[] = []; + + for (const tx of block.transactions) { + const result = { + contracts: [], + hash: tx.hash, + }; + + for (let i = 0; i < tx.traces.length; i += 1) { + const trace = tx.traces[i]; + + if ((trace.type === 'create' || trace.type == 'create2') && trace.result) { + // Basic Create Contract Details + const isoTimestamp = new Date(block.timestamp * 1000).toISOString(); + + const contract: Contract = { + deployer: tx.from, + directDeployer: trace.action.from, + address: trace.result.address, + bytecode: trace.result.code, + fingerprint: trace.result.code !== '0x0' ? keccak256(trace.result.code) : '', // TODO - need a way to avoid validation errors + gas: trace.action.gas, // TOOD - do we convert with bignumber here? + gasUsed: trace.result.gasUsed, // TODO - do we convert with bignumber here? + blockNumber: block.number, + transactionHash: tx.hash, + type: trace.type, + metadata: { + isUniswapV3: false, + isUniswapV2: false, + isUniswapV1: false, + uniswapPairs: [], + isPropHouseToken: false, + isPropHouseMetadata: false, + isPropHouseAuction: false, + isPropHouseTreasury: false, + isPropHouseGovernor: false, + isGenericGovernance: false, + isGnosisSafe: false, + whatsAbiSelectors: [], + whatsAbiAbi: [], + isProxy: false, + tokenMetadata: { + tokenStandard: '', + name: '', + symbol: '', + decimals: 0, + }, + }, + sigHash: '', + internalSigHashes: [], + transactionIndex: tx.transactionIndex as number, + traceIndex: i, + + ethTransfer: false, + timestamp: block.timestamp, + isoTimestamp, + }; + + result.contracts.push(contract); + } + } + + if (result.contracts.length > 0) { + results.push(result); + } + } + + return results; +} diff --git a/src/transformers/_common/transactionDelegateCalls.ts b/src/transformers/_common/transactionDelegateCalls.ts new file mode 100644 index 0000000..1dd4e35 --- /dev/null +++ b/src/transformers/_common/transactionDelegateCalls.ts @@ -0,0 +1,17 @@ +import type { RawBlock, RawTrace } from '../types'; + +export function transform(block: RawBlock) { + const results: { hash: string; delegateCalls: RawTrace[] }[] = []; + + for (const tx of block.transactions) { + const delegateCalls = tx.traces.filter((t) => t.action.callType === 'delegatecall'); + if (delegateCalls.length > 0) { + results.push({ + hash: tx.hash, + delegateCalls, + }); + } + } + + return results; +} diff --git a/src/transformers/_common/transactionDerivativesNeighbors.ts b/src/transformers/_common/transactionDerivativesNeighbors.ts new file mode 100644 index 0000000..f53cf6a --- /dev/null +++ b/src/transformers/_common/transactionDerivativesNeighbors.ts @@ -0,0 +1,21 @@ +import type { RawBlock, Neighbor } from '../types'; + +export function transform(block: RawBlock): Neighbor[] { + const result: Neighbor[] = []; + for (let i = 0; i < block.transactions.length; i++) { + const tx = block.transactions[i]; + if (tx.assetTransfers) { + const fromAddresses: Set = new Set( + (tx.assetTransfers as { from: string }[]).map((assetTransfer) => assetTransfer.from) + ); + const toAddresses: Set = new Set( + (tx.assetTransfers as { to: string }[]).map((assetTransfer) => assetTransfer.to) + ); + if (fromAddresses.size === 1 && fromAddresses.has(tx.from) && toAddresses.size === 1) { + result.push({ hash: tx.hash, neighbor: { address: tx.from, neighbor: [...toAddresses][0] } }); + } + } + } + + return result; +} diff --git a/src/transformers/_common/transactionErrors.ts b/src/transformers/_common/transactionErrors.ts new file mode 100644 index 0000000..93b9791 --- /dev/null +++ b/src/transformers/_common/transactionErrors.ts @@ -0,0 +1,24 @@ +import type { RawBlock } from '../types'; + +export function transform(block: RawBlock) { + const allTxErrors: { hash: string; errors: string[] }[] = []; + + for (const tx of block.transactions) { + const errors: string[] = []; + + for (const trace of tx.traces) { + if (trace.error) { + errors.push(trace.error); + } + } + + if (errors.length > 0) { + allTxErrors.push({ + hash: tx.hash, + errors, + }); + } + } + + return allTxErrors; +} diff --git a/src/transformers/_common/transactionNetAssetTransfers.ts b/src/transformers/_common/transactionNetAssetTransfers.ts new file mode 100644 index 0000000..21fc77e --- /dev/null +++ b/src/transformers/_common/transactionNetAssetTransfers.ts @@ -0,0 +1,96 @@ +import BigNumber from 'bignumber.js'; +import type { RawBlock, NetAssetTransfer, NetAssetTransfers } from '../types'; +import { toBigNumber } from '../helpers/utils'; + +export function transform(block: RawBlock) { + const results: { hash: string; netAssetTransfers: NetAssetTransfers }[] = []; + + for (const tx of block.transactions) { + const assetTransfers = tx.assetTransfers; + if (!assetTransfers?.length) { + continue; + } + + const assetsById: Record = {}; + const netAssetsByAddress: Record> = {}; + + for (const txfer of assetTransfers) { + if (txfer.from === txfer.to || !txfer.from || !txfer.to) { + continue; + } + + let asset: NetAssetTransfer; + if (txfer.type === 'erc721' || txfer.type === 'erc1155') { + asset = { + asset: txfer.asset, + id: `${txfer.asset}-${txfer.tokenId}`, + tokenId: txfer.tokenId, + type: txfer.type, + value: txfer.value || '1', + }; + } else if (txfer.type === 'erc20') { + asset = { + asset: txfer.asset, + id: txfer.asset, + tokenId: txfer.tokenId, + type: txfer.type, + value: txfer.value, + }; + } else if (txfer.type === 'eth') { + asset = { + asset: 'eth', + id: 'eth', + type: txfer.type, + value: txfer.value, + }; + } + + if (!asset.id || !asset.value || asset.value === '0') { + continue; + } + + if (!netAssetsByAddress[txfer.from]) { + netAssetsByAddress[txfer.from] = {}; + } + if (!netAssetsByAddress[txfer.to]) { + netAssetsByAddress[txfer.to] = {}; + } + if (!netAssetsByAddress[txfer.from][asset.id]) { + netAssetsByAddress[txfer.from][asset.id] = toBigNumber(0); + } + if (!netAssetsByAddress[txfer.to][asset.id]) { + netAssetsByAddress[txfer.to][asset.id] = toBigNumber(0); + } + + assetsById[asset.id] = asset; + netAssetsByAddress[txfer.from][asset.id] = netAssetsByAddress[txfer.from][asset.id].minus(asset.value); + netAssetsByAddress[txfer.to][asset.id] = netAssetsByAddress[txfer.to][asset.id].plus(asset.value); + } + + const netAssetTransfers: NetAssetTransfers = {}; + for (const [address, assets] of Object.entries(netAssetsByAddress)) { + for (const [id, value] of Object.entries(assets)) { + if (value.eq(0)) { + continue; + } + if (!netAssetTransfers[address]) { + netAssetTransfers[address] = { received: [], sent: [] }; + } + if (value.lt(0)) { + netAssetTransfers[address].sent.push({ ...assetsById[id], value: value.multipliedBy(-1).toString() }); + } else { + netAssetTransfers[address].received.push({ ...assetsById[id], value: value.toString() }); + } + } + } + + if (Object.keys(netAssetTransfers).length > 0) { + results.push({ + hash: tx.hash, + netAssetTransfers, + }); + } + } + + return results; +} diff --git a/src/transformers/_common/transactionParties.ts b/src/transformers/_common/transactionParties.ts new file mode 100644 index 0000000..3be2d53 --- /dev/null +++ b/src/transformers/_common/transactionParties.ts @@ -0,0 +1,79 @@ +/* eslint-disable @typescript-eslint/no-unsafe-call */ +import type { RawBlock } from '../types'; + +type TransactionWithParties = { + hash: string; + parties: string[]; +}; +export function transform(block: RawBlock): TransactionWithParties[] { + const result: TransactionWithParties[] = block.transactions.map((tx) => { + // from/to addresses + let parties: string[] = []; + if (tx.from) { + parties = [...parties, tx.from.toLowerCase()]; + } + if (tx.to) { + parties = [...parties, tx.to.toLowerCase()]; + } + // address from input data + const inputAddresses = tx.decode?.fragment.inputs + .map((param, index) => (param.type === 'address' ? tx.decode?.args[index].toLowerCase() : '')) + .filter((address) => address !== ''); + // addresses from traces + const traceParties = tx.traces.map((trace) => { + let result: string[] = []; + if (trace.action?.from) { + result = [...result, trace.action.from.toLowerCase()]; + } + if (trace.action?.to) { + result = [...result, trace.action.to.toLowerCase()]; + } + if (trace.type === 'suicide') { + result = [...result, trace.action.address.toLowerCase(), trace.action.refundAddress.toLowerCase()]; + } + // grab event inputs params from decoded trace + const partiesFromTrace: string[] = trace.decode?.fragment.inputs + .map((param, index) => (param.type === 'address' ? trace.decode.args[index].toLowerCase() : '')) + .filter((address) => address !== ''); + + if (partiesFromTrace?.length > 0) { + result = [...result, ...partiesFromTrace]; + } + return result; + }); + // addresses from logs + const logParties = tx.receipt.logs.map((log) => { + let result = [log.address.toLowerCase()]; + // grab event inputs params from decoded log + const partiesFromLog: string[] = log.decode?.fragment.inputs + .map((param, index) => (param.type === 'address' ? log.decode.args[index].toLowerCase() : '')) + .filter((address) => address !== ''); + + if (partiesFromLog?.length > 0) { + result = [...result, ...partiesFromLog]; + } + return result; + }); + // nfts + const nfts = tx.receipt.logs + .filter( + (log) => + (log.decode?.name === 'Transfer' || log.decode?.name === 'Approval') && + log.decode?.fragment.inputs[2]?.type === 'uint256' + ) + .map((log) => `${log.address.toLowerCase()}-${log.decode?.args[2]}`); + // contracts created + const contractsCreated: string[] = tx.contracts?.map((contract) => contract.address); + parties = [...parties, ...traceParties.flat(), ...logParties.flat(), ...nfts.flat()]; + if (inputAddresses?.length > 0) { + parties = [...parties, ...inputAddresses]; + } + if (contractsCreated?.length > 0) { + parties = [...parties, ...contractsCreated]; + } + + return { hash: tx.hash, parties: [...new Set(parties)].filter((party) => party) }; + }); + + return result; +} diff --git a/src/transformers/_common/transactionProxyUpgrades.ts b/src/transformers/_common/transactionProxyUpgrades.ts new file mode 100644 index 0000000..45b9425 --- /dev/null +++ b/src/transformers/_common/transactionProxyUpgrades.ts @@ -0,0 +1,42 @@ +import type { RawBlock, RawTransaction } from '../types'; +import { TRANSPARENT_UPGRADEABLE_PROXY_EVENTS } from '../helpers/constants'; +import { decodeEVMAddress } from '../helpers/utils'; + +type ProxyUpgrade = { hash: string; address: string; upgradedAddress: string }; + +function getProxyUpgrades(tx: RawTransaction): ProxyUpgrade[] { + const proxyUpgrades: ProxyUpgrade[] = []; + for (const log of tx.receipt.logs) { + const [signature] = log.topics; + // detect upgrade event + if (signature === TRANSPARENT_UPGRADEABLE_PROXY_EVENTS['Upgraded(address)']) { + // store proxy upgrades + const address = log.address.toLowerCase(); + let upgradedAddress = ''; + // check if its beacon proxy + if (log.data === '0x') { + upgradedAddress = decodeEVMAddress(log.topics[1]); + } else { + upgradedAddress = decodeEVMAddress(log.data); + } + proxyUpgrades.push({ + hash: tx.hash, + address, + upgradedAddress, + }); + } + } + + return proxyUpgrades; +} + +export function transform(block: RawBlock): ProxyUpgrade[] { + let results: ProxyUpgrade[] = []; + + for (const tx of block.transactions) { + const proxyUpgrades = getProxyUpgrades(tx); + results = [...results, ...proxyUpgrades]; + } + + return results; +} diff --git a/src/transformers/_common/transactionSigHash.ts b/src/transformers/_common/transactionSigHash.ts new file mode 100644 index 0000000..ba7b6ad --- /dev/null +++ b/src/transformers/_common/transactionSigHash.ts @@ -0,0 +1,16 @@ +import type { RawBlock, TransactionWithHash, InternalHashType } from '../types'; + +export function transform(block: RawBlock): TransactionWithHash[] { + const result: TransactionWithHash[] = block.transactions.map((tx) => { + const sigHash = tx.input.slice(0, 10); + const internalSigHashes: InternalHashType[] = tx.traces.map((trace) => ({ + from: trace.action.from, + to: trace.action.to, + sigHash: String(trace.action.input).slice(0, 10), + })); + + return { hash: tx.hash, sigHash, internalSigHashes }; + }); + + return result; +} diff --git a/src/transformers/_common/transactionTimestamp.ts b/src/transformers/_common/transactionTimestamp.ts new file mode 100644 index 0000000..11bfd90 --- /dev/null +++ b/src/transformers/_common/transactionTimestamp.ts @@ -0,0 +1,13 @@ +import type { RawBlock } from '../types'; + +export function transform(block: RawBlock) { + const isoTimestamp = new Date(block.timestamp * 1000).toISOString(); + + return ( + block.transactions?.slice().map((tx) => ({ + hash: tx.hash, + timestamp: block.timestamp, + isoTimestamp, + })) || [] + ); +} diff --git a/src/transformers/ethereum/blockEthPrice.ts b/src/transformers/ethereum/blockEthPrice.ts new file mode 100644 index 0000000..f43a303 --- /dev/null +++ b/src/transformers/ethereum/blockEthPrice.ts @@ -0,0 +1,164 @@ +import BigNumber from 'bignumber.js'; + +import etherscanPrices from '../helpers/etherscan_prices.json'; +import { toBigNumber } from '../helpers/utils'; +import { RawBlock } from '../types'; +import { decodeEvent } from '../helpers/sigMapper'; + +const ETH_DECIMALS = Math.pow(10, 18); +const USD_DECIMALS = Math.pow(10, 6); + +// put some rough safe guards around removing huge price swings +const MIN_USD_AMOUNT_TO_CONSIDER = 100; +const MAX_USD_AMOUNT_TO_CONSIDER = 10000; + +const etherscanPriceByDay: Record = {}; +for (const { UTCDate, value } of etherscanPrices.result) { + etherscanPriceByDay[UTCDate] = parseFloat(value); +} + +// define the Uniswap pools we want to use +const uniSwapV1USDC = '0x97dec872013f6b5fb443861090ad931542878126'; +const uniSwapV2ETHPools = new Set([ + '0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc', // V2: USDC + '0x0d4a11d5eeaac28ec3f61d100daf4d40471f1852', // V2: USDT +]); +const uniSwapV3ETHPools = new Set([ + '0x7bea39867e4169dbe237d55c8242a8f2fcdcc387', // V3: USDC 1 + '0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8', // V3: USDC 2 + '0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640', // V3: USDC 3 + '0x4e68ccd3e89f51c3074ca5072bbac773960dfa36', // V3: USDT 1 + '0xc5af84701f98fa483ece78af83f11b6c38aca71d', // V3: USDT 2 + '0x11b815efb8f581194ae79006d24e0d814b7697f6', // V3: USDT 3 +]); + +export function transform(block: RawBlock) { + const result: { number: number; price?: number; priceSource?: 'ETHERSCAN' | 'UNISWAP' } = { number: block.number }; + const date = new Date(block.timestamp * 1000); + const swaps: { price: BigNumber; volume: BigNumber }[] = []; + + // if we're pre UniSwap usage (~ February 2019), then use Etherscan prices + if (block.number < 7207017) { + // only track the price for the block right at midnight + if (date.getUTCHours() === 0 && date.getUTCMinutes() === 0 && date.getUTCSeconds() < 30) { + result.price = etherscanPriceByDay[`${date.getUTCFullYear()}-${date.getUTCMonth() + 1}-${date.getUTCDate()}`]; + result.priceSource = 'ETHERSCAN'; + } + } + + // for the next year, look at adding liquidity to the original USDC Uniswap "pool" + else if (block.number < 10093190) { + for (const tx of block.transactions) { + for (const log of tx.receipt.logs) { + if ( + log.address === uniSwapV1USDC && + log.topics[0] === '0x06239653922ac7bea6aa2b19dc486b9361821d37712eb796adfd38d81de278ca' + ) { + const usd = toBigNumber(log.topics[3]).div(USD_DECIMALS); + if (usd.gte(MIN_USD_AMOUNT_TO_CONSIDER)) { + const eth = toBigNumber(log.topics[2]).div(ETH_DECIMALS); + swaps.push({ price: usd.dividedBy(eth), volume: usd }); + } + } + } + } + } + + // and after May 2020, look to swaps on USDC and USDT Uniswap Pools + else { + for (const tx of block.transactions) { + for (const log of tx.receipt.logs) { + let amounts: BigNumber[] = []; + + // check V2 swap logs + if ( + uniSwapV2ETHPools.has(log.address) && + log.topics[0] === '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822' && + log.topics.length === 3 + ) { + const params = decodeEvent( + [ + { + anonymous: false, + inputs: [ + { indexed: true, internalType: 'address', name: 'sender', type: 'address' }, + { indexed: false, internalType: 'uint256', name: 'amount0In', type: 'uint256' }, + { indexed: false, internalType: 'uint256', name: 'amount1In', type: 'uint256' }, + { indexed: false, internalType: 'uint256', name: 'amount0Out', type: 'uint256' }, + { indexed: false, internalType: 'uint256', name: 'amount1Out', type: 'uint256' }, + { indexed: true, internalType: 'address', name: 'to', type: 'address' }, + ], + name: 'Swap', + type: 'event', + }, + ], + log.topics, + log.data + ); + + // first 4 data params are possible amounts, only 2 are used + amounts = params.args.slice(1, 5).map((v) => toBigNumber(v)); + } + + // and check V3 swap logs + else if ( + uniSwapV3ETHPools.has(log.address) && + log.topics[0] === '0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67' && + log.topics.length === 3 + ) { + const params = decodeEvent( + [ + { + anonymous: false, + inputs: [ + { indexed: true, internalType: 'address', name: 'sender', type: 'address' }, + { indexed: true, internalType: 'address', name: 'recipient', type: 'address' }, + { indexed: false, internalType: 'int256', name: 'amount0', type: 'int256' }, + { indexed: false, internalType: 'int256', name: 'amount1', type: 'int256' }, + { indexed: false, internalType: 'uint160', name: 'sqrtPriceX96', type: 'uint160' }, + { indexed: false, internalType: 'uint128', name: 'liquidity', type: 'uint128' }, + { indexed: false, internalType: 'int24', name: 'tick', type: 'int24' }, + ], + name: 'Swap', + type: 'event', + }, + ], + log.topics, + log.data + ); + + // first 2 data params are possible amounts, one is always negative + amounts = params.args.slice(2, 4).map((v) => toBigNumber(v).abs()); + } + + if (amounts.length >= 2) { + // because ETH has 3x the decimals, it will always be the larger number prior to normalizing + let [usd, eth] = amounts.filter((a) => a.gt(0)).sort((a, b) => (a.gt(b) ? 1 : -1)); + if (!usd || !eth) { + continue; + } + + usd = usd.div(USD_DECIMALS); + if (usd.gte(MIN_USD_AMOUNT_TO_CONSIDER) && usd.lte(MAX_USD_AMOUNT_TO_CONSIDER)) { + eth = eth.div(ETH_DECIMALS); + swaps.push({ price: usd.dividedBy(eth), volume: usd }); + } + } + } + } + } + + // compute a quick Volume Weight Average Price (VWAP) for the block + if (swaps.length) { + const totalVolume = swaps.reduce((a, b) => a.plus(b.volume), toBigNumber(0)); + const price = swaps.reduce((a, b) => a.plus(b.price.multipliedBy(b.volume)), toBigNumber(0)).div(totalVolume); + result.price = price.decimalPlaces(2).toNumber(); + result.priceSource = 'UNISWAP'; + } + + if (!result.price) { + delete result.price; + delete result.priceSource; + } + return result; +} diff --git a/src/transformers/ethereum/blockFork.ts b/src/transformers/ethereum/blockFork.ts new file mode 100644 index 0000000..edc88e3 --- /dev/null +++ b/src/transformers/ethereum/blockFork.ts @@ -0,0 +1,27 @@ +import type { RawBlock } from '../types'; +import { FORKS } from '../helpers/constants'; + +export function transform(block: RawBlock) { + let fork: string; + + for (const [forkName, forkNumber] of Object.entries(FORKS)) { + if (block.number >= forkNumber) { + fork = forkName; + } + } + + let minerReward: number; + if (block.number < FORKS.byzantium) { + minerReward = 5; + } else if (block.number < FORKS.constantinople) { + minerReward = 3; + } else { + minerReward = 2; + } + + return { + number: block.number, + fork, + minerReward, + }; +} diff --git a/src/transformers/ethereum/contractPropHouseDetection.ts b/src/transformers/ethereum/contractPropHouseDetection.ts new file mode 100644 index 0000000..ebc7c06 --- /dev/null +++ b/src/transformers/ethereum/contractPropHouseDetection.ts @@ -0,0 +1,82 @@ +import { ethers } from 'ethers'; +import type { RawBlock, TransactionContract, PropHouseDao } from '../types'; +import { + PROP_HOUSE_PROXY_CONTRACT, + PROP_HOUSE_DAO_DEPLOYED_EVENT_HASH, + PROP_HOUSE_DAO_DEPLOYED_EVENT, +} from '../helpers/constants'; + +export function transform(block: RawBlock): TransactionContract[] { + const result: TransactionContract[] = block.transactions + .filter((tx) => tx.contracts?.length > 0) + .map((tx) => { + const propHouseDaos: PropHouseDao[] = tx.receipt.logs + .filter( + (log) => + log.topics[0] === PROP_HOUSE_DAO_DEPLOYED_EVENT_HASH && + log.address.toLowerCase() === PROP_HOUSE_PROXY_CONTRACT.toLowerCase() + ) + .map((log) => { + // decode log + try { + const iface = new ethers.Interface([PROP_HOUSE_DAO_DEPLOYED_EVENT]); + const logDescriptor = iface.parseLog({ + topics: log.topics, + data: log.data, + }); + // get governor address from decoded log + const token = logDescriptor.args[0] as string; + const metadata = logDescriptor.args[1] as string; + const auction = logDescriptor.args[2] as string; + const treasury = logDescriptor.args[3] as string; + const governor = logDescriptor.args[4] as string; + + return { + token: token.toLowerCase(), + metadata: metadata.toLowerCase(), + auction: auction.toLowerCase(), + treasury: treasury.toLowerCase(), + governor: governor.toLowerCase(), + }; + } catch (e) { + return null; + } + }) + .filter((v) => v); + + const propHouseTokens = propHouseDaos.map((dao) => dao.token); + const propHouseMetadatas = propHouseDaos.map((dao) => dao.metadata); + const propHouseAuctions = propHouseDaos.map((dao) => dao.auction); + const propHouseTreasuries = propHouseDaos.map((dao) => dao.treasury); + const propHouseGovernors = propHouseDaos.map((dao) => dao.governor); + + // check contracts + const contracts = tx.contracts.map((contract) => { + // check if contract is PropHouse token address + if (propHouseTokens.includes(contract.address)) { + contract.metadata.isPropHouseToken = true; + } + // check if contract is PropHouse metadata address + if (propHouseMetadatas.includes(contract.address)) { + contract.metadata.isPropHouseMetadata = true; + } + // check if contract is PropHouse auction address + if (propHouseAuctions.includes(contract.address)) { + contract.metadata.isPropHouseAuction = true; + } + // check if contract is PropHouse treasuries address + if (propHouseTreasuries.includes(contract.address)) { + contract.metadata.isPropHouseTreasury = true; + } + // check if contract is PropHouse governor address + if (propHouseGovernors.includes(contract.address)) { + contract.metadata.isPropHouseGovernor = true; + } + return contract; + }); + + return { hash: tx.hash, contracts }; + }); + + return result; +} diff --git a/src/transformers/ethereum/contractUniswapDetection.ts b/src/transformers/ethereum/contractUniswapDetection.ts new file mode 100644 index 0000000..0649407 --- /dev/null +++ b/src/transformers/ethereum/contractUniswapDetection.ts @@ -0,0 +1,112 @@ +import { ethers } from 'ethers'; +import type { RawBlock, TransactionContract, UniswapPair } from '../types'; +import { decodeEVMAddress } from '../helpers/utils'; +import { + UNISWAP_V3_FACTORY, + UNISWAP_V2_FACTORY, + UNISWAP_V1_FACTORY, + UNISWAP_V3_POOL_CREATED_EVENT, + UNISWAP_V2_PAIR_CREATED_EVENT, + UNISWAP_V1_NEW_EXCHANGE_EVENT_HASH, + UNISWAP_V2_PAIR_CREATED_EVENT_HASH, + UNISWAP_V3_POOL_CREATED_EVENT_HASH, +} from '../helpers/constants'; + +export function transform(block: RawBlock): TransactionContract[] { + const result: TransactionContract[] = block.transactions + .filter((tx) => tx.contracts?.length > 0) + .map((tx) => { + const uniswapV3Pools: UniswapPair[] = tx.receipt.logs + .filter((log) => log.topics[0] === UNISWAP_V3_POOL_CREATED_EVENT_HASH && log.address === UNISWAP_V3_FACTORY) + .map((log) => { + // decode log + try { + const iface = new ethers.Interface([UNISWAP_V3_POOL_CREATED_EVENT]); + const logDescriptor = iface.parseLog({ + topics: log.topics, + data: log.data, + }); + // get pool address from decoded log + const pool = logDescriptor.args[4] as string; + // get token addresses + const tokenA = decodeEVMAddress(log.topics[1]); + const tokenB = decodeEVMAddress(log.topics[2]); + + return { + address: pool.toLowerCase(), + tokens: [tokenA.toLowerCase(), tokenB.toLowerCase()], + }; + } catch (e) { + return null; + } + }) + .filter((v) => v); + + const uniswapV2Pairs: UniswapPair[] = tx.receipt.logs + .filter((log) => log.topics[0] === UNISWAP_V2_PAIR_CREATED_EVENT_HASH && log.address === UNISWAP_V2_FACTORY) + .map((log) => { + // decode log + try { + const iface = new ethers.Interface([UNISWAP_V2_PAIR_CREATED_EVENT]); + const logDescriptor = iface.parseLog({ + topics: log.topics, + data: log.data, + }); + // get pool address from decoded log + const pool = logDescriptor.args[2] as string; + // get token addresses + const tokenA = decodeEVMAddress(log.topics[1]); + const tokenB = decodeEVMAddress(log.topics[2]); + + return { + address: pool.toLowerCase(), + tokens: [tokenA.toLowerCase(), tokenB.toLowerCase()], + }; + } catch (e) { + return null; + } + }) + .filter((v) => v); + + const uniswapV1Exchanges: UniswapPair[] = tx.receipt.logs + .filter((log) => log.topics[0] === UNISWAP_V1_NEW_EXCHANGE_EVENT_HASH && log.address === UNISWAP_V1_FACTORY) + .map((log) => { + // go trough traces and tract create call + const exchangeCreateTrace = tx.traces.find((trace) => trace.type === 'create'); + const pool = exchangeCreateTrace.result.address; + // get token addresses + const tokenA = decodeEVMAddress(log.topics[1]); + const tokenB = decodeEVMAddress(log.topics[2]); + + return { + address: pool.toLowerCase(), + tokens: [tokenA.toLowerCase(), tokenB.toLowerCase()], + }; + }); + + // check contracts + const contracts = tx.contracts.map((contract) => { + const v3Pair = uniswapV3Pools.find((pair) => pair.address === contract.address); + const v2Pair = uniswapV2Pairs.find((pair) => pair.address === contract.address); + const v1Pair = uniswapV1Exchanges.find((pair) => pair.address === contract.address); + // check if contract is uniswap v3 pool + if (v3Pair) { + contract.metadata.isUniswapV3 = true; + contract.metadata.uniswapPairs = v3Pair.tokens; + } + if (v2Pair) { + contract.metadata.isUniswapV2 = true; + contract.metadata.uniswapPairs = v2Pair.tokens; + } + if (v1Pair) { + contract.metadata.isUniswapV1 = true; + contract.metadata.uniswapPairs = v1Pair.tokens; + } + return contract; + }); + + return { hash: tx.hash, contracts }; + }); + + return result; +} diff --git a/src/transformers/ethereum/transactionAssetTransfersOldNFTs.ts b/src/transformers/ethereum/transactionAssetTransfersOldNFTs.ts new file mode 100644 index 0000000..55b1acf --- /dev/null +++ b/src/transformers/ethereum/transactionAssetTransfersOldNFTs.ts @@ -0,0 +1,113 @@ +import { decodeEVMAddress, toBigNumber } from '../helpers/utils'; +import type { AssetTransfer, RawBlock, RawTransaction, transactionAssetTransfers } from '../types'; +import { + KNOWN_ADDRESSES, + OLD_NFT_ADDRESSES, + ERC721_TRANSFER_EVENT_1, + ERC721_TRANSFER_EVENT_2, +} from '../helpers/constants'; +import { decodeEvent } from '../helpers/sigMapper'; + +const TRANSFER_SIGNATURES = { + // event Transfer(address,address,uint256) + ERC721: '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', + + // event PunkTransfer(address indexed from, address indexed to, uint256 punkIndex) + CRYPTO_PUNKS_ERC721: '0x05af636b70da6819000c49f85b21fa82081c632069bb626f30932034099107d8', +}; + +function updateTokenTransfers(tx: RawTransaction) { + const oldNFTsTransfers: AssetTransfer[] = []; + + for (const log of tx.receipt.logs) { + if (!OLD_NFT_ADDRESSES.includes(log.address)) { + continue; + } + + const [signature] = log.topics; + + switch (signature) { + // @NOTE: all of these cases are the same function signature + case TRANSFER_SIGNATURES.ERC721: { + // for cryptopunks, we skip Transfer event and parse PunkTransfer + if (log.address === KNOWN_ADDRESSES.CryptoPunksNew || log.address === KNOWN_ADDRESSES.CryptoPunksOld) { + continue; + } + + // check for old nfts + let logDescriptor = decodeEvent([ERC721_TRANSFER_EVENT_1], log.topics, log.data); + if (!logDescriptor) { + logDescriptor = decodeEvent([ERC721_TRANSFER_EVENT_2], log.topics, log.data); + } + if (logDescriptor) { + oldNFTsTransfers.push({ + asset: log.address, + from: logDescriptor.args[0] as string, + to: logDescriptor.args[1] as string, + tokenId: logDescriptor.args[2] as string, + type: 'erc721', + }); + } else { + // if there's a 4th topic (indexed parameter), then it's an ERC721 + if (log.topics.length === 4) { + oldNFTsTransfers.push({ + asset: log.address, + from: decodeEVMAddress(log.topics[1]), + to: decodeEVMAddress(log.topics[2]), + tokenId: toBigNumber(log.topics[3]).toString(), + type: 'erc721', + }); + } else { + oldNFTsTransfers.push({ + asset: log.address, + from: decodeEVMAddress(log.topics[1]), + to: decodeEVMAddress(log.topics[2]), + value: toBigNumber(log.data).toString(), + type: 'erc721', + }); + } + } + + continue; + } + + case TRANSFER_SIGNATURES.CRYPTO_PUNKS_ERC721: { + oldNFTsTransfers.push({ + asset: log.address, + from: decodeEVMAddress(log.topics[1]), + to: decodeEVMAddress(log.topics[2]), + tokenId: toBigNumber(log.data).toString(), + type: 'erc721', + }); + continue; + } + + default: + break; + } + } + + // filter old asset transfers from previous asset transfers + const nonOldAssetTransfers = tx.assetTransfers.filter( + (assetTransfer) => !OLD_NFT_ADDRESSES.includes(assetTransfer.asset) + ); + const assetTransfers = [...nonOldAssetTransfers, ...oldNFTsTransfers]; + + return assetTransfers; +} + +export function transform(block: RawBlock) { + const results: transactionAssetTransfers[] = block.transactions.map((tx) => { + let assetTransfers = tx.assetTransfers; + const hasOldNFTTransfer = tx.assetTransfers?.some((assetTransfer) => + OLD_NFT_ADDRESSES.includes(assetTransfer.asset) + ); + if (hasOldNFTTransfer) { + assetTransfers = updateTokenTransfers(tx); + } + + return { hash: tx.hash, assetTransfers }; + }); + + return results; +} diff --git a/src/transformers/ethereum/transactionFees.ts b/src/transformers/ethereum/transactionFees.ts new file mode 100644 index 0000000..ca823d7 --- /dev/null +++ b/src/transformers/ethereum/transactionFees.ts @@ -0,0 +1,40 @@ +import type { RawBlock, RawTransaction } from '../types'; +import { toBigNumber } from '../helpers/utils'; +import { FORKS } from '../helpers/constants'; + +export function transform(block: RawBlock) { + const newTxs: Partial[] = []; + + for (const tx of block.transactions) { + const transactionFee = toBigNumber(tx.receipt.gasUsed) + .multipliedBy(toBigNumber(tx.receipt.effectiveGasPrice)) + .toString(); + + let burntFees = '0'; + let minerFees = transactionFee; + + /*** + * Legacy tx after EIP1559 https://legacy.ethgasstation.info/blog/eip-1559/ + * "EIP-1559 will still be able to facilitate legacy style transactions. + * When these transactions come in their gas prices are simply converted into fee caps, + * including respective base fees and tips." + */ + if (tx.type === 2 && block.number >= FORKS.london) { + burntFees = toBigNumber(block.baseFeePerGas).multipliedBy(toBigNumber(tx.receipt.gasUsed)).toString(); + minerFees = toBigNumber(tx.receipt.effectiveGasPrice) + .minus(toBigNumber(block.baseFeePerGas)) + .multipliedBy(toBigNumber(tx.receipt.gasUsed)) + .toString(); + } + + newTxs.push({ + hash: tx.hash, + baseFeePerGas: block.baseFeePerGas, + burntFees, + minerFees, + transactionFee, + }); + } + + return newTxs; +} diff --git a/src/transformers/ethereum/transactionForks.ts b/src/transformers/ethereum/transactionForks.ts new file mode 100644 index 0000000..4c0dd7f --- /dev/null +++ b/src/transformers/ethereum/transactionForks.ts @@ -0,0 +1,14 @@ +import type { RawBlock } from '../types'; +import { FORKS } from '../helpers/constants'; + +export function transform(block: RawBlock) { + let fork: string; + + for (const [forkName, forkNumber] of Object.entries(FORKS)) { + if (block.number >= forkNumber) { + fork = forkName; + } + } + + return block.transactions?.slice().map((tx) => ({ hash: tx.hash, fork })) || []; +} diff --git a/src/transformers/helpers/constants.ts b/src/transformers/helpers/constants.ts new file mode 100644 index 0000000..ea7323a --- /dev/null +++ b/src/transformers/helpers/constants.ts @@ -0,0 +1,396 @@ +import 'dotenv/config'; +import { keccak256 } from 'web3-utils'; +import { AbiItem } from '../types'; + +export const CHAIN_IDS = { + base: 8453, + base_goerli: 84531, + base_sepolia: 84532, + eth_goerli: 5, + ethereum: 1, + linea: 59144, + lyra_sepolia: 901, + mode_sepolia: 919, + op_goerli: 420, + op_sepolia: 11155420, + optimism: 10, + orderly_sepolia: 4460, + pgn_sepolia: 58008, + public_goods_network: 424, + zora: 7777777, + zora_goerli: 999, + zora_sepolia: 999999999, +}; + +export const FORKS = { + frontier: 0, // July 30, 2015: https://ethereum.org/en/history/#frontier + frontier_thawing: 200000, // September 7, 2015: https://ethereum.org/en/history/#frontier-thawing + homestead: 1150000, // March 14, 2016: https://ethereum.org/en/history/#homestead + dao_fork: 1920000, // July 20, 2016: https://ethereum.org/en/history/#dao-fork + tangerine_whistle: 2463000, // October 18, 2016: https://ethereum.org/en/history/#tangerine-whistle + spurious_dragon: 2675000, // November 22, 2016: https://ethereum.org/en/history/#spurious-dragon + byzantium: 4370000, // October 16, 2017: https://ethereum.org/en/history/#byzantium + constantinople: 7280000, // February 28, 2019: https://ethereum.org/en/history/#constantinople + istanbul: 9069000, // December 8, 2019: https://ethereum.org/en/history/#istanbul + muir_glacier: 9200000, // January 2, 2020: https://ethereum.org/en/history/#muir-glacier + berlin: 1244000, // April 15, 2021: https://ethereum.org/en/history/#berlin + london: 12965000, // August 05, 2021: https://ethereum.org/en/history/#london + arrow_glacier: 13773000, // December 9, 2021: https://ethereum.org/en/history/#arrow-glacier + gray_glacier: 15050000, // June 30, 2022: https://ethereum.org/en/history/#gray-glacier + paris: 15537394, // September 15, 2022: https://ethereum.org/en/history/#paris + shanghai: 17034870, // April 12, 2023: https://ethereum.org/en/history/#shanghai +}; + +// Helper method for building dictionary of method signatures => method hashes +const createSignatureMapping = (signatures: string[]) => { + const mapping: Record = {}; + for (const signature of signatures) { + mapping[signature] = keccak256(signature).slice(2, 10); + } + return mapping; +}; + +// https://eips.ethereum.org/EIPS/eip-20 +export const ERC20_METHOD_SIGNATURES = [ + 'totalSupply()', + 'balanceOf(address)', + 'transfer(address,uint256)', + 'transferFrom(address,address,uint256)', + 'approve(address,uint256)', + 'allowance(address,address)', +]; + +export const ERC20_METHODS = createSignatureMapping(ERC20_METHOD_SIGNATURES); + +// https://eips.ethereum.org/EIPS/eip-777 +export const ERC777_METHOD_SIGNATURES = [ + 'totalSupply()', + 'balanceOf(address)', + 'granularity()', + 'defaultOperators()', + 'isOperatorFor(address,address)', + 'authorizeOperator(address)', + 'revokeOperator(address)', + 'send(address,uint256,bytes)', + 'operatorSend(address,address,uint256,bytes,bytes)', + 'burn(uint256,bytes)', + 'operatorBurn(address,uint256,bytes,bytes)', +]; + +export const ERC777_METHODS = createSignatureMapping(ERC777_METHOD_SIGNATURES); + +// TODO - ERC721_OLD_METHOD_SIGNATURES (e.g. CryptoKitties, CryptoStrikers, CryptoArte, etc.) + +// https://ethereum.org/en/developers/docs/standards/tokens/erc-721/#methods +export const ERC721_METHOD_SIGNATURES = [ + 'balanceOf(address)', + 'ownerOf(uint256)', + 'safeTransferFrom(address,address,uint256,bytes)', + 'safeTransferFrom(address,address,uint256)', + 'transferFrom(address,address,uint256)', + 'approve(address,uint256)', + 'setApprovalForAll(address,bool)', + 'getApproved(uint256)', + 'isApprovedForAll(address,address)', +]; + +export const ERC721_METHODS = createSignatureMapping(ERC721_METHOD_SIGNATURES); + +// NOTE - ERC721a implements ERC721, so we don't need to include ERC721a methods here https://www.azuki.com/erc721a + +// https://eips.ethereum.org/EIPS/eip-1155 +export const ERC1155_METHOD_SIGNATURES = [ + // TODO - For some reason balanceOf(address,uint256) is not showing up in the bytecode for erc1155s + // balanceOf(address,uint256), + 'balanceOfBatch(address[],uint256[])', + 'setApprovalForAll(address,bool)', + 'isApprovedForAll(address,address)', + 'safeTransferFrom(address,address,uint256,uint256,bytes)', + 'safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)', +]; + +export const ERC1155_METHODS = createSignatureMapping(ERC1155_METHOD_SIGNATURES); + +//https://eips.ethereum.org/EIPS/eip-165 +export const ERC165_METHOD_SIGNATURES = ['supportsInterface(bytes4)']; + +export const ERC165_METHODS = createSignatureMapping(ERC165_METHOD_SIGNATURES); + +// Contract Addresses +export const OPENSEA_REGISTRY_SIGNATURES = ['registerProxy()']; +export const OPENSEA_REGISTRY_METHODS = createSignatureMapping(OPENSEA_REGISTRY_SIGNATURES); +export const OPENSEA_REGISTRY_ADDRESS = '0xa5409ec958c83c3f309868babaca7c86dcb077c1'; + +// Gnosis Safe +export const GNOSIS_SAFE_FACTORY_METHOD_SIGNATURES = [ + 'createProxy(address,bytes)', + 'createProxyWithNonce(address,bytes,uint256)', + 'createProxyWithCallback(address,bytes,uint256,address)', +]; + +export const GNOSIS_SAFE_FACTORY_METHODS = createSignatureMapping(GNOSIS_SAFE_FACTORY_METHOD_SIGNATURES); + +export const GNOSIS_SAFE_FACTORY_0_1_0_ADDRESS = '0x88cd603a5dc47857d02865bbc7941b588c533263'; // Not used often +export const GNOSIS_SAFE_FACTORY_1_0_0_ADDRESS = '0x12302fe9c02ff50939baaaaf415fc226c078613c'; // This release appears to have been buggy and didn't deploy contracts often +export const GNOSIS_SAFE_FACTORY_1_0_1_ADDRESS = '0x50e55af101c777ba7a1d560a774a82ef002ced9f'; // Not used often +export const GNOSIS_SAFE_FACTORY_1_1_1_ADDRESS = '0x76e2cfc1f5fa8f6a5b3fc4c8f4788f0116861f9b'; +export const GNOSIS_SAFE_FACTORY_1_3_0_ADDRESS = '0xa6b71e26c5e0845f74c812102ca7114b6a896ab2'; + +export const KNOWN_ADDRESSES = { + CryptoKitties: '0x06012c8cf97bead5deae237070f9587f8e7a266d', // Meow + CryptoPunksNew: '0xb47e3cd837ddf8e4c57f05d70ab865de6e193bbb', + CryptoPunksOld: '0x6ba6f2207e343923ba692e5cae646fb0f566db8d', + CryptoStrikers: '0xdcaad9fd9a74144d226dbf94ce6162ca9f09ed7e', + NULL: '0x0000000000000000000000000000000000000000', + WETH: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', +}; + +// Helper method for building dictionary of event signatures => event hashes +const createEventSignatureMapping = (signatures: string[]) => { + const mapping: Record = {}; + for (const signature of signatures) { + mapping[signature] = keccak256(signature); + } + return mapping; +}; + +// https://eips.ethereum.org/EIPS/eip-1967 +export const TRANSPARENT_UPGRADEABLE_PROXY_EVENT_SIGNATURES = ['Upgraded(address)']; + +export const TRANSPARENT_UPGRADEABLE_PROXY_EVENTS = createEventSignatureMapping( + TRANSPARENT_UPGRADEABLE_PROXY_EVENT_SIGNATURES +); + +export const ERC20ABI: AbiItem[] = [ + { + name: 'name', + inputs: [], + outputs: [{ name: '', type: 'string' }], + type: 'function', + }, + { + name: 'symbol', + inputs: [], + outputs: [{ name: '', type: 'string' }], + type: 'function', + }, + { + name: 'decimals', + inputs: [], + outputs: [{ name: '', type: 'uint8' }], + type: 'function', + }, +]; + +export const ERC721ABI: AbiItem[] = [ + { + name: 'name', + inputs: [], + outputs: [{ name: '', type: 'string' }], + type: 'function', + }, + { + name: 'symbol', + inputs: [], + outputs: [{ name: '', type: 'string' }], + type: 'function', + }, +]; + +export const ERC165ABI: AbiItem[] = [ + { + constant: true, + inputs: [ + { + internalType: 'bytes4', + name: 'interfaceId', + type: 'bytes4', + }, + ], + name: 'supportsInterface', + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool', + }, + ], + payable: false, + stateMutability: 'view', + type: 'function', + }, +]; + +export const ERC165_CHECK_INPUTS = [ + '0x01ffc9a701ffc9a700000000000000000000000000000000000000000000000000000000', + '0x01ffc9a7ffffffff00000000000000000000000000000000000000000000000000000000', +]; + +export const INTERFACE_IDS = { + ERC1967: '0x2a55205a', + ERC721: '0x80ac58cd', + ERC165: '0x01ffc9a7', + ERC875: '0x553e757e', + ERC721Metadata: '0x5b5e139f', + ERC20: '0xb7799584', + ERC721Enumerable: '0x780e9d63', + ERC1155: '0xbb3bafd6', + ERC721BatchTransfer: '0xd9b67a26', + ERC777: '0x1890fe8e', + ERC721MetadataMintable: '0x7d248440', + ERC998: '0xec5f752e', + ERC1654: '0x1626ba7e', + ERC223: '0xc169902c', + ERC2981: '0x9385547e', + ERC721Pausable: '0x7a63aa3a', + ERC20Burnable: '0x40c1a064', + ERC20Mintable: '0xff5e34e7', + ERC721Burnable: '0xa1a3cd2a', + ERC1651: '0x54fd4d50', + ERC777TokensSender: '0xa920b78c', + ERC777TokensRecipient: '0x9a20483d', +}; + +export const GENERIC_GOVERNANCE_INTERFACES = ['0xbf26d897', '0x79dd796f', '0x3938f78a']; + +export const UNISWAP_V3_FACTORY = '0x1f98431c8ad98523631ae4a59f267346ea31f984'; +export const UNISWAP_V2_FACTORY = '0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f'; +export const UNISWAP_V1_FACTORY = '0xc0a47dfe034b400b47bdad5fecda2621de6c4d95'; +export const PROP_HOUSE_PROXY_CONTRACT = '0xd310a3041dfcf14def5ccbc508668974b5da7174'; +export const PROP_HOUSE_IMPLEMENTATION_CONTRACT = '0x138d8aef5cbbbb9ea8da98cc0847fe0f3b573b40'; + +export const UNISWAP_V3_POOL_CREATED_EVENT_HASH = '0x783cca1c0412dd0d695e784568c96da2e9c22ff989357a2e8b1d9b2b4e6b7118'; +export const UNISWAP_V2_PAIR_CREATED_EVENT_HASH = '0x0d3648bd0f6ba80134a33ba9275ac585d9d315f0ad8355cddefde31afa28d0e9'; +export const UNISWAP_V1_NEW_EXCHANGE_EVENT_HASH = '0x9d42cb017eb05bd8944ab536a8b35bc68085931dd5f4356489801453923953f9'; + +export const UNISWAP_V1_NEW_EXCHANGE_EVENT = 'event NewExchange(address,address)'; +export const UNISWAP_V2_PAIR_CREATED_EVENT = + 'event PairCreated(address indexed token0, address indexed token1, address pair, uint)'; +export const UNISWAP_V3_POOL_CREATED_EVENT = + 'event PoolCreated(address indexed token0, address indexed token1, uint24 indexed fee, int24 tickSpacing, address pool)'; + +export const PROP_HOUSE_DAO_DEPLOYED_EVENT_HASH = '0x456d2baf5a87d70e586ec06fb91c2d7849778dd41d80fa826a6ea5bf8d28e3a6'; +export const PROP_HOUSE_DAO_DEPLOYED_EVENT = 'event DAODeployed(address,address,address,address,address)'; + +// https://docs.openzeppelin.com/contracts/4.x/api/governance#IGovernor +export const GOVERNOR_METHOD_SIGNATURES = [ + 'name()', + 'version()', + 'COUNTING_MODE()', + 'hashProposal(address[],uint256[],bytes[],bytes32)', + 'state(uint256)', + 'proposalSnapshot(uint256)', + 'proposalDeadline(uint256)', + 'votingDelay()', + 'votingPeriod()', + 'quorum(uint256)', + 'getVotes(address,uint256)', + 'hasVoted(uint256,address)', + 'propose(address[],uint256[],bytes[],string)', + 'execute(address[],uint256[],bytes[],bytes32)', + 'castVote(uint256,uint8)', + 'castVoteWithReason(uint256,uint8,string)', + 'castVoteBySig(uint256,uint8,uint8,bytes32,bytes32)', +]; +export const GOVERNOR_METHODS = createSignatureMapping(GOVERNOR_METHOD_SIGNATURES); + +export const TOKEN_SWAP_CONTRACTS = [ + '0xe592427a0aece92de3edee1f18e0157c05861564', // Uniswap V3 Router + '0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45', // Uniswap V3router2 + '0x7a250d5630b4cf539739df2c5dacb4c659f2488d', // Uniswap V2 Router2 + '0xef1c6e67703c7bd7107eed8303fbe6ec2554bf6b', // Uniswap Universal Router + '0xd9e1ce17f2641f24ae83637ab66a2cca9c378b9f', // Sushiswap Router + '0x1111111254fb6c44bac0bed2854e76f90643097d', // 1inch Router + '0x881d40237659c251811cec9c364ef91dc08d300c', // Metamask Swap Router + '0xe66b31678d6c16e9ebf358268a790b763c133750', // Coinbase Wallet Swapper + '0x00000000009726632680fb29d3f7a9734e3010e2', // Rainbow Router + '0xdef1c0ded9bec7f1a1670819833240f027b25eff', // 0x Exchange Proxy. NOTE - This is both an erc20 swap and erc721 swap contract. This address is in both contract lists. +]; + +export const ERC721_SALE_CONTRACTS = [ + '0x00000000006c3852cbef3e08e8df289169ede581', // Seaport v1.1 + '0x00000000000006c7676171937c444f6bde3d6282', // Seaport v1.2 + '0x0000000000000ad24e80fd803c6ac37206a45f15', // Seaport v1.3 + '0x00000000000001ad428e4906ae43d8f9852d0dd6', // Seaport v1.4 + '0x00000000000000adc04c56bf30ac9d3c0aaf14dc', // Seaport v1.5 + '0x7be8076f4ea4a4ad08075c2508e481d6c946d12b', // Wyvern v1 + '0x7f268357a8c2552623316e2562d90e642bb538e5', // Wyvern v2 + '0x59728544b08ab483533076417fbbb2fd0b17ce3a', // LooksRare Exchange + '0x39da41747a83aee658334415666f3ef92dd0d541', // Blur 1 + '0x000000000000ad05ccc4f10045630fb830b95127', // Blur 2 + '0x1073777134ccc108b9f59bdceb101588d64b6bdb', // Cameron on Farcaster's Marketplace + '0xb4e7b8946fa2b35912cc0581772cccd69a33000c', // Element Swap 2 + '0x83c8f28c26bf6aaca652df1dbbe0e1b56f8baba2', // Gem + '0x0a267cf51ef038fc00e71801f5a524aec06e4f07', // Genie + '0xcdface5643b90ca4b3160dd2b5de80c1bf1cb088', // Genie: Seaport Aggregator + '0x74312363e45dcaba76c59ec49a7aa8a65a67eed3', // X2Y2 Exchange + '0xdef1c0ded9bec7f1a1670819833240f027b25eff', // 0x Exchange Proxy. NOTE - This is both an erc20 swap and erc721 swap contract. This address is in both contract lists. + '0x552b16d19dbad7af2786fe5a40d96d2a5c09428c', // AlphaSharks?? + '0x9e97195f937c9372fe5fda5e3b86e9b88cbefed7', // Gitcoin Grants Simple?? + '0x35ca26a7a7f3ca98f3e60bd94c139c892e45b6c3', // Gitcoin Grants Simple?? + '0x20f780a973856b93f63670377900c1d2a50a77c4', // Element Marketplace + '0x36c72892fcc72b52fa3b82ed3bb2a467d9079b9a', // Unknown + '0xe525fae3fc6fbb23af05e54ff413613a6573cff2', // Unknown discovered via Dreadfulz investigation (0x81ae0be3a8044772d04f32398bac1e1b4b215aa8) + '0xac335e6855df862410f96f345f93af4f96351a87', // Unknown discovered via Dreadfulz investigation (0x81ae0be3a8044772d04f32398bac1e1b4b215aa8) +]; + +export const SAFE_METHOD_SIGNATURES = [ + // GnosisSafe + // 'NAME()', + 'VERSION()', + 'nonce()', + 'domainSeparator()', + 'signedMessages(bytes32)', + // 'setup(address[],uint256,address,bytes,address,address,uint256,address)', + 'execTransaction(address,uint256,bytes,uint8,uint256,uint256,uint256,address,address,bytes)', + 'requiredTxGas(address,uint256,bytes,uint8)', + 'approveHash(bytes32)', + // 'signMessage(bytes)', + 'isValidSignature(bytes,bytes)', + // 'getMessageHash(bytes)', + 'encodeTransactionData(address,uint256,bytes,uint8,uint256,uint256,uint256,address,address,uint256)', + 'getTransactionHash(address,uint256,bytes,uint8,uint256,uint256,uint256,address,address,uint256)', + // MasterCopy + // 'changeMasterCopy(address)', + // ModuleManager + 'enableModule(address)', + 'disableModule(address,address)', + 'execTransactionFromModule(address,uint256,bytes,uint8)', + // 'execTransactionFromModuleReturnData(address,uint256,bytes,uint8)', + // 'getModules()', + // 'getModulesPaginated(address,uint256)', + // OwnerManager + 'addOwnerWithThreshold(address,uint256)', + 'removeOwner(address,address,uint256)', + 'swapOwner(address,address,address)', + 'changeThreshold(uint256)', + 'getThreshold()', + 'isOwner(address)', + 'getOwners()', + // FallbackManager + // 'setFallbackHandler(address)', +]; +export const SAFE_METHODS = createSignatureMapping(SAFE_METHOD_SIGNATURES); +export const EXECUTE_TRANSACTION_SIGNATURE = + 'execTransaction(address,uint256,bytes,uint8,uint256,uint256,uint256,address,address,bytes)'; + +export const OLD_NFT_ADDRESSES = [ + '0x6ba6f2207e343923ba692e5cae646fb0f566db8d', // CRYPTOPUNKS_OLD + '0xb47e3cd837ddf8e4c57f05d70ab865de6e193bbb', // CRYPTOPUNKS_NEW + '0x06012c8cf97bead5deae237070f9587f8e7a266d', // CryptoKitties + '0xe897e5953ef250bd49875fe7a48254def92730b9', // FanBits + '0x73b0ebea28f76be1368d578d13657354330472a9', // XART + '0xdcaad9fd9a74144d226dbf94ce6162ca9f09ed7e', // CryptoStrikers + '0xf5b0a3efb8e8e4c201e2a935f110eaaf3ffecb8d', // Axie Infinity + '0xf7a6e15dfd5cdd9ef12711bd757a9b6021abf643', // CryptoBots (NOTE - this one might be weird because the transfer event has _no_ indexed fields) + '0xdde2d979e8d39bb8416eafcfc1758f3cab2c9c72', // Known Origin + '0x79986af15539de2db9a5086382daeda917a9cf0c', // CryptoVoxels + '0x323a3e1693e7a0959f65972f3bf2dfcb93239dfe', // Digital Art Chain + '0x552d72f86f04098a4eaeda6d7b665ac12f846ad2', // Dark Winds +]; +export const ERC721_TRANSFER_EVENT_1 = 'event Transfer(address indexed,address indexed,uint256)'; +export const ERC721_TRANSFER_EVENT_2 = 'event Transfer(address,address,uint256)'; + +export const PROXY_IMPLEMENTATION_METHOD_SIGNATURES = ['implementation()', 'IMPL()']; + +export const PROXY_IMPLEMENTATION_METHODS = createSignatureMapping(PROXY_IMPLEMENTATION_METHOD_SIGNATURES); diff --git a/src/transformers/helpers/etherscan_prices.json b/src/transformers/helpers/etherscan_prices.json new file mode 100644 index 0000000..e248b6f --- /dev/null +++ b/src/transformers/helpers/etherscan_prices.json @@ -0,0 +1,1299 @@ +{ + "status": "1", + "message": "OK", + "result": [ + { "UTCDate": "2015-07-30", "unixTimeStamp": "1438214400", "value": "0.00" }, + { "UTCDate": "2015-07-31", "unixTimeStamp": "1438300800", "value": "0.00" }, + { "UTCDate": "2015-08-01", "unixTimeStamp": "1438387200", "value": "0.00" }, + { "UTCDate": "2015-08-02", "unixTimeStamp": "1438473600", "value": "0.00" }, + { "UTCDate": "2015-08-03", "unixTimeStamp": "1438560000", "value": "0.00" }, + { "UTCDate": "2015-08-04", "unixTimeStamp": "1438646400", "value": "0.00" }, + { "UTCDate": "2015-08-05", "unixTimeStamp": "1438732800", "value": "0.00" }, + { "UTCDate": "2015-08-06", "unixTimeStamp": "1438819200", "value": "0.00" }, + { "UTCDate": "2015-08-07", "unixTimeStamp": "1438905600", "value": "2.77" }, + { "UTCDate": "2015-08-08", "unixTimeStamp": "1438992000", "value": "0.81" }, + { "UTCDate": "2015-08-09", "unixTimeStamp": "1439078400", "value": "0.74" }, + { "UTCDate": "2015-08-10", "unixTimeStamp": "1439164800", "value": "0.68" }, + { "UTCDate": "2015-08-11", "unixTimeStamp": "1439251200", "value": "1.06" }, + { "UTCDate": "2015-08-12", "unixTimeStamp": "1439337600", "value": "1.25" }, + { "UTCDate": "2015-08-13", "unixTimeStamp": "1439424000", "value": "1.78" }, + { "UTCDate": "2015-08-14", "unixTimeStamp": "1439510400", "value": "1.80" }, + { "UTCDate": "2015-08-15", "unixTimeStamp": "1439596800", "value": "1.79" }, + { "UTCDate": "2015-08-16", "unixTimeStamp": "1439683200", "value": "1.37" }, + { "UTCDate": "2015-08-17", "unixTimeStamp": "1439769600", "value": "1.20" }, + { "UTCDate": "2015-08-18", "unixTimeStamp": "1439856000", "value": "1.27" }, + { "UTCDate": "2015-08-19", "unixTimeStamp": "1439942400", "value": "1.26" }, + { "UTCDate": "2015-08-20", "unixTimeStamp": "1440028800", "value": "1.48" }, + { "UTCDate": "2015-08-21", "unixTimeStamp": "1440115200", "value": "1.44" }, + { "UTCDate": "2015-08-22", "unixTimeStamp": "1440201600", "value": "1.39" }, + { "UTCDate": "2015-08-23", "unixTimeStamp": "1440288000", "value": "1.35" }, + { "UTCDate": "2015-08-24", "unixTimeStamp": "1440374400", "value": "1.24" }, + { "UTCDate": "2015-08-25", "unixTimeStamp": "1440460800", "value": "1.17" }, + { "UTCDate": "2015-08-26", "unixTimeStamp": "1440547200", "value": "1.16" }, + { "UTCDate": "2015-08-27", "unixTimeStamp": "1440633600", "value": "1.13" }, + { "UTCDate": "2015-08-28", "unixTimeStamp": "1440720000", "value": "1.30" }, + { "UTCDate": "2015-08-29", "unixTimeStamp": "1440806400", "value": "1.18" }, + { "UTCDate": "2015-08-30", "unixTimeStamp": "1440892800", "value": "1.32" }, + { "UTCDate": "2015-08-31", "unixTimeStamp": "1440979200", "value": "1.35" }, + { "UTCDate": "2015-09-01", "unixTimeStamp": "1441065600", "value": "1.35" }, + { "UTCDate": "2015-09-02", "unixTimeStamp": "1441152000", "value": "1.29" }, + { "UTCDate": "2015-09-03", "unixTimeStamp": "1441238400", "value": "1.26" }, + { "UTCDate": "2015-09-04", "unixTimeStamp": "1441324800", "value": "1.27" }, + { "UTCDate": "2015-09-05", "unixTimeStamp": "1441411200", "value": "1.37" }, + { "UTCDate": "2015-09-06", "unixTimeStamp": "1441497600", "value": "1.30" }, + { "UTCDate": "2015-09-07", "unixTimeStamp": "1441584000", "value": "1.24" }, + { "UTCDate": "2015-09-08", "unixTimeStamp": "1441670400", "value": "1.23" }, + { "UTCDate": "2015-09-09", "unixTimeStamp": "1441756800", "value": "1.21" }, + { "UTCDate": "2015-09-10", "unixTimeStamp": "1441843200", "value": "1.16" }, + { "UTCDate": "2015-09-11", "unixTimeStamp": "1441929600", "value": "0.98" }, + { "UTCDate": "2015-09-12", "unixTimeStamp": "1442016000", "value": "1.04" }, + { "UTCDate": "2015-09-13", "unixTimeStamp": "1442102400", "value": "0.94" }, + { "UTCDate": "2015-09-14", "unixTimeStamp": "1442188800", "value": "0.87" }, + { "UTCDate": "2015-09-15", "unixTimeStamp": "1442275200", "value": "0.94" }, + { "UTCDate": "2015-09-16", "unixTimeStamp": "1442361600", "value": "0.90" }, + { "UTCDate": "2015-09-17", "unixTimeStamp": "1442448000", "value": "0.89" }, + { "UTCDate": "2015-09-18", "unixTimeStamp": "1442534400", "value": "0.85" }, + { "UTCDate": "2015-09-19", "unixTimeStamp": "1442620800", "value": "0.89" }, + { "UTCDate": "2015-09-20", "unixTimeStamp": "1442707200", "value": "0.94" }, + { "UTCDate": "2015-09-21", "unixTimeStamp": "1442793600", "value": "0.90" }, + { "UTCDate": "2015-09-22", "unixTimeStamp": "1442880000", "value": "0.90" }, + { "UTCDate": "2015-09-23", "unixTimeStamp": "1442966400", "value": "0.90" }, + { "UTCDate": "2015-09-24", "unixTimeStamp": "1443052800", "value": "0.81" }, + { "UTCDate": "2015-09-25", "unixTimeStamp": "1443139200", "value": "0.74" }, + { "UTCDate": "2015-09-26", "unixTimeStamp": "1443225600", "value": "0.78" }, + { "UTCDate": "2015-09-27", "unixTimeStamp": "1443312000", "value": "0.72" }, + { "UTCDate": "2015-09-28", "unixTimeStamp": "1443398400", "value": "0.59" }, + { "UTCDate": "2015-09-29", "unixTimeStamp": "1443484800", "value": "0.68" }, + { "UTCDate": "2015-09-30", "unixTimeStamp": "1443571200", "value": "0.72" }, + { "UTCDate": "2015-10-01", "unixTimeStamp": "1443657600", "value": "0.68" }, + { "UTCDate": "2015-10-02", "unixTimeStamp": "1443744000", "value": "0.68" }, + { "UTCDate": "2015-10-03", "unixTimeStamp": "1443830400", "value": "0.69" }, + { "UTCDate": "2015-10-04", "unixTimeStamp": "1443916800", "value": "0.67" }, + { "UTCDate": "2015-10-05", "unixTimeStamp": "1444003200", "value": "0.63" }, + { "UTCDate": "2015-10-06", "unixTimeStamp": "1444089600", "value": "0.66" }, + { "UTCDate": "2015-10-07", "unixTimeStamp": "1444176000", "value": "0.61" }, + { "UTCDate": "2015-10-08", "unixTimeStamp": "1444262400", "value": "0.62" }, + { "UTCDate": "2015-10-09", "unixTimeStamp": "1444348800", "value": "0.65" }, + { "UTCDate": "2015-10-10", "unixTimeStamp": "1444435200", "value": "0.63" }, + { "UTCDate": "2015-10-11", "unixTimeStamp": "1444521600", "value": "0.63" }, + { "UTCDate": "2015-10-12", "unixTimeStamp": "1444608000", "value": "0.63" }, + { "UTCDate": "2015-10-13", "unixTimeStamp": "1444694400", "value": "0.60" }, + { "UTCDate": "2015-10-14", "unixTimeStamp": "1444780800", "value": "0.51" }, + { "UTCDate": "2015-10-15", "unixTimeStamp": "1444867200", "value": "0.56" }, + { "UTCDate": "2015-10-16", "unixTimeStamp": "1444953600", "value": "0.53" }, + { "UTCDate": "2015-10-17", "unixTimeStamp": "1445040000", "value": "0.55" }, + { "UTCDate": "2015-10-18", "unixTimeStamp": "1445126400", "value": "0.52" }, + { "UTCDate": "2015-10-19", "unixTimeStamp": "1445212800", "value": "0.49" }, + { "UTCDate": "2015-10-20", "unixTimeStamp": "1445299200", "value": "0.44" }, + { "UTCDate": "2015-10-21", "unixTimeStamp": "1445385600", "value": "0.44" }, + { "UTCDate": "2015-10-22", "unixTimeStamp": "1445472000", "value": "0.59" }, + { "UTCDate": "2015-10-23", "unixTimeStamp": "1445558400", "value": "0.52" }, + { "UTCDate": "2015-10-24", "unixTimeStamp": "1445644800", "value": "0.57" }, + { "UTCDate": "2015-10-25", "unixTimeStamp": "1445731200", "value": "0.65" }, + { "UTCDate": "2015-10-26", "unixTimeStamp": "1445817600", "value": "0.74" }, + { "UTCDate": "2015-10-27", "unixTimeStamp": "1445904000", "value": "0.87" }, + { "UTCDate": "2015-10-28", "unixTimeStamp": "1445990400", "value": "1.01" }, + { "UTCDate": "2015-10-29", "unixTimeStamp": "1446076800", "value": "1.16" }, + { "UTCDate": "2015-10-30", "unixTimeStamp": "1446163200", "value": "1.04" }, + { "UTCDate": "2015-10-31", "unixTimeStamp": "1446249600", "value": "0.89" }, + { "UTCDate": "2015-11-01", "unixTimeStamp": "1446336000", "value": "1.05" }, + { "UTCDate": "2015-11-02", "unixTimeStamp": "1446422400", "value": "0.96" }, + { "UTCDate": "2015-11-03", "unixTimeStamp": "1446508800", "value": "1.00" }, + { "UTCDate": "2015-11-04", "unixTimeStamp": "1446595200", "value": "0.87" }, + { "UTCDate": "2015-11-05", "unixTimeStamp": "1446681600", "value": "0.89" }, + { "UTCDate": "2015-11-06", "unixTimeStamp": "1446768000", "value": "0.92" }, + { "UTCDate": "2015-11-07", "unixTimeStamp": "1446854400", "value": "0.92" }, + { "UTCDate": "2015-11-08", "unixTimeStamp": "1446940800", "value": "1.02" }, + { "UTCDate": "2015-11-09", "unixTimeStamp": "1447027200", "value": "1.00" }, + { "UTCDate": "2015-11-10", "unixTimeStamp": "1447113600", "value": "0.92" }, + { "UTCDate": "2015-11-11", "unixTimeStamp": "1447200000", "value": "0.78" }, + { "UTCDate": "2015-11-12", "unixTimeStamp": "1447286400", "value": "0.89" }, + { "UTCDate": "2015-11-13", "unixTimeStamp": "1447372800", "value": "0.89" }, + { "UTCDate": "2015-11-14", "unixTimeStamp": "1447459200", "value": "0.89" }, + { "UTCDate": "2015-11-15", "unixTimeStamp": "1447545600", "value": "0.90" }, + { "UTCDate": "2015-11-16", "unixTimeStamp": "1447632000", "value": "0.94" }, + { "UTCDate": "2015-11-17", "unixTimeStamp": "1447718400", "value": "1.00" }, + { "UTCDate": "2015-11-18", "unixTimeStamp": "1447804800", "value": "0.99" }, + { "UTCDate": "2015-11-19", "unixTimeStamp": "1447891200", "value": "0.95" }, + { "UTCDate": "2015-11-20", "unixTimeStamp": "1447977600", "value": "0.93" }, + { "UTCDate": "2015-11-21", "unixTimeStamp": "1448064000", "value": "0.97" }, + { "UTCDate": "2015-11-22", "unixTimeStamp": "1448150400", "value": "0.96" }, + { "UTCDate": "2015-11-23", "unixTimeStamp": "1448236800", "value": "0.94" }, + { "UTCDate": "2015-11-24", "unixTimeStamp": "1448323200", "value": "0.91" }, + { "UTCDate": "2015-11-25", "unixTimeStamp": "1448409600", "value": "0.86" }, + { "UTCDate": "2015-11-26", "unixTimeStamp": "1448496000", "value": "0.88" }, + { "UTCDate": "2015-11-27", "unixTimeStamp": "1448582400", "value": "0.87" }, + { "UTCDate": "2015-11-28", "unixTimeStamp": "1448668800", "value": "0.91" }, + { "UTCDate": "2015-11-29", "unixTimeStamp": "1448755200", "value": "0.87" }, + { "UTCDate": "2015-11-30", "unixTimeStamp": "1448841600", "value": "0.88" }, + { "UTCDate": "2015-12-01", "unixTimeStamp": "1448928000", "value": "0.87" }, + { "UTCDate": "2015-12-02", "unixTimeStamp": "1449014400", "value": "0.83" }, + { "UTCDate": "2015-12-03", "unixTimeStamp": "1449100800", "value": "0.82" }, + { "UTCDate": "2015-12-04", "unixTimeStamp": "1449187200", "value": "0.84" }, + { "UTCDate": "2015-12-05", "unixTimeStamp": "1449273600", "value": "0.85" }, + { "UTCDate": "2015-12-06", "unixTimeStamp": "1449360000", "value": "0.84" }, + { "UTCDate": "2015-12-07", "unixTimeStamp": "1449446400", "value": "0.80" }, + { "UTCDate": "2015-12-08", "unixTimeStamp": "1449532800", "value": "0.83" }, + { "UTCDate": "2015-12-09", "unixTimeStamp": "1449619200", "value": "0.79" }, + { "UTCDate": "2015-12-10", "unixTimeStamp": "1449705600", "value": "0.84" }, + { "UTCDate": "2015-12-11", "unixTimeStamp": "1449792000", "value": "0.91" }, + { "UTCDate": "2015-12-12", "unixTimeStamp": "1449878400", "value": "0.97" }, + { "UTCDate": "2015-12-13", "unixTimeStamp": "1449964800", "value": "0.96" }, + { "UTCDate": "2015-12-14", "unixTimeStamp": "1450051200", "value": "0.99" }, + { "UTCDate": "2015-12-15", "unixTimeStamp": "1450137600", "value": "1.01" }, + { "UTCDate": "2015-12-16", "unixTimeStamp": "1450224000", "value": "0.99" }, + { "UTCDate": "2015-12-17", "unixTimeStamp": "1450310400", "value": "0.94" }, + { "UTCDate": "2015-12-18", "unixTimeStamp": "1450396800", "value": "0.91" }, + { "UTCDate": "2015-12-19", "unixTimeStamp": "1450483200", "value": "0.90" }, + { "UTCDate": "2015-12-20", "unixTimeStamp": "1450569600", "value": "0.90" }, + { "UTCDate": "2015-12-21", "unixTimeStamp": "1450656000", "value": "0.89" }, + { "UTCDate": "2015-12-22", "unixTimeStamp": "1450742400", "value": "0.87" }, + { "UTCDate": "2015-12-23", "unixTimeStamp": "1450828800", "value": "0.85" }, + { "UTCDate": "2015-12-24", "unixTimeStamp": "1450915200", "value": "0.85" }, + { "UTCDate": "2015-12-25", "unixTimeStamp": "1451001600", "value": "0.87" }, + { "UTCDate": "2015-12-26", "unixTimeStamp": "1451088000", "value": "0.85" }, + { "UTCDate": "2015-12-27", "unixTimeStamp": "1451174400", "value": "0.85" }, + { "UTCDate": "2015-12-28", "unixTimeStamp": "1451260800", "value": "0.84" }, + { "UTCDate": "2015-12-29", "unixTimeStamp": "1451347200", "value": "0.87" }, + { "UTCDate": "2015-12-30", "unixTimeStamp": "1451433600", "value": "0.90" }, + { "UTCDate": "2015-12-31", "unixTimeStamp": "1451520000", "value": "0.93" }, + { "UTCDate": "2016-01-01", "unixTimeStamp": "1451606400", "value": "0.93" }, + { "UTCDate": "2016-01-02", "unixTimeStamp": "1451692800", "value": "0.93" }, + { "UTCDate": "2016-01-03", "unixTimeStamp": "1451779200", "value": "0.97" }, + { "UTCDate": "2016-01-04", "unixTimeStamp": "1451865600", "value": "0.95" }, + { "UTCDate": "2016-01-05", "unixTimeStamp": "1451952000", "value": "0.95" }, + { "UTCDate": "2016-01-06", "unixTimeStamp": "1452038400", "value": "0.96" }, + { "UTCDate": "2016-01-07", "unixTimeStamp": "1452124800", "value": "0.95" }, + { "UTCDate": "2016-01-08", "unixTimeStamp": "1452211200", "value": "0.99" }, + { "UTCDate": "2016-01-09", "unixTimeStamp": "1452297600", "value": "0.99" }, + { "UTCDate": "2016-01-10", "unixTimeStamp": "1452384000", "value": "0.99" }, + { "UTCDate": "2016-01-11", "unixTimeStamp": "1452470400", "value": "1.05" }, + { "UTCDate": "2016-01-12", "unixTimeStamp": "1452556800", "value": "1.23" }, + { "UTCDate": "2016-01-13", "unixTimeStamp": "1452643200", "value": "1.13" }, + { "UTCDate": "2016-01-14", "unixTimeStamp": "1452729600", "value": "1.16" }, + { "UTCDate": "2016-01-15", "unixTimeStamp": "1452816000", "value": "1.22" }, + { "UTCDate": "2016-01-16", "unixTimeStamp": "1452902400", "value": "1.22" }, + { "UTCDate": "2016-01-17", "unixTimeStamp": "1452988800", "value": "1.31" }, + { "UTCDate": "2016-01-18", "unixTimeStamp": "1453075200", "value": "1.47" }, + { "UTCDate": "2016-01-19", "unixTimeStamp": "1453161600", "value": "1.37" }, + { "UTCDate": "2016-01-20", "unixTimeStamp": "1453248000", "value": "1.53" }, + { "UTCDate": "2016-01-21", "unixTimeStamp": "1453334400", "value": "1.54" }, + { "UTCDate": "2016-01-22", "unixTimeStamp": "1453420800", "value": "1.52" }, + { "UTCDate": "2016-01-23", "unixTimeStamp": "1453507200", "value": "2.03" }, + { "UTCDate": "2016-01-24", "unixTimeStamp": "1453593600", "value": "2.10" }, + { "UTCDate": "2016-01-25", "unixTimeStamp": "1453680000", "value": "2.50" }, + { "UTCDate": "2016-01-26", "unixTimeStamp": "1453766400", "value": "2.30" }, + { "UTCDate": "2016-01-27", "unixTimeStamp": "1453852800", "value": "2.42" }, + { "UTCDate": "2016-01-28", "unixTimeStamp": "1453939200", "value": "2.55" }, + { "UTCDate": "2016-01-29", "unixTimeStamp": "1454025600", "value": "2.41" }, + { "UTCDate": "2016-01-30", "unixTimeStamp": "1454112000", "value": "2.43" }, + { "UTCDate": "2016-01-31", "unixTimeStamp": "1454198400", "value": "2.20" }, + { "UTCDate": "2016-02-01", "unixTimeStamp": "1454284800", "value": "2.17" }, + { "UTCDate": "2016-02-02", "unixTimeStamp": "1454371200", "value": "2.45" }, + { "UTCDate": "2016-02-03", "unixTimeStamp": "1454457600", "value": "2.53" }, + { "UTCDate": "2016-02-04", "unixTimeStamp": "1454544000", "value": "2.57" }, + { "UTCDate": "2016-02-05", "unixTimeStamp": "1454630400", "value": "2.57" }, + { "UTCDate": "2016-02-06", "unixTimeStamp": "1454716800", "value": "2.53" }, + { "UTCDate": "2016-02-07", "unixTimeStamp": "1454803200", "value": "3.00" }, + { "UTCDate": "2016-02-08", "unixTimeStamp": "1454889600", "value": "3.16" }, + { "UTCDate": "2016-02-09", "unixTimeStamp": "1454976000", "value": "3.76" }, + { "UTCDate": "2016-02-10", "unixTimeStamp": "1455062400", "value": "4.35" }, + { "UTCDate": "2016-02-11", "unixTimeStamp": "1455148800", "value": "6.38" }, + { "UTCDate": "2016-02-12", "unixTimeStamp": "1455235200", "value": "5.27" }, + { "UTCDate": "2016-02-13", "unixTimeStamp": "1455321600", "value": "5.22" }, + { "UTCDate": "2016-02-14", "unixTimeStamp": "1455408000", "value": "5.20" }, + { "UTCDate": "2016-02-15", "unixTimeStamp": "1455494400", "value": "5.22" }, + { "UTCDate": "2016-02-16", "unixTimeStamp": "1455580800", "value": "4.25" }, + { "UTCDate": "2016-02-17", "unixTimeStamp": "1455667200", "value": "3.86" }, + { "UTCDate": "2016-02-18", "unixTimeStamp": "1455753600", "value": "4.36" }, + { "UTCDate": "2016-02-19", "unixTimeStamp": "1455840000", "value": "4.45" }, + { "UTCDate": "2016-02-20", "unixTimeStamp": "1455926400", "value": "4.37" }, + { "UTCDate": "2016-02-21", "unixTimeStamp": "1456012800", "value": "4.63" }, + { "UTCDate": "2016-02-22", "unixTimeStamp": "1456099200", "value": "5.60" }, + { "UTCDate": "2016-02-23", "unixTimeStamp": "1456185600", "value": "5.70" }, + { "UTCDate": "2016-02-24", "unixTimeStamp": "1456272000", "value": "6.23" }, + { "UTCDate": "2016-02-25", "unixTimeStamp": "1456358400", "value": "5.93" }, + { "UTCDate": "2016-02-26", "unixTimeStamp": "1456444800", "value": "6.03" }, + { "UTCDate": "2016-02-27", "unixTimeStamp": "1456531200", "value": "6.31" }, + { "UTCDate": "2016-02-28", "unixTimeStamp": "1456617600", "value": "6.50" }, + { "UTCDate": "2016-02-29", "unixTimeStamp": "1456704000", "value": "6.35" }, + { "UTCDate": "2016-03-01", "unixTimeStamp": "1456790400", "value": "7.59" }, + { "UTCDate": "2016-03-02", "unixTimeStamp": "1456876800", "value": "8.70" }, + { "UTCDate": "2016-03-03", "unixTimeStamp": "1456963200", "value": "9.35" }, + { "UTCDate": "2016-03-04", "unixTimeStamp": "1457049600", "value": "9.96" }, + { "UTCDate": "2016-03-05", "unixTimeStamp": "1457136000", "value": "11.00" }, + { "UTCDate": "2016-03-06", "unixTimeStamp": "1457222400", "value": "10.98" }, + { "UTCDate": "2016-03-07", "unixTimeStamp": "1457308800", "value": "9.50" }, + { "UTCDate": "2016-03-08", "unixTimeStamp": "1457395200", "value": "9.88" }, + { "UTCDate": "2016-03-09", "unixTimeStamp": "1457481600", "value": "11.55" }, + { "UTCDate": "2016-03-10", "unixTimeStamp": "1457568000", "value": "11.11" }, + { "UTCDate": "2016-03-11", "unixTimeStamp": "1457654400", "value": "11.25" }, + { "UTCDate": "2016-03-12", "unixTimeStamp": "1457740800", "value": "13.25" }, + { "UTCDate": "2016-03-13", "unixTimeStamp": "1457827200", "value": "15.00" }, + { "UTCDate": "2016-03-14", "unixTimeStamp": "1457913600", "value": "12.50" }, + { "UTCDate": "2016-03-15", "unixTimeStamp": "1458000000", "value": "13.09" }, + { "UTCDate": "2016-03-16", "unixTimeStamp": "1458086400", "value": "12.92" }, + { "UTCDate": "2016-03-17", "unixTimeStamp": "1458172800", "value": "11.14" }, + { "UTCDate": "2016-03-18", "unixTimeStamp": "1458259200", "value": "10.75" }, + { "UTCDate": "2016-03-19", "unixTimeStamp": "1458345600", "value": "10.55" }, + { "UTCDate": "2016-03-20", "unixTimeStamp": "1458432000", "value": "10.06" }, + { "UTCDate": "2016-03-21", "unixTimeStamp": "1458518400", "value": "11.97" }, + { "UTCDate": "2016-03-22", "unixTimeStamp": "1458604800", "value": "10.96" }, + { "UTCDate": "2016-03-23", "unixTimeStamp": "1458691200", "value": "12.29" }, + { "UTCDate": "2016-03-24", "unixTimeStamp": "1458777600", "value": "11.13" }, + { "UTCDate": "2016-03-25", "unixTimeStamp": "1458864000", "value": "10.69" }, + { "UTCDate": "2016-03-26", "unixTimeStamp": "1458950400", "value": "11.00" }, + { "UTCDate": "2016-03-27", "unixTimeStamp": "1459036800", "value": "10.50" }, + { "UTCDate": "2016-03-28", "unixTimeStamp": "1459123200", "value": "11.58" }, + { "UTCDate": "2016-03-29", "unixTimeStamp": "1459209600", "value": "11.73" }, + { "UTCDate": "2016-03-30", "unixTimeStamp": "1459296000", "value": "11.88" }, + { "UTCDate": "2016-03-31", "unixTimeStamp": "1459382400", "value": "11.41" }, + { "UTCDate": "2016-04-01", "unixTimeStamp": "1459468800", "value": "11.63" }, + { "UTCDate": "2016-04-02", "unixTimeStamp": "1459555200", "value": "11.61" }, + { "UTCDate": "2016-04-03", "unixTimeStamp": "1459641600", "value": "11.58" }, + { "UTCDate": "2016-04-04", "unixTimeStamp": "1459728000", "value": "11.10" }, + { "UTCDate": "2016-04-05", "unixTimeStamp": "1459814400", "value": "10.39" }, + { "UTCDate": "2016-04-06", "unixTimeStamp": "1459900800", "value": "10.79" }, + { "UTCDate": "2016-04-07", "unixTimeStamp": "1459987200", "value": "10.08" }, + { "UTCDate": "2016-04-08", "unixTimeStamp": "1460073600", "value": "9.74" }, + { "UTCDate": "2016-04-09", "unixTimeStamp": "1460160000", "value": "9.16" }, + { "UTCDate": "2016-04-10", "unixTimeStamp": "1460246400", "value": "8.80" }, + { "UTCDate": "2016-04-11", "unixTimeStamp": "1460332800", "value": "8.72" }, + { "UTCDate": "2016-04-12", "unixTimeStamp": "1460419200", "value": "7.54" }, + { "UTCDate": "2016-04-13", "unixTimeStamp": "1460505600", "value": "8.02" }, + { "UTCDate": "2016-04-14", "unixTimeStamp": "1460592000", "value": "8.48" }, + { "UTCDate": "2016-04-15", "unixTimeStamp": "1460678400", "value": "8.22" }, + { "UTCDate": "2016-04-16", "unixTimeStamp": "1460764800", "value": "8.48" }, + { "UTCDate": "2016-04-17", "unixTimeStamp": "1460851200", "value": "9.45" }, + { "UTCDate": "2016-04-18", "unixTimeStamp": "1460937600", "value": "8.92" }, + { "UTCDate": "2016-04-19", "unixTimeStamp": "1461024000", "value": "8.77" }, + { "UTCDate": "2016-04-20", "unixTimeStamp": "1461110400", "value": "8.54" }, + { "UTCDate": "2016-04-21", "unixTimeStamp": "1461196800", "value": "8.16" }, + { "UTCDate": "2016-04-22", "unixTimeStamp": "1461283200", "value": "7.83" }, + { "UTCDate": "2016-04-23", "unixTimeStamp": "1461369600", "value": "8.31" }, + { "UTCDate": "2016-04-24", "unixTimeStamp": "1461456000", "value": "8.00" }, + { "UTCDate": "2016-04-25", "unixTimeStamp": "1461542400", "value": "7.43" }, + { "UTCDate": "2016-04-26", "unixTimeStamp": "1461628800", "value": "7.50" }, + { "UTCDate": "2016-04-27", "unixTimeStamp": "1461715200", "value": "7.77" }, + { "UTCDate": "2016-04-28", "unixTimeStamp": "1461801600", "value": "7.30" }, + { "UTCDate": "2016-04-29", "unixTimeStamp": "1461888000", "value": "7.52" }, + { "UTCDate": "2016-04-30", "unixTimeStamp": "1461974400", "value": "8.83" }, + { "UTCDate": "2016-05-01", "unixTimeStamp": "1462060800", "value": "8.76" }, + { "UTCDate": "2016-05-02", "unixTimeStamp": "1462147200", "value": "10.03" }, + { "UTCDate": "2016-05-03", "unixTimeStamp": "1462233600", "value": "9.37" }, + { "UTCDate": "2016-05-04", "unixTimeStamp": "1462320000", "value": "9.43" }, + { "UTCDate": "2016-05-05", "unixTimeStamp": "1462406400", "value": "9.79" }, + { "UTCDate": "2016-05-06", "unixTimeStamp": "1462492800", "value": "9.27" }, + { "UTCDate": "2016-05-07", "unixTimeStamp": "1462579200", "value": "9.30" }, + { "UTCDate": "2016-05-08", "unixTimeStamp": "1462665600", "value": "9.44" }, + { "UTCDate": "2016-05-09", "unixTimeStamp": "1462752000", "value": "9.32" }, + { "UTCDate": "2016-05-10", "unixTimeStamp": "1462838400", "value": "9.39" }, + { "UTCDate": "2016-05-11", "unixTimeStamp": "1462924800", "value": "9.97" }, + { "UTCDate": "2016-05-12", "unixTimeStamp": "1463011200", "value": "10.10" }, + { "UTCDate": "2016-05-13", "unixTimeStamp": "1463097600", "value": "10.48" }, + { "UTCDate": "2016-05-14", "unixTimeStamp": "1463184000", "value": "10.14" }, + { "UTCDate": "2016-05-15", "unixTimeStamp": "1463270400", "value": "9.94" }, + { "UTCDate": "2016-05-16", "unixTimeStamp": "1463356800", "value": "11.04" }, + { "UTCDate": "2016-05-17", "unixTimeStamp": "1463443200", "value": "12.26" }, + { "UTCDate": "2016-05-18", "unixTimeStamp": "1463529600", "value": "13.29" }, + { "UTCDate": "2016-05-19", "unixTimeStamp": "1463616000", "value": "14.49" }, + { "UTCDate": "2016-05-20", "unixTimeStamp": "1463702400", "value": "13.73" }, + { "UTCDate": "2016-05-21", "unixTimeStamp": "1463788800", "value": "13.95" }, + { "UTCDate": "2016-05-22", "unixTimeStamp": "1463875200", "value": "14.21" }, + { "UTCDate": "2016-05-23", "unixTimeStamp": "1463961600", "value": "13.45" }, + { "UTCDate": "2016-05-24", "unixTimeStamp": "1464048000", "value": "12.62" }, + { "UTCDate": "2016-05-25", "unixTimeStamp": "1464134400", "value": "12.53" }, + { "UTCDate": "2016-05-26", "unixTimeStamp": "1464220800", "value": "12.37" }, + { "UTCDate": "2016-05-27", "unixTimeStamp": "1464307200", "value": "11.11" }, + { "UTCDate": "2016-05-28", "unixTimeStamp": "1464393600", "value": "11.56" }, + { "UTCDate": "2016-05-29", "unixTimeStamp": "1464480000", "value": "12.28" }, + { "UTCDate": "2016-05-30", "unixTimeStamp": "1464566400", "value": "12.48" }, + { "UTCDate": "2016-05-31", "unixTimeStamp": "1464652800", "value": "13.85" }, + { "UTCDate": "2016-06-01", "unixTimeStamp": "1464739200", "value": "13.83" }, + { "UTCDate": "2016-06-02", "unixTimeStamp": "1464825600", "value": "13.78" }, + { "UTCDate": "2016-06-03", "unixTimeStamp": "1464912000", "value": "13.78" }, + { "UTCDate": "2016-06-04", "unixTimeStamp": "1464998400", "value": "13.66" }, + { "UTCDate": "2016-06-05", "unixTimeStamp": "1465084800", "value": "13.85" }, + { "UTCDate": "2016-06-06", "unixTimeStamp": "1465171200", "value": "13.96" }, + { "UTCDate": "2016-06-07", "unixTimeStamp": "1465257600", "value": "14.41" }, + { "UTCDate": "2016-06-08", "unixTimeStamp": "1465344000", "value": "14.44" }, + { "UTCDate": "2016-06-09", "unixTimeStamp": "1465430400", "value": "14.49" }, + { "UTCDate": "2016-06-10", "unixTimeStamp": "1465516800", "value": "13.97" }, + { "UTCDate": "2016-06-11", "unixTimeStamp": "1465603200", "value": "14.01" }, + { "UTCDate": "2016-06-12", "unixTimeStamp": "1465689600", "value": "15.57" }, + { "UTCDate": "2016-06-13", "unixTimeStamp": "1465776000", "value": "17.55" }, + { "UTCDate": "2016-06-14", "unixTimeStamp": "1465862400", "value": "18.70" }, + { "UTCDate": "2016-06-15", "unixTimeStamp": "1465948800", "value": "18.30" }, + { "UTCDate": "2016-06-16", "unixTimeStamp": "1466035200", "value": "20.61" }, + { "UTCDate": "2016-06-17", "unixTimeStamp": "1466121600", "value": "15.49" }, + { "UTCDate": "2016-06-18", "unixTimeStamp": "1466208000", "value": "11.36" }, + { "UTCDate": "2016-06-19", "unixTimeStamp": "1466294400", "value": "12.33" }, + { "UTCDate": "2016-06-20", "unixTimeStamp": "1466380800", "value": "11.70" }, + { "UTCDate": "2016-06-21", "unixTimeStamp": "1466467200", "value": "12.71" }, + { "UTCDate": "2016-06-22", "unixTimeStamp": "1466553600", "value": "13.21" }, + { "UTCDate": "2016-06-23", "unixTimeStamp": "1466640000", "value": "13.58" }, + { "UTCDate": "2016-06-24", "unixTimeStamp": "1466726400", "value": "14.25" }, + { "UTCDate": "2016-06-25", "unixTimeStamp": "1466812800", "value": "14.28" }, + { "UTCDate": "2016-06-26", "unixTimeStamp": "1466899200", "value": "13.82" }, + { "UTCDate": "2016-06-27", "unixTimeStamp": "1466985600", "value": "14.04" }, + { "UTCDate": "2016-06-28", "unixTimeStamp": "1467072000", "value": "12.15" }, + { "UTCDate": "2016-06-29", "unixTimeStamp": "1467158400", "value": "12.76" }, + { "UTCDate": "2016-06-30", "unixTimeStamp": "1467244800", "value": "12.40" }, + { "UTCDate": "2016-07-01", "unixTimeStamp": "1467331200", "value": "12.23" }, + { "UTCDate": "2016-07-02", "unixTimeStamp": "1467417600", "value": "12.04" }, + { "UTCDate": "2016-07-03", "unixTimeStamp": "1467504000", "value": "11.85" }, + { "UTCDate": "2016-07-04", "unixTimeStamp": "1467590400", "value": "11.34" }, + { "UTCDate": "2016-07-05", "unixTimeStamp": "1467676800", "value": "10.45" }, + { "UTCDate": "2016-07-06", "unixTimeStamp": "1467763200", "value": "10.51" }, + { "UTCDate": "2016-07-07", "unixTimeStamp": "1467849600", "value": "10.07" }, + { "UTCDate": "2016-07-08", "unixTimeStamp": "1467936000", "value": "11.30" }, + { "UTCDate": "2016-07-09", "unixTimeStamp": "1468022400", "value": "10.92" }, + { "UTCDate": "2016-07-10", "unixTimeStamp": "1468108800", "value": "10.97" }, + { "UTCDate": "2016-07-11", "unixTimeStamp": "1468195200", "value": "10.58" }, + { "UTCDate": "2016-07-12", "unixTimeStamp": "1468281600", "value": "10.54" }, + { "UTCDate": "2016-07-13", "unixTimeStamp": "1468368000", "value": "10.44" }, + { "UTCDate": "2016-07-14", "unixTimeStamp": "1468454400", "value": "11.55" }, + { "UTCDate": "2016-07-15", "unixTimeStamp": "1468540800", "value": "11.88" }, + { "UTCDate": "2016-07-16", "unixTimeStamp": "1468627200", "value": "11.59" }, + { "UTCDate": "2016-07-17", "unixTimeStamp": "1468713600", "value": "11.19" }, + { "UTCDate": "2016-07-18", "unixTimeStamp": "1468800000", "value": "11.03" }, + { "UTCDate": "2016-07-19", "unixTimeStamp": "1468886400", "value": "11.63" }, + { "UTCDate": "2016-07-20", "unixTimeStamp": "1468972800", "value": "12.54" }, + { "UTCDate": "2016-07-21", "unixTimeStamp": "1469059200", "value": "12.66" }, + { "UTCDate": "2016-07-22", "unixTimeStamp": "1469145600", "value": "14.82" }, + { "UTCDate": "2016-07-23", "unixTimeStamp": "1469232000", "value": "14.40" }, + { "UTCDate": "2016-07-24", "unixTimeStamp": "1469318400", "value": "12.63" }, + { "UTCDate": "2016-07-25", "unixTimeStamp": "1469404800", "value": "13.84" }, + { "UTCDate": "2016-07-26", "unixTimeStamp": "1469491200", "value": "12.08" }, + { "UTCDate": "2016-07-27", "unixTimeStamp": "1469577600", "value": "13.05" }, + { "UTCDate": "2016-07-28", "unixTimeStamp": "1469664000", "value": "12.87" }, + { "UTCDate": "2016-07-29", "unixTimeStamp": "1469750400", "value": "12.87" }, + { "UTCDate": "2016-07-30", "unixTimeStamp": "1469836800", "value": "12.57" }, + { "UTCDate": "2016-07-31", "unixTimeStamp": "1469923200", "value": "11.86" }, + { "UTCDate": "2016-08-01", "unixTimeStamp": "1470009600", "value": "11.04" }, + { "UTCDate": "2016-08-02", "unixTimeStamp": "1470096000", "value": "8.30" }, + { "UTCDate": "2016-08-03", "unixTimeStamp": "1470182400", "value": "10.42" }, + { "UTCDate": "2016-08-04", "unixTimeStamp": "1470268800", "value": "11.21" }, + { "UTCDate": "2016-08-05", "unixTimeStamp": "1470355200", "value": "11.05" }, + { "UTCDate": "2016-08-06", "unixTimeStamp": "1470441600", "value": "10.95" }, + { "UTCDate": "2016-08-07", "unixTimeStamp": "1470528000", "value": "10.98" }, + { "UTCDate": "2016-08-08", "unixTimeStamp": "1470614400", "value": "11.29" }, + { "UTCDate": "2016-08-09", "unixTimeStamp": "1470700800", "value": "12.22" }, + { "UTCDate": "2016-08-10", "unixTimeStamp": "1470787200", "value": "12.22" }, + { "UTCDate": "2016-08-11", "unixTimeStamp": "1470873600", "value": "11.68" }, + { "UTCDate": "2016-08-12", "unixTimeStamp": "1470960000", "value": "11.78" }, + { "UTCDate": "2016-08-13", "unixTimeStamp": "1471046400", "value": "11.56" }, + { "UTCDate": "2016-08-14", "unixTimeStamp": "1471132800", "value": "11.21" }, + { "UTCDate": "2016-08-15", "unixTimeStamp": "1471219200", "value": "11.21" }, + { "UTCDate": "2016-08-16", "unixTimeStamp": "1471305600", "value": "11.17" }, + { "UTCDate": "2016-08-17", "unixTimeStamp": "1471392000", "value": "10.77" }, + { "UTCDate": "2016-08-18", "unixTimeStamp": "1471478400", "value": "10.77" }, + { "UTCDate": "2016-08-19", "unixTimeStamp": "1471564800", "value": "10.71" }, + { "UTCDate": "2016-08-20", "unixTimeStamp": "1471651200", "value": "11.28" }, + { "UTCDate": "2016-08-21", "unixTimeStamp": "1471737600", "value": "11.14" }, + { "UTCDate": "2016-08-22", "unixTimeStamp": "1471824000", "value": "11.07" }, + { "UTCDate": "2016-08-23", "unixTimeStamp": "1471910400", "value": "11.01" }, + { "UTCDate": "2016-08-24", "unixTimeStamp": "1471996800", "value": "11.01" }, + { "UTCDate": "2016-08-25", "unixTimeStamp": "1472083200", "value": "11.35" }, + { "UTCDate": "2016-08-26", "unixTimeStamp": "1472169600", "value": "11.26" }, + { "UTCDate": "2016-08-27", "unixTimeStamp": "1472256000", "value": "11.19" }, + { "UTCDate": "2016-08-28", "unixTimeStamp": "1472342400", "value": "10.99" }, + { "UTCDate": "2016-08-29", "unixTimeStamp": "1472428800", "value": "10.95" }, + { "UTCDate": "2016-08-30", "unixTimeStamp": "1472515200", "value": "11.21" }, + { "UTCDate": "2016-08-31", "unixTimeStamp": "1472601600", "value": "11.55" }, + { "UTCDate": "2016-09-01", "unixTimeStamp": "1472688000", "value": "12.21" }, + { "UTCDate": "2016-09-02", "unixTimeStamp": "1472774400", "value": "12.08" }, + { "UTCDate": "2016-09-03", "unixTimeStamp": "1472860800", "value": "11.85" }, + { "UTCDate": "2016-09-04", "unixTimeStamp": "1472947200", "value": "11.71" }, + { "UTCDate": "2016-09-05", "unixTimeStamp": "1473033600", "value": "11.75" }, + { "UTCDate": "2016-09-06", "unixTimeStamp": "1473120000", "value": "11.70" }, + { "UTCDate": "2016-09-07", "unixTimeStamp": "1473206400", "value": "11.59" }, + { "UTCDate": "2016-09-08", "unixTimeStamp": "1473292800", "value": "11.39" }, + { "UTCDate": "2016-09-09", "unixTimeStamp": "1473379200", "value": "11.72" }, + { "UTCDate": "2016-09-10", "unixTimeStamp": "1473465600", "value": "12.05" }, + { "UTCDate": "2016-09-11", "unixTimeStamp": "1473552000", "value": "11.64" }, + { "UTCDate": "2016-09-12", "unixTimeStamp": "1473638400", "value": "11.89" }, + { "UTCDate": "2016-09-13", "unixTimeStamp": "1473724800", "value": "11.92" }, + { "UTCDate": "2016-09-14", "unixTimeStamp": "1473811200", "value": "11.97" }, + { "UTCDate": "2016-09-15", "unixTimeStamp": "1473897600", "value": "11.96" }, + { "UTCDate": "2016-09-16", "unixTimeStamp": "1473984000", "value": "12.61" }, + { "UTCDate": "2016-09-17", "unixTimeStamp": "1474070400", "value": "12.83" }, + { "UTCDate": "2016-09-18", "unixTimeStamp": "1474156800", "value": "12.39" }, + { "UTCDate": "2016-09-19", "unixTimeStamp": "1474243200", "value": "12.93" }, + { "UTCDate": "2016-09-20", "unixTimeStamp": "1474329600", "value": "14.72" }, + { "UTCDate": "2016-09-21", "unixTimeStamp": "1474416000", "value": "13.72" }, + { "UTCDate": "2016-09-22", "unixTimeStamp": "1474502400", "value": "13.11" }, + { "UTCDate": "2016-09-23", "unixTimeStamp": "1474588800", "value": "13.36" }, + { "UTCDate": "2016-09-24", "unixTimeStamp": "1474675200", "value": "12.91" }, + { "UTCDate": "2016-09-25", "unixTimeStamp": "1474761600", "value": "13.05" }, + { "UTCDate": "2016-09-26", "unixTimeStamp": "1474848000", "value": "12.89" }, + { "UTCDate": "2016-09-27", "unixTimeStamp": "1474934400", "value": "13.09" }, + { "UTCDate": "2016-09-28", "unixTimeStamp": "1475020800", "value": "13.30" }, + { "UTCDate": "2016-09-29", "unixTimeStamp": "1475107200", "value": "13.17" }, + { "UTCDate": "2016-09-30", "unixTimeStamp": "1475193600", "value": "13.24" }, + { "UTCDate": "2016-10-01", "unixTimeStamp": "1475280000", "value": "13.21" }, + { "UTCDate": "2016-10-02", "unixTimeStamp": "1475366400", "value": "13.23" }, + { "UTCDate": "2016-10-03", "unixTimeStamp": "1475452800", "value": "13.45" }, + { "UTCDate": "2016-10-04", "unixTimeStamp": "1475539200", "value": "13.32" }, + { "UTCDate": "2016-10-05", "unixTimeStamp": "1475625600", "value": "13.09" }, + { "UTCDate": "2016-10-06", "unixTimeStamp": "1475712000", "value": "12.87" }, + { "UTCDate": "2016-10-07", "unixTimeStamp": "1475798400", "value": "12.68" }, + { "UTCDate": "2016-10-08", "unixTimeStamp": "1475884800", "value": "12.24" }, + { "UTCDate": "2016-10-09", "unixTimeStamp": "1475971200", "value": "12.06" }, + { "UTCDate": "2016-10-10", "unixTimeStamp": "1476057600", "value": "11.74" }, + { "UTCDate": "2016-10-11", "unixTimeStamp": "1476144000", "value": "11.75" }, + { "UTCDate": "2016-10-12", "unixTimeStamp": "1476230400", "value": "11.77" }, + { "UTCDate": "2016-10-13", "unixTimeStamp": "1476316800", "value": "12.02" }, + { "UTCDate": "2016-10-14", "unixTimeStamp": "1476403200", "value": "11.90" }, + { "UTCDate": "2016-10-15", "unixTimeStamp": "1476489600", "value": "11.96" }, + { "UTCDate": "2016-10-16", "unixTimeStamp": "1476576000", "value": "11.93" }, + { "UTCDate": "2016-10-17", "unixTimeStamp": "1476662400", "value": "11.98" }, + { "UTCDate": "2016-10-18", "unixTimeStamp": "1476748800", "value": "12.50" }, + { "UTCDate": "2016-10-19", "unixTimeStamp": "1476835200", "value": "11.98" }, + { "UTCDate": "2016-10-20", "unixTimeStamp": "1476921600", "value": "12.05" }, + { "UTCDate": "2016-10-21", "unixTimeStamp": "1477008000", "value": "12.07" }, + { "UTCDate": "2016-10-22", "unixTimeStamp": "1477094400", "value": "12.06" }, + { "UTCDate": "2016-10-23", "unixTimeStamp": "1477180800", "value": "11.95" }, + { "UTCDate": "2016-10-24", "unixTimeStamp": "1477267200", "value": "11.93" }, + { "UTCDate": "2016-10-25", "unixTimeStamp": "1477353600", "value": "11.38" }, + { "UTCDate": "2016-10-26", "unixTimeStamp": "1477440000", "value": "11.50" }, + { "UTCDate": "2016-10-27", "unixTimeStamp": "1477526400", "value": "11.43" }, + { "UTCDate": "2016-10-28", "unixTimeStamp": "1477612800", "value": "11.08" }, + { "UTCDate": "2016-10-29", "unixTimeStamp": "1477699200", "value": "10.39" }, + { "UTCDate": "2016-10-30", "unixTimeStamp": "1477785600", "value": "11.22" }, + { "UTCDate": "2016-10-31", "unixTimeStamp": "1477872000", "value": "10.91" }, + { "UTCDate": "2016-11-01", "unixTimeStamp": "1477958400", "value": "10.75" }, + { "UTCDate": "2016-11-02", "unixTimeStamp": "1478044800", "value": "10.82" }, + { "UTCDate": "2016-11-03", "unixTimeStamp": "1478131200", "value": "10.86" }, + { "UTCDate": "2016-11-04", "unixTimeStamp": "1478217600", "value": "11.13" }, + { "UTCDate": "2016-11-05", "unixTimeStamp": "1478304000", "value": "11.11" }, + { "UTCDate": "2016-11-06", "unixTimeStamp": "1478390400", "value": "10.97" }, + { "UTCDate": "2016-11-07", "unixTimeStamp": "1478476800", "value": "10.90" }, + { "UTCDate": "2016-11-08", "unixTimeStamp": "1478563200", "value": "10.86" }, + { "UTCDate": "2016-11-09", "unixTimeStamp": "1478649600", "value": "10.64" }, + { "UTCDate": "2016-11-10", "unixTimeStamp": "1478736000", "value": "10.52" }, + { "UTCDate": "2016-11-11", "unixTimeStamp": "1478822400", "value": "10.29" }, + { "UTCDate": "2016-11-12", "unixTimeStamp": "1478908800", "value": "9.96" }, + { "UTCDate": "2016-11-13", "unixTimeStamp": "1478995200", "value": "10.13" }, + { "UTCDate": "2016-11-14", "unixTimeStamp": "1479081600", "value": "10.00" }, + { "UTCDate": "2016-11-15", "unixTimeStamp": "1479168000", "value": "10.22" }, + { "UTCDate": "2016-11-16", "unixTimeStamp": "1479254400", "value": "10.01" }, + { "UTCDate": "2016-11-17", "unixTimeStamp": "1479340800", "value": "9.95" }, + { "UTCDate": "2016-11-18", "unixTimeStamp": "1479427200", "value": "9.53" }, + { "UTCDate": "2016-11-19", "unixTimeStamp": "1479513600", "value": "9.70" }, + { "UTCDate": "2016-11-20", "unixTimeStamp": "1479600000", "value": "9.57" }, + { "UTCDate": "2016-11-21", "unixTimeStamp": "1479686400", "value": "9.56" }, + { "UTCDate": "2016-11-22", "unixTimeStamp": "1479772800", "value": "9.84" }, + { "UTCDate": "2016-11-23", "unixTimeStamp": "1479859200", "value": "9.78" }, + { "UTCDate": "2016-11-24", "unixTimeStamp": "1479945600", "value": "9.22" }, + { "UTCDate": "2016-11-25", "unixTimeStamp": "1480032000", "value": "9.39" }, + { "UTCDate": "2016-11-26", "unixTimeStamp": "1480118400", "value": "9.34" }, + { "UTCDate": "2016-11-27", "unixTimeStamp": "1480204800", "value": "8.91" }, + { "UTCDate": "2016-11-28", "unixTimeStamp": "1480291200", "value": "8.67" }, + { "UTCDate": "2016-11-29", "unixTimeStamp": "1480377600", "value": "8.18" }, + { "UTCDate": "2016-11-30", "unixTimeStamp": "1480464000", "value": "8.59" }, + { "UTCDate": "2016-12-01", "unixTimeStamp": "1480550400", "value": "8.44" }, + { "UTCDate": "2016-12-02", "unixTimeStamp": "1480636800", "value": "7.65" }, + { "UTCDate": "2016-12-03", "unixTimeStamp": "1480723200", "value": "7.90" }, + { "UTCDate": "2016-12-04", "unixTimeStamp": "1480809600", "value": "7.54" }, + { "UTCDate": "2016-12-05", "unixTimeStamp": "1480896000", "value": "6.69" }, + { "UTCDate": "2016-12-06", "unixTimeStamp": "1480982400", "value": "7.61" }, + { "UTCDate": "2016-12-07", "unixTimeStamp": "1481068800", "value": "8.35" }, + { "UTCDate": "2016-12-08", "unixTimeStamp": "1481155200", "value": "8.30" }, + { "UTCDate": "2016-12-09", "unixTimeStamp": "1481241600", "value": "8.52" }, + { "UTCDate": "2016-12-10", "unixTimeStamp": "1481328000", "value": "8.09" }, + { "UTCDate": "2016-12-11", "unixTimeStamp": "1481414400", "value": "8.20" }, + { "UTCDate": "2016-12-12", "unixTimeStamp": "1481500800", "value": "8.45" }, + { "UTCDate": "2016-12-13", "unixTimeStamp": "1481587200", "value": "8.40" }, + { "UTCDate": "2016-12-14", "unixTimeStamp": "1481673600", "value": "8.23" }, + { "UTCDate": "2016-12-15", "unixTimeStamp": "1481760000", "value": "7.76" }, + { "UTCDate": "2016-12-16", "unixTimeStamp": "1481846400", "value": "7.85" }, + { "UTCDate": "2016-12-17", "unixTimeStamp": "1481932800", "value": "7.66" }, + { "UTCDate": "2016-12-18", "unixTimeStamp": "1482019200", "value": "7.89" }, + { "UTCDate": "2016-12-19", "unixTimeStamp": "1482105600", "value": "7.61" }, + { "UTCDate": "2016-12-20", "unixTimeStamp": "1482192000", "value": "7.59" }, + { "UTCDate": "2016-12-21", "unixTimeStamp": "1482278400", "value": "7.87" }, + { "UTCDate": "2016-12-22", "unixTimeStamp": "1482364800", "value": "7.64" }, + { "UTCDate": "2016-12-23", "unixTimeStamp": "1482451200", "value": "7.16" }, + { "UTCDate": "2016-12-24", "unixTimeStamp": "1482537600", "value": "7.23" }, + { "UTCDate": "2016-12-25", "unixTimeStamp": "1482624000", "value": "7.19" }, + { "UTCDate": "2016-12-26", "unixTimeStamp": "1482710400", "value": "7.21" }, + { "UTCDate": "2016-12-27", "unixTimeStamp": "1482796800", "value": "7.15" }, + { "UTCDate": "2016-12-28", "unixTimeStamp": "1482883200", "value": "7.57" }, + { "UTCDate": "2016-12-29", "unixTimeStamp": "1482969600", "value": "8.21" }, + { "UTCDate": "2016-12-30", "unixTimeStamp": "1483056000", "value": "8.16" }, + { "UTCDate": "2016-12-31", "unixTimeStamp": "1483142400", "value": "8.05" }, + { "UTCDate": "2017-01-01", "unixTimeStamp": "1483228800", "value": "8.14" }, + { "UTCDate": "2017-01-02", "unixTimeStamp": "1483315200", "value": "8.34" }, + { "UTCDate": "2017-01-03", "unixTimeStamp": "1483401600", "value": "9.60" }, + { "UTCDate": "2017-01-04", "unixTimeStamp": "1483488000", "value": "10.88" }, + { "UTCDate": "2017-01-05", "unixTimeStamp": "1483574400", "value": "10.20" }, + { "UTCDate": "2017-01-06", "unixTimeStamp": "1483660800", "value": "10.07" }, + { "UTCDate": "2017-01-07", "unixTimeStamp": "1483747200", "value": "9.79" }, + { "UTCDate": "2017-01-08", "unixTimeStamp": "1483833600", "value": "10.27" }, + { "UTCDate": "2017-01-09", "unixTimeStamp": "1483920000", "value": "10.20" }, + { "UTCDate": "2017-01-10", "unixTimeStamp": "1484006400", "value": "10.55" }, + { "UTCDate": "2017-01-11", "unixTimeStamp": "1484092800", "value": "9.83" }, + { "UTCDate": "2017-01-12", "unixTimeStamp": "1484179200", "value": "9.81" }, + { "UTCDate": "2017-01-13", "unixTimeStamp": "1484265600", "value": "9.78" }, + { "UTCDate": "2017-01-14", "unixTimeStamp": "1484352000", "value": "9.78" }, + { "UTCDate": "2017-01-15", "unixTimeStamp": "1484438400", "value": "9.88" }, + { "UTCDate": "2017-01-16", "unixTimeStamp": "1484524800", "value": "9.59" }, + { "UTCDate": "2017-01-17", "unixTimeStamp": "1484611200", "value": "10.14" }, + { "UTCDate": "2017-01-18", "unixTimeStamp": "1484697600", "value": "10.19" }, + { "UTCDate": "2017-01-19", "unixTimeStamp": "1484784000", "value": "10.43" }, + { "UTCDate": "2017-01-20", "unixTimeStamp": "1484870400", "value": "10.60" }, + { "UTCDate": "2017-01-21", "unixTimeStamp": "1484956800", "value": "10.91" }, + { "UTCDate": "2017-01-22", "unixTimeStamp": "1485043200", "value": "10.71" }, + { "UTCDate": "2017-01-23", "unixTimeStamp": "1485129600", "value": "10.78" }, + { "UTCDate": "2017-01-24", "unixTimeStamp": "1485216000", "value": "10.51" }, + { "UTCDate": "2017-01-25", "unixTimeStamp": "1485302400", "value": "10.51" }, + { "UTCDate": "2017-01-26", "unixTimeStamp": "1485388800", "value": "10.65" }, + { "UTCDate": "2017-01-27", "unixTimeStamp": "1485475200", "value": "10.51" }, + { "UTCDate": "2017-01-28", "unixTimeStamp": "1485561600", "value": "10.54" }, + { "UTCDate": "2017-01-29", "unixTimeStamp": "1485648000", "value": "10.47" }, + { "UTCDate": "2017-01-30", "unixTimeStamp": "1485734400", "value": "10.62" }, + { "UTCDate": "2017-01-31", "unixTimeStamp": "1485820800", "value": "10.71" }, + { "UTCDate": "2017-02-01", "unixTimeStamp": "1485907200", "value": "10.71" }, + { "UTCDate": "2017-02-02", "unixTimeStamp": "1485993600", "value": "10.78" }, + { "UTCDate": "2017-02-03", "unixTimeStamp": "1486080000", "value": "10.95" }, + { "UTCDate": "2017-02-04", "unixTimeStamp": "1486166400", "value": "11.32" }, + { "UTCDate": "2017-02-05", "unixTimeStamp": "1486252800", "value": "11.22" }, + { "UTCDate": "2017-02-06", "unixTimeStamp": "1486339200", "value": "11.32" }, + { "UTCDate": "2017-02-07", "unixTimeStamp": "1486425600", "value": "11.45" }, + { "UTCDate": "2017-02-08", "unixTimeStamp": "1486512000", "value": "11.39" }, + { "UTCDate": "2017-02-09", "unixTimeStamp": "1486598400", "value": "10.94" }, + { "UTCDate": "2017-02-10", "unixTimeStamp": "1486684800", "value": "11.34" }, + { "UTCDate": "2017-02-11", "unixTimeStamp": "1486771200", "value": "11.43" }, + { "UTCDate": "2017-02-12", "unixTimeStamp": "1486857600", "value": "11.42" }, + { "UTCDate": "2017-02-13", "unixTimeStamp": "1486944000", "value": "11.39" }, + { "UTCDate": "2017-02-14", "unixTimeStamp": "1487030400", "value": "13.00" }, + { "UTCDate": "2017-02-15", "unixTimeStamp": "1487116800", "value": "12.97" }, + { "UTCDate": "2017-02-16", "unixTimeStamp": "1487203200", "value": "12.95" }, + { "UTCDate": "2017-02-17", "unixTimeStamp": "1487289600", "value": "12.72" }, + { "UTCDate": "2017-02-18", "unixTimeStamp": "1487376000", "value": "12.83" }, + { "UTCDate": "2017-02-19", "unixTimeStamp": "1487462400", "value": "12.82" }, + { "UTCDate": "2017-02-20", "unixTimeStamp": "1487548800", "value": "12.52" }, + { "UTCDate": "2017-02-21", "unixTimeStamp": "1487635200", "value": "12.77" }, + { "UTCDate": "2017-02-22", "unixTimeStamp": "1487721600", "value": "12.69" }, + { "UTCDate": "2017-02-23", "unixTimeStamp": "1487808000", "value": "13.13" }, + { "UTCDate": "2017-02-24", "unixTimeStamp": "1487894400", "value": "13.11" }, + { "UTCDate": "2017-02-25", "unixTimeStamp": "1487980800", "value": "13.57" }, + { "UTCDate": "2017-02-26", "unixTimeStamp": "1488067200", "value": "14.59" }, + { "UTCDate": "2017-02-27", "unixTimeStamp": "1488153600", "value": "15.55" }, + { "UTCDate": "2017-02-28", "unixTimeStamp": "1488240000", "value": "16.07" }, + { "UTCDate": "2017-03-01", "unixTimeStamp": "1488326400", "value": "17.55" }, + { "UTCDate": "2017-03-02", "unixTimeStamp": "1488412800", "value": "19.08" }, + { "UTCDate": "2017-03-03", "unixTimeStamp": "1488499200", "value": "19.48" }, + { "UTCDate": "2017-03-04", "unixTimeStamp": "1488585600", "value": "18.61" }, + { "UTCDate": "2017-03-05", "unixTimeStamp": "1488672000", "value": "19.22" }, + { "UTCDate": "2017-03-06", "unixTimeStamp": "1488758400", "value": "19.75" }, + { "UTCDate": "2017-03-07", "unixTimeStamp": "1488844800", "value": "18.91" }, + { "UTCDate": "2017-03-08", "unixTimeStamp": "1488931200", "value": "16.54" }, + { "UTCDate": "2017-03-09", "unixTimeStamp": "1489017600", "value": "17.71" }, + { "UTCDate": "2017-03-10", "unixTimeStamp": "1489104000", "value": "19.13" }, + { "UTCDate": "2017-03-11", "unixTimeStamp": "1489190400", "value": "21.45" }, + { "UTCDate": "2017-03-12", "unixTimeStamp": "1489276800", "value": "23.31" }, + { "UTCDate": "2017-03-13", "unixTimeStamp": "1489363200", "value": "28.45" }, + { "UTCDate": "2017-03-14", "unixTimeStamp": "1489449600", "value": "28.58" }, + { "UTCDate": "2017-03-15", "unixTimeStamp": "1489536000", "value": "35.18" }, + { "UTCDate": "2017-03-16", "unixTimeStamp": "1489622400", "value": "45.51" }, + { "UTCDate": "2017-03-17", "unixTimeStamp": "1489708800", "value": "44.48" }, + { "UTCDate": "2017-03-18", "unixTimeStamp": "1489795200", "value": "34.00" }, + { "UTCDate": "2017-03-19", "unixTimeStamp": "1489881600", "value": "43.12" }, + { "UTCDate": "2017-03-20", "unixTimeStamp": "1489968000", "value": "42.51" }, + { "UTCDate": "2017-03-21", "unixTimeStamp": "1490054400", "value": "42.67" }, + { "UTCDate": "2017-03-22", "unixTimeStamp": "1490140800", "value": "41.65" }, + { "UTCDate": "2017-03-23", "unixTimeStamp": "1490227200", "value": "43.20" }, + { "UTCDate": "2017-03-24", "unixTimeStamp": "1490313600", "value": "53.19" }, + { "UTCDate": "2017-03-25", "unixTimeStamp": "1490400000", "value": "50.62" }, + { "UTCDate": "2017-03-26", "unixTimeStamp": "1490486400", "value": "50.63" }, + { "UTCDate": "2017-03-27", "unixTimeStamp": "1490572800", "value": "49.06" }, + { "UTCDate": "2017-03-28", "unixTimeStamp": "1490659200", "value": "50.25" }, + { "UTCDate": "2017-03-29", "unixTimeStamp": "1490745600", "value": "53.07" }, + { "UTCDate": "2017-03-30", "unixTimeStamp": "1490832000", "value": "51.91" }, + { "UTCDate": "2017-03-31", "unixTimeStamp": "1490918400", "value": "49.91" }, + { "UTCDate": "2017-04-01", "unixTimeStamp": "1491004800", "value": "50.60" }, + { "UTCDate": "2017-04-02", "unixTimeStamp": "1491091200", "value": "48.55" }, + { "UTCDate": "2017-04-03", "unixTimeStamp": "1491177600", "value": "44.13" }, + { "UTCDate": "2017-04-04", "unixTimeStamp": "1491264000", "value": "44.43" }, + { "UTCDate": "2017-04-05", "unixTimeStamp": "1491350400", "value": "44.90" }, + { "UTCDate": "2017-04-06", "unixTimeStamp": "1491436800", "value": "43.23" }, + { "UTCDate": "2017-04-07", "unixTimeStamp": "1491523200", "value": "42.31" }, + { "UTCDate": "2017-04-08", "unixTimeStamp": "1491609600", "value": "44.37" }, + { "UTCDate": "2017-04-09", "unixTimeStamp": "1491696000", "value": "43.72" }, + { "UTCDate": "2017-04-10", "unixTimeStamp": "1491782400", "value": "43.74" }, + { "UTCDate": "2017-04-11", "unixTimeStamp": "1491868800", "value": "43.74" }, + { "UTCDate": "2017-04-12", "unixTimeStamp": "1491955200", "value": "46.38" }, + { "UTCDate": "2017-04-13", "unixTimeStamp": "1492041600", "value": "49.97" }, + { "UTCDate": "2017-04-14", "unixTimeStamp": "1492128000", "value": "47.32" }, + { "UTCDate": "2017-04-15", "unixTimeStamp": "1492214400", "value": "48.89" }, + { "UTCDate": "2017-04-16", "unixTimeStamp": "1492300800", "value": "48.22" }, + { "UTCDate": "2017-04-17", "unixTimeStamp": "1492387200", "value": "47.94" }, + { "UTCDate": "2017-04-18", "unixTimeStamp": "1492473600", "value": "49.88" }, + { "UTCDate": "2017-04-19", "unixTimeStamp": "1492560000", "value": "47.88" }, + { "UTCDate": "2017-04-20", "unixTimeStamp": "1492646400", "value": "49.36" }, + { "UTCDate": "2017-04-21", "unixTimeStamp": "1492732800", "value": "48.27" }, + { "UTCDate": "2017-04-22", "unixTimeStamp": "1492819200", "value": "48.41" }, + { "UTCDate": "2017-04-23", "unixTimeStamp": "1492905600", "value": "48.75" }, + { "UTCDate": "2017-04-24", "unixTimeStamp": "1492992000", "value": "49.94" }, + { "UTCDate": "2017-04-25", "unixTimeStamp": "1493078400", "value": "50.09" }, + { "UTCDate": "2017-04-26", "unixTimeStamp": "1493164800", "value": "53.28" }, + { "UTCDate": "2017-04-27", "unixTimeStamp": "1493251200", "value": "63.14" }, + { "UTCDate": "2017-04-28", "unixTimeStamp": "1493337600", "value": "72.42" }, + { "UTCDate": "2017-04-29", "unixTimeStamp": "1493424000", "value": "69.83" }, + { "UTCDate": "2017-04-30", "unixTimeStamp": "1493510400", "value": "79.83" }, + { "UTCDate": "2017-05-01", "unixTimeStamp": "1493596800", "value": "77.53" }, + { "UTCDate": "2017-05-02", "unixTimeStamp": "1493683200", "value": "77.25" }, + { "UTCDate": "2017-05-03", "unixTimeStamp": "1493769600", "value": "80.37" }, + { "UTCDate": "2017-05-04", "unixTimeStamp": "1493856000", "value": "94.55" }, + { "UTCDate": "2017-05-05", "unixTimeStamp": "1493942400", "value": "90.79" }, + { "UTCDate": "2017-05-06", "unixTimeStamp": "1494028800", "value": "94.82" }, + { "UTCDate": "2017-05-07", "unixTimeStamp": "1494115200", "value": "90.46" }, + { "UTCDate": "2017-05-08", "unixTimeStamp": "1494201600", "value": "88.39" }, + { "UTCDate": "2017-05-09", "unixTimeStamp": "1494288000", "value": "86.27" }, + { "UTCDate": "2017-05-10", "unixTimeStamp": "1494374400", "value": "87.83" }, + { "UTCDate": "2017-05-11", "unixTimeStamp": "1494460800", "value": "88.20" }, + { "UTCDate": "2017-05-12", "unixTimeStamp": "1494547200", "value": "85.15" }, + { "UTCDate": "2017-05-13", "unixTimeStamp": "1494633600", "value": "87.96" }, + { "UTCDate": "2017-05-14", "unixTimeStamp": "1494720000", "value": "88.72" }, + { "UTCDate": "2017-05-15", "unixTimeStamp": "1494806400", "value": "90.32" }, + { "UTCDate": "2017-05-16", "unixTimeStamp": "1494892800", "value": "87.80" }, + { "UTCDate": "2017-05-17", "unixTimeStamp": "1494979200", "value": "86.98" }, + { "UTCDate": "2017-05-18", "unixTimeStamp": "1495065600", "value": "95.88" }, + { "UTCDate": "2017-05-19", "unixTimeStamp": "1495152000", "value": "124.38" }, + { "UTCDate": "2017-05-20", "unixTimeStamp": "1495238400", "value": "123.06" }, + { "UTCDate": "2017-05-21", "unixTimeStamp": "1495324800", "value": "148.00" }, + { "UTCDate": "2017-05-22", "unixTimeStamp": "1495411200", "value": "160.39" }, + { "UTCDate": "2017-05-23", "unixTimeStamp": "1495497600", "value": "169.50" }, + { "UTCDate": "2017-05-24", "unixTimeStamp": "1495584000", "value": "193.03" }, + { "UTCDate": "2017-05-25", "unixTimeStamp": "1495670400", "value": "177.33" }, + { "UTCDate": "2017-05-26", "unixTimeStamp": "1495756800", "value": "162.83" }, + { "UTCDate": "2017-05-27", "unixTimeStamp": "1495843200", "value": "156.63" }, + { "UTCDate": "2017-05-28", "unixTimeStamp": "1495929600", "value": "172.86" }, + { "UTCDate": "2017-05-29", "unixTimeStamp": "1496016000", "value": "194.17" }, + { "UTCDate": "2017-05-30", "unixTimeStamp": "1496102400", "value": "228.58" }, + { "UTCDate": "2017-05-31", "unixTimeStamp": "1496188800", "value": "228.64" }, + { "UTCDate": "2017-06-01", "unixTimeStamp": "1496275200", "value": "220.70" }, + { "UTCDate": "2017-06-02", "unixTimeStamp": "1496361600", "value": "222.04" }, + { "UTCDate": "2017-06-03", "unixTimeStamp": "1496448000", "value": "224.30" }, + { "UTCDate": "2017-06-04", "unixTimeStamp": "1496534400", "value": "244.96" }, + { "UTCDate": "2017-06-05", "unixTimeStamp": "1496620800", "value": "247.75" }, + { "UTCDate": "2017-06-06", "unixTimeStamp": "1496707200", "value": "264.26" }, + { "UTCDate": "2017-06-07", "unixTimeStamp": "1496793600", "value": "255.77" }, + { "UTCDate": "2017-06-08", "unixTimeStamp": "1496880000", "value": "259.41" }, + { "UTCDate": "2017-06-09", "unixTimeStamp": "1496966400", "value": "279.11" }, + { "UTCDate": "2017-06-10", "unixTimeStamp": "1497052800", "value": "335.95" }, + { "UTCDate": "2017-06-11", "unixTimeStamp": "1497139200", "value": "339.68" }, + { "UTCDate": "2017-06-12", "unixTimeStamp": "1497225600", "value": "394.66" }, + { "UTCDate": "2017-06-13", "unixTimeStamp": "1497312000", "value": "388.09" }, + { "UTCDate": "2017-06-14", "unixTimeStamp": "1497398400", "value": "343.84" }, + { "UTCDate": "2017-06-15", "unixTimeStamp": "1497484800", "value": "344.68" }, + { "UTCDate": "2017-06-16", "unixTimeStamp": "1497571200", "value": "353.61" }, + { "UTCDate": "2017-06-17", "unixTimeStamp": "1497657600", "value": "368.10" }, + { "UTCDate": "2017-06-18", "unixTimeStamp": "1497744000", "value": "351.53" }, + { "UTCDate": "2017-06-19", "unixTimeStamp": "1497830400", "value": "358.20" }, + { "UTCDate": "2017-06-20", "unixTimeStamp": "1497916800", "value": "350.53" }, + { "UTCDate": "2017-06-21", "unixTimeStamp": "1498003200", "value": "325.30" }, + { "UTCDate": "2017-06-22", "unixTimeStamp": "1498089600", "value": "320.97" }, + { "UTCDate": "2017-06-23", "unixTimeStamp": "1498176000", "value": "326.85" }, + { "UTCDate": "2017-06-24", "unixTimeStamp": "1498262400", "value": "304.54" }, + { "UTCDate": "2017-06-25", "unixTimeStamp": "1498348800", "value": "279.36" }, + { "UTCDate": "2017-06-26", "unixTimeStamp": "1498435200", "value": "253.68" }, + { "UTCDate": "2017-06-27", "unixTimeStamp": "1498521600", "value": "286.14" }, + { "UTCDate": "2017-06-28", "unixTimeStamp": "1498608000", "value": "315.86" }, + { "UTCDate": "2017-06-29", "unixTimeStamp": "1498694400", "value": "292.90" }, + { "UTCDate": "2017-06-30", "unixTimeStamp": "1498780800", "value": "280.68" }, + { "UTCDate": "2017-07-01", "unixTimeStamp": "1498867200", "value": "261.00" }, + { "UTCDate": "2017-07-02", "unixTimeStamp": "1498953600", "value": "283.99" }, + { "UTCDate": "2017-07-03", "unixTimeStamp": "1499040000", "value": "276.41" }, + { "UTCDate": "2017-07-04", "unixTimeStamp": "1499126400", "value": "269.05" }, + { "UTCDate": "2017-07-05", "unixTimeStamp": "1499212800", "value": "266.00" }, + { "UTCDate": "2017-07-06", "unixTimeStamp": "1499299200", "value": "265.88" }, + { "UTCDate": "2017-07-07", "unixTimeStamp": "1499385600", "value": "240.94" }, + { "UTCDate": "2017-07-08", "unixTimeStamp": "1499472000", "value": "245.67" }, + { "UTCDate": "2017-07-09", "unixTimeStamp": "1499558400", "value": "237.72" }, + { "UTCDate": "2017-07-10", "unixTimeStamp": "1499644800", "value": "205.76" }, + { "UTCDate": "2017-07-11", "unixTimeStamp": "1499731200", "value": "190.55" }, + { "UTCDate": "2017-07-12", "unixTimeStamp": "1499817600", "value": "224.15" }, + { "UTCDate": "2017-07-13", "unixTimeStamp": "1499904000", "value": "205.41" }, + { "UTCDate": "2017-07-14", "unixTimeStamp": "1499990400", "value": "197.14" }, + { "UTCDate": "2017-07-15", "unixTimeStamp": "1500076800", "value": "169.10" }, + { "UTCDate": "2017-07-16", "unixTimeStamp": "1500163200", "value": "155.42" }, + { "UTCDate": "2017-07-17", "unixTimeStamp": "1500249600", "value": "189.97" }, + { "UTCDate": "2017-07-18", "unixTimeStamp": "1500336000", "value": "227.09" }, + { "UTCDate": "2017-07-19", "unixTimeStamp": "1500422400", "value": "194.41" }, + { "UTCDate": "2017-07-20", "unixTimeStamp": "1500508800", "value": "226.33" }, + { "UTCDate": "2017-07-21", "unixTimeStamp": "1500595200", "value": "216.33" }, + { "UTCDate": "2017-07-22", "unixTimeStamp": "1500681600", "value": "230.47" }, + { "UTCDate": "2017-07-23", "unixTimeStamp": "1500768000", "value": "228.32" }, + { "UTCDate": "2017-07-24", "unixTimeStamp": "1500854400", "value": "225.48" }, + { "UTCDate": "2017-07-25", "unixTimeStamp": "1500940800", "value": "203.59" }, + { "UTCDate": "2017-07-26", "unixTimeStamp": "1501027200", "value": "202.88" }, + { "UTCDate": "2017-07-27", "unixTimeStamp": "1501113600", "value": "202.93" }, + { "UTCDate": "2017-07-28", "unixTimeStamp": "1501200000", "value": "191.21" }, + { "UTCDate": "2017-07-29", "unixTimeStamp": "1501286400", "value": "206.14" }, + { "UTCDate": "2017-07-30", "unixTimeStamp": "1501372800", "value": "196.78" }, + { "UTCDate": "2017-07-31", "unixTimeStamp": "1501459200", "value": "201.33" }, + { "UTCDate": "2017-08-01", "unixTimeStamp": "1501545600", "value": "225.90" }, + { "UTCDate": "2017-08-02", "unixTimeStamp": "1501632000", "value": "218.12" }, + { "UTCDate": "2017-08-03", "unixTimeStamp": "1501718400", "value": "224.39" }, + { "UTCDate": "2017-08-04", "unixTimeStamp": "1501804800", "value": "220.60" }, + { "UTCDate": "2017-08-05", "unixTimeStamp": "1501891200", "value": "253.09" }, + { "UTCDate": "2017-08-06", "unixTimeStamp": "1501977600", "value": "264.56" }, + { "UTCDate": "2017-08-07", "unixTimeStamp": "1502064000", "value": "269.94" }, + { "UTCDate": "2017-08-08", "unixTimeStamp": "1502150400", "value": "296.51" }, + { "UTCDate": "2017-08-09", "unixTimeStamp": "1502236800", "value": "295.28" }, + { "UTCDate": "2017-08-10", "unixTimeStamp": "1502323200", "value": "298.28" }, + { "UTCDate": "2017-08-11", "unixTimeStamp": "1502409600", "value": "309.32" }, + { "UTCDate": "2017-08-12", "unixTimeStamp": "1502496000", "value": "308.02" }, + { "UTCDate": "2017-08-13", "unixTimeStamp": "1502582400", "value": "296.62" }, + { "UTCDate": "2017-08-14", "unixTimeStamp": "1502668800", "value": "299.16" }, + { "UTCDate": "2017-08-15", "unixTimeStamp": "1502755200", "value": "286.52" }, + { "UTCDate": "2017-08-16", "unixTimeStamp": "1502841600", "value": "301.38" }, + { "UTCDate": "2017-08-17", "unixTimeStamp": "1502928000", "value": "300.30" }, + { "UTCDate": "2017-08-18", "unixTimeStamp": "1503014400", "value": "292.62" }, + { "UTCDate": "2017-08-19", "unixTimeStamp": "1503100800", "value": "293.02" }, + { "UTCDate": "2017-08-20", "unixTimeStamp": "1503187200", "value": "298.20" }, + { "UTCDate": "2017-08-21", "unixTimeStamp": "1503273600", "value": "321.85" }, + { "UTCDate": "2017-08-22", "unixTimeStamp": "1503360000", "value": "313.37" }, + { "UTCDate": "2017-08-23", "unixTimeStamp": "1503446400", "value": "317.40" }, + { "UTCDate": "2017-08-24", "unixTimeStamp": "1503532800", "value": "325.28" }, + { "UTCDate": "2017-08-25", "unixTimeStamp": "1503619200", "value": "330.06" }, + { "UTCDate": "2017-08-26", "unixTimeStamp": "1503705600", "value": "332.86" }, + { "UTCDate": "2017-08-27", "unixTimeStamp": "1503792000", "value": "347.88" }, + { "UTCDate": "2017-08-28", "unixTimeStamp": "1503878400", "value": "347.66" }, + { "UTCDate": "2017-08-29", "unixTimeStamp": "1503964800", "value": "372.35" }, + { "UTCDate": "2017-08-30", "unixTimeStamp": "1504051200", "value": "383.86" }, + { "UTCDate": "2017-08-31", "unixTimeStamp": "1504137600", "value": "388.33" }, + { "UTCDate": "2017-09-01", "unixTimeStamp": "1504224000", "value": "391.42" }, + { "UTCDate": "2017-09-02", "unixTimeStamp": "1504310400", "value": "351.03" }, + { "UTCDate": "2017-09-03", "unixTimeStamp": "1504396800", "value": "352.45" }, + { "UTCDate": "2017-09-04", "unixTimeStamp": "1504483200", "value": "303.70" }, + { "UTCDate": "2017-09-05", "unixTimeStamp": "1504569600", "value": "317.94" }, + { "UTCDate": "2017-09-06", "unixTimeStamp": "1504656000", "value": "338.92" }, + { "UTCDate": "2017-09-07", "unixTimeStamp": "1504742400", "value": "335.37" }, + { "UTCDate": "2017-09-08", "unixTimeStamp": "1504828800", "value": "306.72" }, + { "UTCDate": "2017-09-09", "unixTimeStamp": "1504915200", "value": "303.79" }, + { "UTCDate": "2017-09-10", "unixTimeStamp": "1505001600", "value": "299.21" }, + { "UTCDate": "2017-09-11", "unixTimeStamp": "1505088000", "value": "297.95" }, + { "UTCDate": "2017-09-12", "unixTimeStamp": "1505174400", "value": "294.10" }, + { "UTCDate": "2017-09-13", "unixTimeStamp": "1505260800", "value": "275.84" }, + { "UTCDate": "2017-09-14", "unixTimeStamp": "1505347200", "value": "223.14" }, + { "UTCDate": "2017-09-15", "unixTimeStamp": "1505433600", "value": "259.57" }, + { "UTCDate": "2017-09-16", "unixTimeStamp": "1505520000", "value": "254.49" }, + { "UTCDate": "2017-09-17", "unixTimeStamp": "1505606400", "value": "258.40" }, + { "UTCDate": "2017-09-18", "unixTimeStamp": "1505692800", "value": "297.53" }, + { "UTCDate": "2017-09-19", "unixTimeStamp": "1505779200", "value": "283.00" }, + { "UTCDate": "2017-09-20", "unixTimeStamp": "1505865600", "value": "283.56" }, + { "UTCDate": "2017-09-21", "unixTimeStamp": "1505952000", "value": "257.77" }, + { "UTCDate": "2017-09-22", "unixTimeStamp": "1506038400", "value": "262.94" }, + { "UTCDate": "2017-09-23", "unixTimeStamp": "1506124800", "value": "286.14" }, + { "UTCDate": "2017-09-24", "unixTimeStamp": "1506211200", "value": "282.60" }, + { "UTCDate": "2017-09-25", "unixTimeStamp": "1506297600", "value": "294.89" }, + { "UTCDate": "2017-09-26", "unixTimeStamp": "1506384000", "value": "288.64" }, + { "UTCDate": "2017-09-27", "unixTimeStamp": "1506470400", "value": "309.97" }, + { "UTCDate": "2017-09-28", "unixTimeStamp": "1506556800", "value": "302.77" }, + { "UTCDate": "2017-09-29", "unixTimeStamp": "1506643200", "value": "292.58" }, + { "UTCDate": "2017-09-30", "unixTimeStamp": "1506729600", "value": "302.77" }, + { "UTCDate": "2017-10-01", "unixTimeStamp": "1506816000", "value": "303.95" }, + { "UTCDate": "2017-10-02", "unixTimeStamp": "1506902400", "value": "296.81" }, + { "UTCDate": "2017-10-03", "unixTimeStamp": "1506988800", "value": "291.81" }, + { "UTCDate": "2017-10-04", "unixTimeStamp": "1507075200", "value": "291.68" }, + { "UTCDate": "2017-10-05", "unixTimeStamp": "1507161600", "value": "294.99" }, + { "UTCDate": "2017-10-06", "unixTimeStamp": "1507248000", "value": "308.33" }, + { "UTCDate": "2017-10-07", "unixTimeStamp": "1507334400", "value": "311.26" }, + { "UTCDate": "2017-10-08", "unixTimeStamp": "1507420800", "value": "309.49" }, + { "UTCDate": "2017-10-09", "unixTimeStamp": "1507507200", "value": "296.95" }, + { "UTCDate": "2017-10-10", "unixTimeStamp": "1507593600", "value": "298.46" }, + { "UTCDate": "2017-10-11", "unixTimeStamp": "1507680000", "value": "302.86" }, + { "UTCDate": "2017-10-12", "unixTimeStamp": "1507766400", "value": "302.89" }, + { "UTCDate": "2017-10-13", "unixTimeStamp": "1507852800", "value": "336.83" }, + { "UTCDate": "2017-10-14", "unixTimeStamp": "1507939200", "value": "338.81" }, + { "UTCDate": "2017-10-15", "unixTimeStamp": "1508025600", "value": "336.58" }, + { "UTCDate": "2017-10-16", "unixTimeStamp": "1508112000", "value": "334.23" }, + { "UTCDate": "2017-10-17", "unixTimeStamp": "1508198400", "value": "316.14" }, + { "UTCDate": "2017-10-18", "unixTimeStamp": "1508284800", "value": "313.54" }, + { "UTCDate": "2017-10-19", "unixTimeStamp": "1508371200", "value": "307.41" }, + { "UTCDate": "2017-10-20", "unixTimeStamp": "1508457600", "value": "303.08" }, + { "UTCDate": "2017-10-21", "unixTimeStamp": "1508544000", "value": "299.55" }, + { "UTCDate": "2017-10-22", "unixTimeStamp": "1508630400", "value": "294.03" }, + { "UTCDate": "2017-10-23", "unixTimeStamp": "1508716800", "value": "285.27" }, + { "UTCDate": "2017-10-24", "unixTimeStamp": "1508803200", "value": "296.50" }, + { "UTCDate": "2017-10-25", "unixTimeStamp": "1508889600", "value": "296.35" }, + { "UTCDate": "2017-10-26", "unixTimeStamp": "1508976000", "value": "295.54" }, + { "UTCDate": "2017-10-27", "unixTimeStamp": "1509062400", "value": "296.36" }, + { "UTCDate": "2017-10-28", "unixTimeStamp": "1509148800", "value": "293.35" }, + { "UTCDate": "2017-10-29", "unixTimeStamp": "1509235200", "value": "304.04" }, + { "UTCDate": "2017-10-30", "unixTimeStamp": "1509321600", "value": "306.80" }, + { "UTCDate": "2017-10-31", "unixTimeStamp": "1509408000", "value": "303.64" }, + { "UTCDate": "2017-11-01", "unixTimeStamp": "1509494400", "value": "289.42" }, + { "UTCDate": "2017-11-02", "unixTimeStamp": "1509580800", "value": "284.92" }, + { "UTCDate": "2017-11-03", "unixTimeStamp": "1509667200", "value": "304.51" }, + { "UTCDate": "2017-11-04", "unixTimeStamp": "1509753600", "value": "300.04" }, + { "UTCDate": "2017-11-05", "unixTimeStamp": "1509840000", "value": "296.23" }, + { "UTCDate": "2017-11-06", "unixTimeStamp": "1509926400", "value": "296.82" }, + { "UTCDate": "2017-11-07", "unixTimeStamp": "1510012800", "value": "291.84" }, + { "UTCDate": "2017-11-08", "unixTimeStamp": "1510099200", "value": "307.35" }, + { "UTCDate": "2017-11-09", "unixTimeStamp": "1510185600", "value": "319.66" }, + { "UTCDate": "2017-11-10", "unixTimeStamp": "1510272000", "value": "296.86" }, + { "UTCDate": "2017-11-11", "unixTimeStamp": "1510358400", "value": "314.23" }, + { "UTCDate": "2017-11-12", "unixTimeStamp": "1510444800", "value": "306.02" }, + { "UTCDate": "2017-11-13", "unixTimeStamp": "1510531200", "value": "314.60" }, + { "UTCDate": "2017-11-14", "unixTimeStamp": "1510617600", "value": "334.72" }, + { "UTCDate": "2017-11-15", "unixTimeStamp": "1510704000", "value": "331.20" }, + { "UTCDate": "2017-11-16", "unixTimeStamp": "1510790400", "value": "330.32" }, + { "UTCDate": "2017-11-17", "unixTimeStamp": "1510876800", "value": "331.72" }, + { "UTCDate": "2017-11-18", "unixTimeStamp": "1510963200", "value": "346.65" }, + { "UTCDate": "2017-11-19", "unixTimeStamp": "1511049600", "value": "354.60" }, + { "UTCDate": "2017-11-20", "unixTimeStamp": "1511136000", "value": "367.71" }, + { "UTCDate": "2017-11-21", "unixTimeStamp": "1511222400", "value": "360.52" }, + { "UTCDate": "2017-11-22", "unixTimeStamp": "1511308800", "value": "380.84" }, + { "UTCDate": "2017-11-23", "unixTimeStamp": "1511395200", "value": "406.57" }, + { "UTCDate": "2017-11-24", "unixTimeStamp": "1511481600", "value": "470.43" }, + { "UTCDate": "2017-11-25", "unixTimeStamp": "1511568000", "value": "464.61" }, + { "UTCDate": "2017-11-26", "unixTimeStamp": "1511654400", "value": "470.54" }, + { "UTCDate": "2017-11-27", "unixTimeStamp": "1511740800", "value": "475.24" }, + { "UTCDate": "2017-11-28", "unixTimeStamp": "1511827200", "value": "466.27" }, + { "UTCDate": "2017-11-29", "unixTimeStamp": "1511913600", "value": "427.42" }, + { "UTCDate": "2017-11-30", "unixTimeStamp": "1512000000", "value": "434.85" }, + { "UTCDate": "2017-12-01", "unixTimeStamp": "1512086400", "value": "461.58" }, + { "UTCDate": "2017-12-02", "unixTimeStamp": "1512172800", "value": "457.96" }, + { "UTCDate": "2017-12-03", "unixTimeStamp": "1512259200", "value": "462.81" }, + { "UTCDate": "2017-12-04", "unixTimeStamp": "1512345600", "value": "466.93" }, + { "UTCDate": "2017-12-05", "unixTimeStamp": "1512432000", "value": "453.96" }, + { "UTCDate": "2017-12-06", "unixTimeStamp": "1512518400", "value": "422.48" }, + { "UTCDate": "2017-12-07", "unixTimeStamp": "1512604800", "value": "421.15" }, + { "UTCDate": "2017-12-08", "unixTimeStamp": "1512691200", "value": "451.74" }, + { "UTCDate": "2017-12-09", "unixTimeStamp": "1512777600", "value": "472.86" }, + { "UTCDate": "2017-12-10", "unixTimeStamp": "1512864000", "value": "436.49" }, + { "UTCDate": "2017-12-11", "unixTimeStamp": "1512950400", "value": "513.29" }, + { "UTCDate": "2017-12-12", "unixTimeStamp": "1513036800", "value": "656.52" }, + { "UTCDate": "2017-12-13", "unixTimeStamp": "1513123200", "value": "699.09" }, + { "UTCDate": "2017-12-14", "unixTimeStamp": "1513209600", "value": "693.58" }, + { "UTCDate": "2017-12-15", "unixTimeStamp": "1513296000", "value": "684.27" }, + { "UTCDate": "2017-12-16", "unixTimeStamp": "1513382400", "value": "692.83" }, + { "UTCDate": "2017-12-17", "unixTimeStamp": "1513468800", "value": "717.71" }, + { "UTCDate": "2017-12-18", "unixTimeStamp": "1513555200", "value": "785.99" }, + { "UTCDate": "2017-12-19", "unixTimeStamp": "1513641600", "value": "812.50" }, + { "UTCDate": "2017-12-20", "unixTimeStamp": "1513728000", "value": "799.17" }, + { "UTCDate": "2017-12-21", "unixTimeStamp": "1513814400", "value": "789.39" }, + { "UTCDate": "2017-12-22", "unixTimeStamp": "1513900800", "value": "657.83" }, + { "UTCDate": "2017-12-23", "unixTimeStamp": "1513987200", "value": "700.44" }, + { "UTCDate": "2017-12-24", "unixTimeStamp": "1514073600", "value": "675.91" }, + { "UTCDate": "2017-12-25", "unixTimeStamp": "1514160000", "value": "723.14" }, + { "UTCDate": "2017-12-26", "unixTimeStamp": "1514246400", "value": "753.40" }, + { "UTCDate": "2017-12-27", "unixTimeStamp": "1514332800", "value": "739.94" }, + { "UTCDate": "2017-12-28", "unixTimeStamp": "1514419200", "value": "716.69" }, + { "UTCDate": "2017-12-29", "unixTimeStamp": "1514505600", "value": "739.60" }, + { "UTCDate": "2017-12-30", "unixTimeStamp": "1514592000", "value": "692.99" }, + { "UTCDate": "2017-12-31", "unixTimeStamp": "1514678400", "value": "741.13" }, + { "UTCDate": "2018-01-01", "unixTimeStamp": "1514764800", "value": "756.20" }, + { "UTCDate": "2018-01-02", "unixTimeStamp": "1514851200", "value": "861.97" }, + { "UTCDate": "2018-01-03", "unixTimeStamp": "1514937600", "value": "941.10" }, + { "UTCDate": "2018-01-04", "unixTimeStamp": "1515024000", "value": "944.83" }, + { "UTCDate": "2018-01-05", "unixTimeStamp": "1515110400", "value": "967.13" }, + { "UTCDate": "2018-01-06", "unixTimeStamp": "1515196800", "value": "1006.41" }, + { "UTCDate": "2018-01-07", "unixTimeStamp": "1515283200", "value": "1117.75" }, + { "UTCDate": "2018-01-08", "unixTimeStamp": "1515369600", "value": "1136.11" }, + { "UTCDate": "2018-01-09", "unixTimeStamp": "1515456000", "value": "1289.24" }, + { "UTCDate": "2018-01-10", "unixTimeStamp": "1515542400", "value": "1248.99" }, + { "UTCDate": "2018-01-11", "unixTimeStamp": "1515628800", "value": "1139.32" }, + { "UTCDate": "2018-01-12", "unixTimeStamp": "1515715200", "value": "1261.03" }, + { "UTCDate": "2018-01-13", "unixTimeStamp": "1515801600", "value": "1385.02" }, + { "UTCDate": "2018-01-14", "unixTimeStamp": "1515888000", "value": "1359.48" }, + { "UTCDate": "2018-01-15", "unixTimeStamp": "1515974400", "value": "1278.69" }, + { "UTCDate": "2018-01-16", "unixTimeStamp": "1516060800", "value": "1050.26" }, + { "UTCDate": "2018-01-17", "unixTimeStamp": "1516147200", "value": "1024.69" }, + { "UTCDate": "2018-01-18", "unixTimeStamp": "1516233600", "value": "1012.97" }, + { "UTCDate": "2018-01-19", "unixTimeStamp": "1516320000", "value": "1037.36" }, + { "UTCDate": "2018-01-20", "unixTimeStamp": "1516406400", "value": "1150.50" }, + { "UTCDate": "2018-01-21", "unixTimeStamp": "1516492800", "value": "1049.09" }, + { "UTCDate": "2018-01-22", "unixTimeStamp": "1516579200", "value": "999.64" }, + { "UTCDate": "2018-01-23", "unixTimeStamp": "1516665600", "value": "984.47" }, + { "UTCDate": "2018-01-24", "unixTimeStamp": "1516752000", "value": "1061.78" }, + { "UTCDate": "2018-01-25", "unixTimeStamp": "1516838400", "value": "1046.37" }, + { "UTCDate": "2018-01-26", "unixTimeStamp": "1516924800", "value": "1048.58" }, + { "UTCDate": "2018-01-27", "unixTimeStamp": "1517011200", "value": "1109.08" }, + { "UTCDate": "2018-01-28", "unixTimeStamp": "1517097600", "value": "1231.58" }, + { "UTCDate": "2018-01-29", "unixTimeStamp": "1517184000", "value": "1169.96" }, + { "UTCDate": "2018-01-30", "unixTimeStamp": "1517270400", "value": "1063.75" }, + { "UTCDate": "2018-01-31", "unixTimeStamp": "1517356800", "value": "1111.31" }, + { "UTCDate": "2018-02-01", "unixTimeStamp": "1517443200", "value": "1026.19" }, + { "UTCDate": "2018-02-02", "unixTimeStamp": "1517529600", "value": "917.47" }, + { "UTCDate": "2018-02-03", "unixTimeStamp": "1517616000", "value": "970.87" }, + { "UTCDate": "2018-02-04", "unixTimeStamp": "1517702400", "value": "827.59" }, + { "UTCDate": "2018-02-05", "unixTimeStamp": "1517788800", "value": "695.08" }, + { "UTCDate": "2018-02-06", "unixTimeStamp": "1517875200", "value": "785.01" }, + { "UTCDate": "2018-02-07", "unixTimeStamp": "1517961600", "value": "751.81" }, + { "UTCDate": "2018-02-08", "unixTimeStamp": "1518048000", "value": "813.55" }, + { "UTCDate": "2018-02-09", "unixTimeStamp": "1518134400", "value": "877.88" }, + { "UTCDate": "2018-02-10", "unixTimeStamp": "1518220800", "value": "850.75" }, + { "UTCDate": "2018-02-11", "unixTimeStamp": "1518307200", "value": "811.24" }, + { "UTCDate": "2018-02-12", "unixTimeStamp": "1518393600", "value": "865.27" }, + { "UTCDate": "2018-02-13", "unixTimeStamp": "1518480000", "value": "840.98" }, + { "UTCDate": "2018-02-14", "unixTimeStamp": "1518566400", "value": "920.11" }, + { "UTCDate": "2018-02-15", "unixTimeStamp": "1518652800", "value": "927.95" }, + { "UTCDate": "2018-02-16", "unixTimeStamp": "1518739200", "value": "938.02" }, + { "UTCDate": "2018-02-17", "unixTimeStamp": "1518825600", "value": "974.77" }, + { "UTCDate": "2018-02-18", "unixTimeStamp": "1518912000", "value": "913.90" }, + { "UTCDate": "2018-02-19", "unixTimeStamp": "1518998400", "value": "939.79" }, + { "UTCDate": "2018-02-20", "unixTimeStamp": "1519084800", "value": "885.52" }, + { "UTCDate": "2018-02-21", "unixTimeStamp": "1519171200", "value": "840.10" }, + { "UTCDate": "2018-02-22", "unixTimeStamp": "1519257600", "value": "804.63" }, + { "UTCDate": "2018-02-23", "unixTimeStamp": "1519344000", "value": "854.70" }, + { "UTCDate": "2018-02-24", "unixTimeStamp": "1519430400", "value": "833.49" }, + { "UTCDate": "2018-02-25", "unixTimeStamp": "1519516800", "value": "840.28" }, + { "UTCDate": "2018-02-26", "unixTimeStamp": "1519603200", "value": "867.62" }, + { "UTCDate": "2018-02-27", "unixTimeStamp": "1519689600", "value": "871.58" }, + { "UTCDate": "2018-02-28", "unixTimeStamp": "1519776000", "value": "851.50" }, + { "UTCDate": "2018-03-01", "unixTimeStamp": "1519862400", "value": "869.87" }, + { "UTCDate": "2018-03-02", "unixTimeStamp": "1519948800", "value": "855.60" }, + { "UTCDate": "2018-03-03", "unixTimeStamp": "1520035200", "value": "855.65" }, + { "UTCDate": "2018-03-04", "unixTimeStamp": "1520121600", "value": "864.83" }, + { "UTCDate": "2018-03-05", "unixTimeStamp": "1520208000", "value": "849.42" }, + { "UTCDate": "2018-03-06", "unixTimeStamp": "1520294400", "value": "815.69" }, + { "UTCDate": "2018-03-07", "unixTimeStamp": "1520380800", "value": "751.13" }, + { "UTCDate": "2018-03-08", "unixTimeStamp": "1520467200", "value": "698.83" }, + { "UTCDate": "2018-03-09", "unixTimeStamp": "1520553600", "value": "726.92" }, + { "UTCDate": "2018-03-10", "unixTimeStamp": "1520640000", "value": "682.30" }, + { "UTCDate": "2018-03-11", "unixTimeStamp": "1520726400", "value": "720.36" }, + { "UTCDate": "2018-03-12", "unixTimeStamp": "1520812800", "value": "697.02" }, + { "UTCDate": "2018-03-13", "unixTimeStamp": "1520899200", "value": "689.96" }, + { "UTCDate": "2018-03-14", "unixTimeStamp": "1520985600", "value": "613.15" }, + { "UTCDate": "2018-03-15", "unixTimeStamp": "1521072000", "value": "610.56" }, + { "UTCDate": "2018-03-16", "unixTimeStamp": "1521158400", "value": "600.53" }, + { "UTCDate": "2018-03-17", "unixTimeStamp": "1521244800", "value": "549.79" }, + { "UTCDate": "2018-03-18", "unixTimeStamp": "1521331200", "value": "537.38" }, + { "UTCDate": "2018-03-19", "unixTimeStamp": "1521417600", "value": "555.55" }, + { "UTCDate": "2018-03-20", "unixTimeStamp": "1521504000", "value": "557.57" }, + { "UTCDate": "2018-03-21", "unixTimeStamp": "1521590400", "value": "559.91" }, + { "UTCDate": "2018-03-22", "unixTimeStamp": "1521676800", "value": "539.89" }, + { "UTCDate": "2018-03-23", "unixTimeStamp": "1521763200", "value": "543.83" }, + { "UTCDate": "2018-03-24", "unixTimeStamp": "1521849600", "value": "520.16" }, + { "UTCDate": "2018-03-25", "unixTimeStamp": "1521936000", "value": "523.01" }, + { "UTCDate": "2018-03-26", "unixTimeStamp": "1522022400", "value": "486.25" }, + { "UTCDate": "2018-03-27", "unixTimeStamp": "1522108800", "value": "448.78" }, + { "UTCDate": "2018-03-28", "unixTimeStamp": "1522195200", "value": "445.93" }, + { "UTCDate": "2018-03-29", "unixTimeStamp": "1522281600", "value": "383.90" }, + { "UTCDate": "2018-03-30", "unixTimeStamp": "1522368000", "value": "393.82" }, + { "UTCDate": "2018-03-31", "unixTimeStamp": "1522454400", "value": "394.07" }, + { "UTCDate": "2018-04-01", "unixTimeStamp": "1522540800", "value": "378.85" }, + { "UTCDate": "2018-04-02", "unixTimeStamp": "1522627200", "value": "384.68" }, + { "UTCDate": "2018-04-03", "unixTimeStamp": "1522713600", "value": "415.93" }, + { "UTCDate": "2018-04-04", "unixTimeStamp": "1522800000", "value": "378.65" }, + { "UTCDate": "2018-04-05", "unixTimeStamp": "1522886400", "value": "381.36" }, + { "UTCDate": "2018-04-06", "unixTimeStamp": "1522972800", "value": "370.35" }, + { "UTCDate": "2018-04-07", "unixTimeStamp": "1523059200", "value": "384.98" }, + { "UTCDate": "2018-04-08", "unixTimeStamp": "1523145600", "value": "400.72" }, + { "UTCDate": "2018-04-09", "unixTimeStamp": "1523232000", "value": "399.02" }, + { "UTCDate": "2018-04-10", "unixTimeStamp": "1523318400", "value": "415.65" }, + { "UTCDate": "2018-04-11", "unixTimeStamp": "1523404800", "value": "430.42" }, + { "UTCDate": "2018-04-12", "unixTimeStamp": "1523491200", "value": "493.95" }, + { "UTCDate": "2018-04-13", "unixTimeStamp": "1523577600", "value": "494.96" }, + { "UTCDate": "2018-04-14", "unixTimeStamp": "1523664000", "value": "502.79" }, + { "UTCDate": "2018-04-15", "unixTimeStamp": "1523750400", "value": "534.15" }, + { "UTCDate": "2018-04-16", "unixTimeStamp": "1523836800", "value": "511.67" }, + { "UTCDate": "2018-04-17", "unixTimeStamp": "1523923200", "value": "503.03" }, + { "UTCDate": "2018-04-18", "unixTimeStamp": "1524009600", "value": "525.78" }, + { "UTCDate": "2018-04-19", "unixTimeStamp": "1524096000", "value": "567.25" }, + { "UTCDate": "2018-04-20", "unixTimeStamp": "1524182400", "value": "617.16" }, + { "UTCDate": "2018-04-21", "unixTimeStamp": "1524268800", "value": "605.17" }, + { "UTCDate": "2018-04-22", "unixTimeStamp": "1524355200", "value": "621.33" }, + { "UTCDate": "2018-04-23", "unixTimeStamp": "1524441600", "value": "644.13" }, + { "UTCDate": "2018-04-24", "unixTimeStamp": "1524528000", "value": "703.35" }, + { "UTCDate": "2018-04-25", "unixTimeStamp": "1524614400", "value": "617.73" }, + { "UTCDate": "2018-04-26", "unixTimeStamp": "1524700800", "value": "661.45" }, + { "UTCDate": "2018-04-27", "unixTimeStamp": "1524787200", "value": "643.33" }, + { "UTCDate": "2018-04-28", "unixTimeStamp": "1524873600", "value": "683.02" }, + { "UTCDate": "2018-04-29", "unixTimeStamp": "1524960000", "value": "689.31" }, + { "UTCDate": "2018-04-30", "unixTimeStamp": "1525046400", "value": "670.04" }, + { "UTCDate": "2018-05-01", "unixTimeStamp": "1525132800", "value": "670.81" }, + { "UTCDate": "2018-05-02", "unixTimeStamp": "1525219200", "value": "686.74" }, + { "UTCDate": "2018-05-03", "unixTimeStamp": "1525305600", "value": "777.62" }, + { "UTCDate": "2018-05-04", "unixTimeStamp": "1525392000", "value": "784.21" }, + { "UTCDate": "2018-05-05", "unixTimeStamp": "1525478400", "value": "816.58" }, + { "UTCDate": "2018-05-06", "unixTimeStamp": "1525564800", "value": "790.39" }, + { "UTCDate": "2018-05-07", "unixTimeStamp": "1525651200", "value": "752.40" }, + { "UTCDate": "2018-05-08", "unixTimeStamp": "1525737600", "value": "747.79" }, + { "UTCDate": "2018-05-09", "unixTimeStamp": "1525824000", "value": "751.27" }, + { "UTCDate": "2018-05-10", "unixTimeStamp": "1525910400", "value": "723.61" }, + { "UTCDate": "2018-05-11", "unixTimeStamp": "1525996800", "value": "677.80" }, + { "UTCDate": "2018-05-12", "unixTimeStamp": "1526083200", "value": "683.64" }, + { "UTCDate": "2018-05-13", "unixTimeStamp": "1526169600", "value": "729.34" }, + { "UTCDate": "2018-05-14", "unixTimeStamp": "1526256000", "value": "727.41" }, + { "UTCDate": "2018-05-15", "unixTimeStamp": "1526342400", "value": "705.64" }, + { "UTCDate": "2018-05-16", "unixTimeStamp": "1526428800", "value": "706.72" }, + { "UTCDate": "2018-05-17", "unixTimeStamp": "1526515200", "value": "668.38" }, + { "UTCDate": "2018-05-18", "unixTimeStamp": "1526601600", "value": "693.57" }, + { "UTCDate": "2018-05-19", "unixTimeStamp": "1526688000", "value": "696.05" }, + { "UTCDate": "2018-05-20", "unixTimeStamp": "1526774400", "value": "715.15" }, + { "UTCDate": "2018-05-21", "unixTimeStamp": "1526860800", "value": "696.73" }, + { "UTCDate": "2018-05-22", "unixTimeStamp": "1526947200", "value": "640.84" }, + { "UTCDate": "2018-05-23", "unixTimeStamp": "1527033600", "value": "577.01" }, + { "UTCDate": "2018-05-24", "unixTimeStamp": "1527120000", "value": "602.59" }, + { "UTCDate": "2018-05-25", "unixTimeStamp": "1527206400", "value": "584.77" }, + { "UTCDate": "2018-05-26", "unixTimeStamp": "1527292800", "value": "585.76" }, + { "UTCDate": "2018-05-27", "unixTimeStamp": "1527379200", "value": "569.64" }, + { "UTCDate": "2018-05-28", "unixTimeStamp": "1527465600", "value": "512.03" }, + { "UTCDate": "2018-05-29", "unixTimeStamp": "1527552000", "value": "566.59" }, + { "UTCDate": "2018-05-30", "unixTimeStamp": "1527638400", "value": "557.12" }, + { "UTCDate": "2018-05-31", "unixTimeStamp": "1527724800", "value": "577.23" }, + { "UTCDate": "2018-06-01", "unixTimeStamp": "1527811200", "value": "579.01" }, + { "UTCDate": "2018-06-02", "unixTimeStamp": "1527897600", "value": "590.53" }, + { "UTCDate": "2018-06-03", "unixTimeStamp": "1527984000", "value": "619.04" }, + { "UTCDate": "2018-06-04", "unixTimeStamp": "1528070400", "value": "591.31" }, + { "UTCDate": "2018-06-05", "unixTimeStamp": "1528156800", "value": "608.23" }, + { "UTCDate": "2018-06-06", "unixTimeStamp": "1528243200", "value": "606.30" }, + { "UTCDate": "2018-06-07", "unixTimeStamp": "1528329600", "value": "604.44" }, + { "UTCDate": "2018-06-08", "unixTimeStamp": "1528416000", "value": "599.55" }, + { "UTCDate": "2018-06-09", "unixTimeStamp": "1528502400", "value": "593.38" }, + { "UTCDate": "2018-06-10", "unixTimeStamp": "1528588800", "value": "524.74" }, + { "UTCDate": "2018-06-11", "unixTimeStamp": "1528675200", "value": "531.15" }, + { "UTCDate": "2018-06-12", "unixTimeStamp": "1528761600", "value": "494.53" }, + { "UTCDate": "2018-06-13", "unixTimeStamp": "1528848000", "value": "476.30" }, + { "UTCDate": "2018-06-14", "unixTimeStamp": "1528934400", "value": "519.83" }, + { "UTCDate": "2018-06-15", "unixTimeStamp": "1529020800", "value": "487.51" }, + { "UTCDate": "2018-06-16", "unixTimeStamp": "1529107200", "value": "497.22" }, + { "UTCDate": "2018-06-17", "unixTimeStamp": "1529193600", "value": "496.74" }, + { "UTCDate": "2018-06-18", "unixTimeStamp": "1529280000", "value": "517.63" }, + { "UTCDate": "2018-06-19", "unixTimeStamp": "1529366400", "value": "538.45" }, + { "UTCDate": "2018-06-20", "unixTimeStamp": "1529452800", "value": "536.16" }, + { "UTCDate": "2018-06-21", "unixTimeStamp": "1529539200", "value": "525.77" }, + { "UTCDate": "2018-06-22", "unixTimeStamp": "1529625600", "value": "462.16" }, + { "UTCDate": "2018-06-23", "unixTimeStamp": "1529712000", "value": "474.18" }, + { "UTCDate": "2018-06-24", "unixTimeStamp": "1529798400", "value": "455.25" }, + { "UTCDate": "2018-06-25", "unixTimeStamp": "1529884800", "value": "458.82" }, + { "UTCDate": "2018-06-26", "unixTimeStamp": "1529971200", "value": "429.58" }, + { "UTCDate": "2018-06-27", "unixTimeStamp": "1530057600", "value": "441.75" }, + { "UTCDate": "2018-06-28", "unixTimeStamp": "1530144000", "value": "420.72" }, + { "UTCDate": "2018-06-29", "unixTimeStamp": "1530230400", "value": "435.25" }, + { "UTCDate": "2018-06-30", "unixTimeStamp": "1530316800", "value": "453.42" }, + { "UTCDate": "2018-07-01", "unixTimeStamp": "1530403200", "value": "451.95" }, + { "UTCDate": "2018-07-02", "unixTimeStamp": "1530489600", "value": "476.58" }, + { "UTCDate": "2018-07-03", "unixTimeStamp": "1530576000", "value": "461.95" }, + { "UTCDate": "2018-07-04", "unixTimeStamp": "1530662400", "value": "467.19" }, + { "UTCDate": "2018-07-05", "unixTimeStamp": "1530748800", "value": "467.55" }, + { "UTCDate": "2018-07-06", "unixTimeStamp": "1530835200", "value": "469.93" }, + { "UTCDate": "2018-07-07", "unixTimeStamp": "1530921600", "value": "485.81" }, + { "UTCDate": "2018-07-08", "unixTimeStamp": "1531008000", "value": "486.19" }, + { "UTCDate": "2018-07-09", "unixTimeStamp": "1531094400", "value": "471.48" }, + { "UTCDate": "2018-07-10", "unixTimeStamp": "1531180800", "value": "432.69" }, + { "UTCDate": "2018-07-11", "unixTimeStamp": "1531267200", "value": "445.59" }, + { "UTCDate": "2018-07-12", "unixTimeStamp": "1531353600", "value": "430.91" }, + { "UTCDate": "2018-07-13", "unixTimeStamp": "1531440000", "value": "432.46" }, + { "UTCDate": "2018-07-14", "unixTimeStamp": "1531526400", "value": "433.74" }, + { "UTCDate": "2018-07-15", "unixTimeStamp": "1531612800", "value": "449.62" }, + { "UTCDate": "2018-07-16", "unixTimeStamp": "1531699200", "value": "478.75" }, + { "UTCDate": "2018-07-17", "unixTimeStamp": "1531785600", "value": "499.06" }, + { "UTCDate": "2018-07-18", "unixTimeStamp": "1531872000", "value": "479.02" }, + { "UTCDate": "2018-07-19", "unixTimeStamp": "1531958400", "value": "468.65" }, + { "UTCDate": "2018-07-20", "unixTimeStamp": "1532044800", "value": "448.84" }, + { "UTCDate": "2018-07-21", "unixTimeStamp": "1532131200", "value": "461.04" }, + { "UTCDate": "2018-07-22", "unixTimeStamp": "1532217600", "value": "457.65" }, + { "UTCDate": "2018-07-23", "unixTimeStamp": "1532304000", "value": "449.63" }, + { "UTCDate": "2018-07-24", "unixTimeStamp": "1532390400", "value": "479.47" }, + { "UTCDate": "2018-07-25", "unixTimeStamp": "1532476800", "value": "471.28" }, + { "UTCDate": "2018-07-26", "unixTimeStamp": "1532563200", "value": "462.03" }, + { "UTCDate": "2018-07-27", "unixTimeStamp": "1532649600", "value": "469.69" }, + { "UTCDate": "2018-07-28", "unixTimeStamp": "1532736000", "value": "468.55" }, + { "UTCDate": "2018-07-29", "unixTimeStamp": "1532822400", "value": "466.20" }, + { "UTCDate": "2018-07-30", "unixTimeStamp": "1532908800", "value": "456.56" }, + { "UTCDate": "2018-07-31", "unixTimeStamp": "1532995200", "value": "431.99" }, + { "UTCDate": "2018-08-01", "unixTimeStamp": "1533081600", "value": "419.87" }, + { "UTCDate": "2018-08-02", "unixTimeStamp": "1533168000", "value": "410.83" }, + { "UTCDate": "2018-08-03", "unixTimeStamp": "1533254400", "value": "417.62" }, + { "UTCDate": "2018-08-04", "unixTimeStamp": "1533340800", "value": "406.91" }, + { "UTCDate": "2018-08-05", "unixTimeStamp": "1533427200", "value": "408.81" }, + { "UTCDate": "2018-08-06", "unixTimeStamp": "1533513600", "value": "404.95" }, + { "UTCDate": "2018-08-07", "unixTimeStamp": "1533600000", "value": "377.94" }, + { "UTCDate": "2018-08-08", "unixTimeStamp": "1533686400", "value": "355.57" }, + { "UTCDate": "2018-08-09", "unixTimeStamp": "1533772800", "value": "363.51" }, + { "UTCDate": "2018-08-10", "unixTimeStamp": "1533859200", "value": "331.57" }, + { "UTCDate": "2018-08-11", "unixTimeStamp": "1533945600", "value": "318.01" }, + { "UTCDate": "2018-08-12", "unixTimeStamp": "1534032000", "value": "318.20" }, + { "UTCDate": "2018-08-13", "unixTimeStamp": "1534118400", "value": "284.03" }, + { "UTCDate": "2018-08-14", "unixTimeStamp": "1534204800", "value": "278.31" }, + { "UTCDate": "2018-08-15", "unixTimeStamp": "1534291200", "value": "281.24" }, + { "UTCDate": "2018-08-16", "unixTimeStamp": "1534377600", "value": "286.80" }, + { "UTCDate": "2018-08-17", "unixTimeStamp": "1534464000", "value": "317.57" }, + { "UTCDate": "2018-08-18", "unixTimeStamp": "1534550400", "value": "294.85" }, + { "UTCDate": "2018-08-19", "unixTimeStamp": "1534636800", "value": "299.62" }, + { "UTCDate": "2018-08-20", "unixTimeStamp": "1534723200", "value": "270.81" }, + { "UTCDate": "2018-08-21", "unixTimeStamp": "1534809600", "value": "281.13" }, + { "UTCDate": "2018-08-22", "unixTimeStamp": "1534896000", "value": "270.37" }, + { "UTCDate": "2018-08-23", "unixTimeStamp": "1534982400", "value": "275.83" }, + { "UTCDate": "2018-08-24", "unixTimeStamp": "1535068800", "value": "281.37" }, + { "UTCDate": "2018-08-25", "unixTimeStamp": "1535155200", "value": "277.56" }, + { "UTCDate": "2018-08-26", "unixTimeStamp": "1535241600", "value": "274.30" }, + { "UTCDate": "2018-08-27", "unixTimeStamp": "1535328000", "value": "288.02" }, + { "UTCDate": "2018-08-28", "unixTimeStamp": "1535414400", "value": "295.55" }, + { "UTCDate": "2018-08-29", "unixTimeStamp": "1535500800", "value": "288.67" }, + { "UTCDate": "2018-08-30", "unixTimeStamp": "1535587200", "value": "284.15" }, + { "UTCDate": "2018-08-31", "unixTimeStamp": "1535673600", "value": "281.66" }, + { "UTCDate": "2018-09-01", "unixTimeStamp": "1535760000", "value": "295.36" }, + { "UTCDate": "2018-09-02", "unixTimeStamp": "1535846400", "value": "295.02" }, + { "UTCDate": "2018-09-03", "unixTimeStamp": "1535932800", "value": "288.97" }, + { "UTCDate": "2018-09-04", "unixTimeStamp": "1536019200", "value": "285.23" }, + { "UTCDate": "2018-09-05", "unixTimeStamp": "1536105600", "value": "228.27" }, + { "UTCDate": "2018-09-06", "unixTimeStamp": "1536192000", "value": "229.52" }, + { "UTCDate": "2018-09-07", "unixTimeStamp": "1536278400", "value": "215.14" }, + { "UTCDate": "2018-09-08", "unixTimeStamp": "1536364800", "value": "196.77" }, + { "UTCDate": "2018-09-09", "unixTimeStamp": "1536451200", "value": "195.99" }, + { "UTCDate": "2018-09-10", "unixTimeStamp": "1536537600", "value": "197.14" }, + { "UTCDate": "2018-09-11", "unixTimeStamp": "1536624000", "value": "185.15" }, + { "UTCDate": "2018-09-12", "unixTimeStamp": "1536710400", "value": "183.03" }, + { "UTCDate": "2018-09-13", "unixTimeStamp": "1536796800", "value": "211.27" }, + { "UTCDate": "2018-09-14", "unixTimeStamp": "1536883200", "value": "208.87" }, + { "UTCDate": "2018-09-15", "unixTimeStamp": "1536969600", "value": "221.63" }, + { "UTCDate": "2018-09-16", "unixTimeStamp": "1537056000", "value": "220.12" }, + { "UTCDate": "2018-09-17", "unixTimeStamp": "1537142400", "value": "196.04" }, + { "UTCDate": "2018-09-18", "unixTimeStamp": "1537228800", "value": "208.39" }, + { "UTCDate": "2018-09-19", "unixTimeStamp": "1537315200", "value": "209.78" }, + { "UTCDate": "2018-09-20", "unixTimeStamp": "1537401600", "value": "224.76" }, + { "UTCDate": "2018-09-21", "unixTimeStamp": "1537488000", "value": "247.69" }, + { "UTCDate": "2018-09-22", "unixTimeStamp": "1537574400", "value": "240.78" }, + { "UTCDate": "2018-09-23", "unixTimeStamp": "1537660800", "value": "244.55" }, + { "UTCDate": "2018-09-24", "unixTimeStamp": "1537747200", "value": "227.92" }, + { "UTCDate": "2018-09-25", "unixTimeStamp": "1537833600", "value": "219.20" }, + { "UTCDate": "2018-09-26", "unixTimeStamp": "1537920000", "value": "214.21" }, + { "UTCDate": "2018-09-27", "unixTimeStamp": "1538006400", "value": "229.09" }, + { "UTCDate": "2018-09-28", "unixTimeStamp": "1538092800", "value": "221.56" }, + { "UTCDate": "2018-09-29", "unixTimeStamp": "1538179200", "value": "231.32" }, + { "UTCDate": "2018-09-30", "unixTimeStamp": "1538265600", "value": "232.60" }, + { "UTCDate": "2018-10-01", "unixTimeStamp": "1538352000", "value": "230.89" }, + { "UTCDate": "2018-10-02", "unixTimeStamp": "1538438400", "value": "225.41" }, + { "UTCDate": "2018-10-03", "unixTimeStamp": "1538524800", "value": "219.97" }, + { "UTCDate": "2018-10-04", "unixTimeStamp": "1538611200", "value": "221.76" }, + { "UTCDate": "2018-10-05", "unixTimeStamp": "1538697600", "value": "227.90" }, + { "UTCDate": "2018-10-06", "unixTimeStamp": "1538784000", "value": "224.62" }, + { "UTCDate": "2018-10-07", "unixTimeStamp": "1538870400", "value": "225.65" }, + { "UTCDate": "2018-10-08", "unixTimeStamp": "1538956800", "value": "229.33" }, + { "UTCDate": "2018-10-09", "unixTimeStamp": "1539043200", "value": "227.49" }, + { "UTCDate": "2018-10-10", "unixTimeStamp": "1539129600", "value": "225.26" }, + { "UTCDate": "2018-10-11", "unixTimeStamp": "1539216000", "value": "189.83" }, + { "UTCDate": "2018-10-12", "unixTimeStamp": "1539302400", "value": "195.97" }, + { "UTCDate": "2018-10-13", "unixTimeStamp": "1539388800", "value": "199.45" }, + { "UTCDate": "2018-10-14", "unixTimeStamp": "1539475200", "value": "194.99" }, + { "UTCDate": "2018-10-15", "unixTimeStamp": "1539561600", "value": "210.80" }, + { "UTCDate": "2018-10-16", "unixTimeStamp": "1539648000", "value": "210.22" }, + { "UTCDate": "2018-10-17", "unixTimeStamp": "1539734400", "value": "207.60" }, + { "UTCDate": "2018-10-18", "unixTimeStamp": "1539820800", "value": "202.49" }, + { "UTCDate": "2018-10-19", "unixTimeStamp": "1539907200", "value": "202.86" }, + { "UTCDate": "2018-10-20", "unixTimeStamp": "1539993600", "value": "205.08" }, + { "UTCDate": "2018-10-21", "unixTimeStamp": "1540080000", "value": "204.77" }, + { "UTCDate": "2018-10-22", "unixTimeStamp": "1540166400", "value": "203.60" }, + { "UTCDate": "2018-10-23", "unixTimeStamp": "1540252800", "value": "203.70" }, + { "UTCDate": "2018-10-24", "unixTimeStamp": "1540339200", "value": "202.92" }, + { "UTCDate": "2018-10-25", "unixTimeStamp": "1540425600", "value": "201.23" }, + { "UTCDate": "2018-10-26", "unixTimeStamp": "1540512000", "value": "203.37" }, + { "UTCDate": "2018-10-27", "unixTimeStamp": "1540598400", "value": "202.79" }, + { "UTCDate": "2018-10-28", "unixTimeStamp": "1540684800", "value": "203.72" }, + { "UTCDate": "2018-10-29", "unixTimeStamp": "1540771200", "value": "195.67" }, + { "UTCDate": "2018-10-30", "unixTimeStamp": "1540857600", "value": "196.19" }, + { "UTCDate": "2018-10-31", "unixTimeStamp": "1540944000", "value": "197.85" }, + { "UTCDate": "2018-11-01", "unixTimeStamp": "1541030400", "value": "198.73" }, + { "UTCDate": "2018-11-02", "unixTimeStamp": "1541116800", "value": "201.02" }, + { "UTCDate": "2018-11-03", "unixTimeStamp": "1541203200", "value": "199.47" }, + { "UTCDate": "2018-11-04", "unixTimeStamp": "1541289600", "value": "211.30" }, + { "UTCDate": "2018-11-05", "unixTimeStamp": "1541376000", "value": "209.70" }, + { "UTCDate": "2018-11-06", "unixTimeStamp": "1541462400", "value": "219.56" }, + { "UTCDate": "2018-11-07", "unixTimeStamp": "1541548800", "value": "217.99" }, + { "UTCDate": "2018-11-08", "unixTimeStamp": "1541635200", "value": "211.29" }, + { "UTCDate": "2018-11-09", "unixTimeStamp": "1541721600", "value": "209.39" }, + { "UTCDate": "2018-11-10", "unixTimeStamp": "1541808000", "value": "211.90" }, + { "UTCDate": "2018-11-11", "unixTimeStamp": "1541894400", "value": "211.70" }, + { "UTCDate": "2018-11-12", "unixTimeStamp": "1541980800", "value": "210.81" }, + { "UTCDate": "2018-11-13", "unixTimeStamp": "1542067200", "value": "206.42" }, + { "UTCDate": "2018-11-14", "unixTimeStamp": "1542153600", "value": "182.72" }, + { "UTCDate": "2018-11-15", "unixTimeStamp": "1542240000", "value": "181.53" }, + { "UTCDate": "2018-11-16", "unixTimeStamp": "1542326400", "value": "174.84" }, + { "UTCDate": "2018-11-17", "unixTimeStamp": "1542412800", "value": "174.22" }, + { "UTCDate": "2018-11-18", "unixTimeStamp": "1542499200", "value": "177.53" }, + { "UTCDate": "2018-11-19", "unixTimeStamp": "1542585600", "value": "148.22" }, + { "UTCDate": "2018-11-20", "unixTimeStamp": "1542672000", "value": "130.74" }, + { "UTCDate": "2018-11-21", "unixTimeStamp": "1542758400", "value": "136.50" }, + { "UTCDate": "2018-11-22", "unixTimeStamp": "1542844800", "value": "124.83" }, + { "UTCDate": "2018-11-23", "unixTimeStamp": "1542931200", "value": "123.37" }, + { "UTCDate": "2018-11-24", "unixTimeStamp": "1543017600", "value": "112.75" }, + { "UTCDate": "2018-11-25", "unixTimeStamp": "1543104000", "value": "116.75" }, + { "UTCDate": "2018-11-26", "unixTimeStamp": "1543190400", "value": "108.87" }, + { "UTCDate": "2018-11-27", "unixTimeStamp": "1543276800", "value": "110.19" }, + { "UTCDate": "2018-11-28", "unixTimeStamp": "1543363200", "value": "122.88" }, + { "UTCDate": "2018-11-29", "unixTimeStamp": "1543449600", "value": "117.48" }, + { "UTCDate": "2018-11-30", "unixTimeStamp": "1543536000", "value": "112.87" }, + { "UTCDate": "2018-12-01", "unixTimeStamp": "1543622400", "value": "118.50" }, + { "UTCDate": "2018-12-02", "unixTimeStamp": "1543708800", "value": "115.96" }, + { "UTCDate": "2018-12-03", "unixTimeStamp": "1543795200", "value": "108.23" }, + { "UTCDate": "2018-12-04", "unixTimeStamp": "1543881600", "value": "109.82" }, + { "UTCDate": "2018-12-05", "unixTimeStamp": "1543968000", "value": "101.57" }, + { "UTCDate": "2018-12-06", "unixTimeStamp": "1544054400", "value": "90.43" }, + { "UTCDate": "2018-12-07", "unixTimeStamp": "1544140800", "value": "93.61" }, + { "UTCDate": "2018-12-08", "unixTimeStamp": "1544227200", "value": "91.44" }, + { "UTCDate": "2018-12-09", "unixTimeStamp": "1544313600", "value": "94.42" }, + { "UTCDate": "2018-12-10", "unixTimeStamp": "1544400000", "value": "90.70" }, + { "UTCDate": "2018-12-11", "unixTimeStamp": "1544486400", "value": "88.05" }, + { "UTCDate": "2018-12-12", "unixTimeStamp": "1544572800", "value": "90.52" }, + { "UTCDate": "2018-12-13", "unixTimeStamp": "1544659200", "value": "86.39" }, + { "UTCDate": "2018-12-14", "unixTimeStamp": "1544745600", "value": "83.90" }, + { "UTCDate": "2018-12-15", "unixTimeStamp": "1544832000", "value": "84.27" }, + { "UTCDate": "2018-12-16", "unixTimeStamp": "1544918400", "value": "85.39" }, + { "UTCDate": "2018-12-17", "unixTimeStamp": "1545004800", "value": "95.44" }, + { "UTCDate": "2018-12-18", "unixTimeStamp": "1545091200", "value": "102.44" }, + { "UTCDate": "2018-12-19", "unixTimeStamp": "1545177600", "value": "100.63" }, + { "UTCDate": "2018-12-20", "unixTimeStamp": "1545264000", "value": "116.43" }, + { "UTCDate": "2018-12-21", "unixTimeStamp": "1545350400", "value": "109.44" }, + { "UTCDate": "2018-12-22", "unixTimeStamp": "1545436800", "value": "118.36" }, + { "UTCDate": "2018-12-23", "unixTimeStamp": "1545523200", "value": "131.56" }, + { "UTCDate": "2018-12-24", "unixTimeStamp": "1545609600", "value": "140.87" }, + { "UTCDate": "2018-12-25", "unixTimeStamp": "1545696000", "value": "130.99" }, + { "UTCDate": "2018-12-26", "unixTimeStamp": "1545782400", "value": "132.61" }, + { "UTCDate": "2018-12-27", "unixTimeStamp": "1545868800", "value": "116.72" }, + { "UTCDate": "2018-12-28", "unixTimeStamp": "1545955200", "value": "139.73" }, + { "UTCDate": "2018-12-29", "unixTimeStamp": "1546041600", "value": "137.30" }, + { "UTCDate": "2018-12-30", "unixTimeStamp": "1546128000", "value": "141.33" }, + { "UTCDate": "2018-12-31", "unixTimeStamp": "1546214400", "value": "133.49" }, + { "UTCDate": "2019-01-01", "unixTimeStamp": "1546300800", "value": "142.66" }, + { "UTCDate": "2019-01-02", "unixTimeStamp": "1546387200", "value": "156.57" }, + { "UTCDate": "2019-01-03", "unixTimeStamp": "1546473600", "value": "149.44" }, + { "UTCDate": "2019-01-04", "unixTimeStamp": "1546560000", "value": "156.04" }, + { "UTCDate": "2019-01-05", "unixTimeStamp": "1546646400", "value": "156.23" }, + { "UTCDate": "2019-01-06", "unixTimeStamp": "1546732800", "value": "158.61" }, + { "UTCDate": "2019-01-07", "unixTimeStamp": "1546819200", "value": "152.09" }, + { "UTCDate": "2019-01-08", "unixTimeStamp": "1546905600", "value": "151.10" }, + { "UTCDate": "2019-01-09", "unixTimeStamp": "1546992000", "value": "151.17" }, + { "UTCDate": "2019-01-10", "unixTimeStamp": "1547078400", "value": "127.96" }, + { "UTCDate": "2019-01-11", "unixTimeStamp": "1547164800", "value": "127.16" }, + { "UTCDate": "2019-01-12", "unixTimeStamp": "1547251200", "value": "125.83" }, + { "UTCDate": "2019-01-13", "unixTimeStamp": "1547337600", "value": "116.56" }, + { "UTCDate": "2019-01-14", "unixTimeStamp": "1547424000", "value": "129.74" }, + { "UTCDate": "2019-01-15", "unixTimeStamp": "1547510400", "value": "121.22" }, + { "UTCDate": "2019-01-16", "unixTimeStamp": "1547596800", "value": "123.12" }, + { "UTCDate": "2019-01-17", "unixTimeStamp": "1547683200", "value": "123.72" }, + { "UTCDate": "2019-01-18", "unixTimeStamp": "1547769600", "value": "120.57" }, + { "UTCDate": "2019-01-19", "unixTimeStamp": "1547856000", "value": "124.85" }, + { "UTCDate": "2019-01-20", "unixTimeStamp": "1547942400", "value": "118.41" }, + { "UTCDate": "2019-01-21", "unixTimeStamp": "1548028800", "value": "116.72" }, + { "UTCDate": "2019-01-22", "unixTimeStamp": "1548115200", "value": "119.12" }, + { "UTCDate": "2019-01-23", "unixTimeStamp": "1548201600", "value": "117.57" }, + { "UTCDate": "2019-01-24", "unixTimeStamp": "1548288000", "value": "117.70" }, + { "UTCDate": "2019-01-25", "unixTimeStamp": "1548374400", "value": "115.92" }, + { "UTCDate": "2019-01-26", "unixTimeStamp": "1548460800", "value": "116.33" }, + { "UTCDate": "2019-01-27", "unixTimeStamp": "1548547200", "value": "112.27" }, + { "UTCDate": "2019-01-28", "unixTimeStamp": "1548633600", "value": "106.36" }, + { "UTCDate": "2019-01-29", "unixTimeStamp": "1548720000", "value": "104.75" }, + { "UTCDate": "2019-01-30", "unixTimeStamp": "1548806400", "value": "109.04" }, + { "UTCDate": "2019-01-31", "unixTimeStamp": "1548892800", "value": "106.89" }, + { "UTCDate": "2019-02-01", "unixTimeStamp": "1548979200", "value": "107.03" }, + { "UTCDate": "2019-02-02", "unixTimeStamp": "1549065600", "value": "111.00" }, + { "UTCDate": "2019-02-03", "unixTimeStamp": "1549152000", "value": "107.21" }, + { "UTCDate": "2019-02-04", "unixTimeStamp": "1549238400", "value": "106.90" }, + { "UTCDate": "2019-02-05", "unixTimeStamp": "1549324800", "value": "106.93" }, + { "UTCDate": "2019-02-06", "unixTimeStamp": "1549411200", "value": "104.50" }, + { "UTCDate": "2019-02-07", "unixTimeStamp": "1549497600", "value": "104.30" }, + { "UTCDate": "2019-02-08", "unixTimeStamp": "1549584000", "value": "119.49" }, + { "UTCDate": "2019-02-09", "unixTimeStamp": "1549670400", "value": "119.46" }, + { "UTCDate": "2019-02-10", "unixTimeStamp": "1549756800", "value": "125.58" }, + { "UTCDate": "2019-02-11", "unixTimeStamp": "1549843200", "value": "120.76" } + ] +} diff --git a/src/transformers/helpers/reqCache.ts b/src/transformers/helpers/reqCache.ts new file mode 100644 index 0000000..68a6c5a --- /dev/null +++ b/src/transformers/helpers/reqCache.ts @@ -0,0 +1,57 @@ +import Web3 from 'web3'; +import _fetch from 'isomorphic-fetch'; + +import { AsyncUtils, StdObj } from '../types'; + +function checkForRateLimitError(resp: StdObj) { + if (JSON.stringify(resp)?.toLowerCase().includes('rate limit')) { + return true; + } + return false; +} + +export async function wrapHttpReqInCache( + getMongoCache: AsyncUtils['getMongoCache'], + url: string, + opts?: { data?: StdObj; headers?: Record } +): Promise { + const cache = await getMongoCache(); + let resp: StdObj; + + const reqHash = Web3.utils.sha3(`${url}-${JSON.stringify(opts?.data)}`); + const existing = await cache.collection('cache').findOne({ reqHash }); + if (existing) { + resp = JSON.parse(existing.response as string) as StdObj; + if (!checkForRateLimitError(resp)) { + return resp; + } + } + + try { + let resp: StdObj; + if (opts?.data) { + resp = (await _fetch(url, { + method: 'POST', + body: JSON.stringify(opts.data), + headers: { 'content-type': 'application/json', ...opts.headers }, + }).then((r) => r.json())) as StdObj; + } else { + resp = (await _fetch(url, { headers: { ...opts?.headers } }).then((r) => r.json())) as StdObj; + } + + await cache + .collection('cache') + .updateOne({ reqHash }, { $set: { response: JSON.stringify(resp) } }, { upsert: true }); + } catch (e) { + if (['invalid argument'].find((msg) => (e as Error).message.includes(msg))) { + return null; + } + throw e; + } + + if (checkForRateLimitError(resp)) { + throw new Error('Hit rate limit for URI'); + } + + return resp; +} diff --git a/src/transformers/helpers/sigMapper.ts b/src/transformers/helpers/sigMapper.ts new file mode 100644 index 0000000..d51b10e --- /dev/null +++ b/src/transformers/helpers/sigMapper.ts @@ -0,0 +1,150 @@ +import { ethers } from 'ethers'; +import { AsyncUtils } from '../types'; + +function sortByValue(obj: Record): [string, string][] { + return Object.entries(obj).sort(([, aVal], [, bVal]) => parseInt(bVal) - parseInt(aVal)); +} + +export function decodeTx(abi: ethers.InterfaceAbi, input: string): ethers.TransactionDescription | undefined { + try { + const iface = new ethers.Interface(abi); + const transactionDescriptor = iface.parseTransaction({ + data: input, + }); + return transactionDescriptor; + } catch (err) { + return undefined; + } +} + +export function decodeEvent( + abi: ethers.InterfaceAbi, + topics: string[], + data: string +): ethers.LogDescription | undefined { + try { + const iface = new ethers.Interface(abi); + const logDescriptor = iface.parseLog({ + topics, + data, + }); + return logDescriptor; + } catch (err) { + return undefined; + } +} + +export async function decodeTransaction( + address: string, + input: string, + abiUtils: AsyncUtils['abi'] +): Promise { + // if input is nothing + if (input === '0x' || !input) return null; + + let abi: ethers.InterfaceAbi; + // check if contract is proxy, if yes, get implementation address + const implementationAddress = await abiUtils.getProxyImplementations(address); + if (implementationAddress?.length > 0) { + // grab abis from proxy implementations + const abiPromises = implementationAddress.map((addr) => abiUtils.get(addr)); + const abis = await Promise.all(abiPromises); + const uniqueAbiSet = new Set(abis.flat().map((ele) => JSON.stringify(ele))); + abi = Array.from(uniqueAbiSet).map((ele) => JSON.parse(ele) as string | ethers.Fragment | ethers.JsonFragment); + } else { + // fetch abi from address + abi = await abiUtils.get(address); + } + + if (abi) { + // decode with abi + try { + const transactionDescriptor = decodeTx(abi, input); + if (transactionDescriptor) { + return transactionDescriptor; + } + } catch (e) { + // ignore this for now + } + } + + // decode with hash + const sigHash = input.slice(0, 10); + const allMatchingFunctionVariants = await abiUtils.getHashMap(sigHash); + if (Object.keys(allMatchingFunctionVariants).length === 0) { + return undefined; + } + + const sortedFunctions = sortByValue(allMatchingFunctionVariants); + for (const functionHash of sortedFunctions) { + try { + const transactionDescriptor = decodeTx([`function ${functionHash[0]}`], input); + // if its correct hash + if (transactionDescriptor) { + return transactionDescriptor; + } + } catch (e) { + // ignore this for now + } + } + + return undefined; +} + +export async function decodeLog( + address: string, + topics: string[], + data: string, + abiUtils: AsyncUtils['abi'] +): Promise { + if (topics.length === 0) { + return null; + } + let abi: ethers.InterfaceAbi; + // check if contract is proxy, if yes, get implementation address + const implementationAddress = await abiUtils.getProxyImplementations(address); + if (implementationAddress?.length > 0) { + // grab abis from proxy implementations + const abiPromises = implementationAddress.map((addr) => abiUtils.get(addr)); + const abis = await Promise.all(abiPromises); + const uniqueAbiSet = new Set(abis.flat().map((ele) => JSON.stringify(ele))); + abi = Array.from(uniqueAbiSet).map((ele) => JSON.parse(ele) as string | ethers.Fragment | ethers.JsonFragment); + } else { + // fetch abi from address + abi = await abiUtils.get(address); + } + if (abi) { + // decode with abi + try { + const logDescriptor = decodeEvent(abi, topics, data); + if (logDescriptor) { + return logDescriptor; + } + } catch (e) { + // ignore this for now + } + } + + // decode with hash + const eventHash = topics[0]; + const eventSigResult = await abiUtils.getHashMap(eventHash); + const eventSig = Object.keys(eventSigResult)[0]; + const allMatchingEventVariants = await abiUtils.getHashMap(eventSig); + if (Object.keys(allMatchingEventVariants).length === 0) { + return undefined; + } + + const sortedEvents = sortByValue(allMatchingEventVariants); + for (const event of sortedEvents) { + try { + const logDescriptor = decodeEvent([`event ${event[0]}`], topics, data); + if (logDescriptor) { + return logDescriptor; + } + } catch (e) { + // ignore this for now + } + } + + return undefined; +} diff --git a/src/transformers/helpers/utils.ts b/src/transformers/helpers/utils.ts new file mode 100644 index 0000000..3f0f308 --- /dev/null +++ b/src/transformers/helpers/utils.ts @@ -0,0 +1,208 @@ +/* eslint-disable @typescript-eslint/no-unsafe-return */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +/* eslint-disable @typescript-eslint/no-unsafe-call */ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +import BigNumber from 'bignumber.js'; +import { ethers } from 'ethers'; +import { EVM } from 'evm'; + +import { + ERC20_METHODS, + ERC777_METHODS, + ERC721_METHODS, + ERC1155_METHODS, + ERC165_METHODS, + GOVERNOR_METHODS, + SAFE_METHODS, + PROXY_IMPLEMENTATION_METHODS, +} from './constants'; +import { AsyncUtils, RawBlock, StdObj, TransactionDescription } from '../types'; + +// this configuration helps us handle wei -> integer -> string conversions being in scientific notation +// (we don't want scientific notation) +BigNumber.config({ EXPONENTIAL_AT: 1000 }); + +// monkey-patch BigInt to serialize as JSON +// more context here: https://github.com/GoogleChromeLabs/jsbi/issues/30 +(BigInt.prototype as any).toJSON = function () { + return this.toString(); +}; + +export const toBigNumber = (v: unknown) => new BigNumber(v as string); + +export const bytecodeIsERC = (standard: Record, bytecode: string): boolean => { + const ercMethodsDetected = Object.keys(standard).filter((key: string): boolean => bytecode.includes(standard[key])); + return ercMethodsDetected.length == Object.keys(standard).length; +}; + +export const bytecodeIsERC20 = (bytecode: string): boolean => bytecodeIsERC(ERC20_METHODS, bytecode); +export const bytecodeIsERC777 = (bytecode: string): boolean => bytecodeIsERC(ERC777_METHODS, bytecode); +export const bytecodeIsERC721 = (bytecode: string): boolean => bytecodeIsERC(ERC721_METHODS, bytecode); +export const bytecodeIsERC1155 = (bytecode: string): boolean => bytecodeIsERC(ERC1155_METHODS, bytecode); +export const bytecodeIsERC165 = (bytecode: string): boolean => bytecodeIsERC(ERC165_METHODS, bytecode); +export const bytecodeIsIGovernor = (bytecode: string): boolean => bytecodeIsERC(GOVERNOR_METHODS, bytecode); +export const bytecodeIsGnosisSafe = (bytecode: string): boolean => bytecodeIsERC(SAFE_METHODS, bytecode); + +export const normalizeBlock = (block: StdObj): RawBlock => { + // console.log('block', block); + + let str = JSON.stringify(block); + + // replace all EVM addresses with lowercased versions + str = str.replace(/("0x[A-z0-9]{40}")/g, (v) => v.toLowerCase()); + + return JSON.parse(str) as RawBlock; +}; + +export function decodeEVMAddress(addressString: string): string { + if (!addressString) return ''; + + const buf = Buffer.from(addressString.replace(/^0x/, ''), 'hex'); + if (!buf.slice(0, 12).equals(Buffer.alloc(12, 0))) { + return ''; + } + const address = '0x' + buf.toString('hex', 12, 32); // grab the last 20 bytes + return address.toLocaleLowerCase(); +} + +export const hexToString = (str: string) => { + const buf = Buffer.from(str, 'hex'); + return buf.toString('utf8'); +}; + +const VALID_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890.? '; + +export const countValidChars = (stringToCount: string) => { + let count = 0; + for (let i = 0; i < stringToCount.length; i++) { + if (VALID_CHARS.indexOf(stringToCount[i]) >= 0) { + count++; + } + } + return count; +}; + +export const convertToString = (value: any): string => { + // Check if the value is not null or undefined, and it has a toString() method. + if (value !== null && value !== undefined && typeof value?.toString === 'function') { + return value.toString(); + } else { + // Return an empty string if the value is not convertible to a string. + return ''; + } +}; + +export function splitStringIntoChunks(inputString: string, chunkSize: number): string[] { + const chunks: string[] = []; + for (let i = 0; i < inputString.length; i += chunkSize) { + chunks.push(inputString.slice(i, i + chunkSize)); + } + return chunks; +} + +export function convertBNToStringInTx(decodeResult: ethers.TransactionDescription): TransactionDescription { + let txDecode; + if (decodeResult) { + try { + txDecode = { + ...decodeResult, + value: decodeResult.value.toString(), + fragment: { + ...decodeResult.fragment, + gas: decodeResult.fragment.gas ? decodeResult.fragment.gas.toString() : null, + }, + args: decodeResult.args.map((arg) => convertToString(arg)), + }; + } catch (e) { + // ignore deferred ethers error + } + } + + return txDecode; +} + +export function objectToDotNotation(obj: Record, current?: string) { + if (!obj || typeof obj !== 'object') { + return obj; + } + + const newObj = {}; + + for (const key in obj) { + const val = obj[key]; + const newKey = current ? `${current}.${key}` : key; + if (val && typeof val === 'object') { + Object.assign(newObj, objectToDotNotation(val as Record, newKey)); + } else { + newObj[newKey] = val; + } + } + + return newObj; +} +/** + * Detect custom proxy and its implementation. + * @param address The Ethereum address to check. + * @param web3Provider The provider for web3 interactions. + * @returns The target address if found, otherwise an empty string. + */ +export async function detectCustomProxy(address: string, web3Provider: AsyncUtils['web3Provider']): Promise { + // Retrieve the bytecode of the given address + const code = await web3Provider.getCode(address); + const evm = new EVM(code); + const opcodes = evm.getOpcodes(); + + // Check if bytecode contains DELEGATECALL + const hasDelegateCall = opcodes.some((opcode) => opcode.name === 'DELEGATECALL'); + + // Retrieve potential proxy implementations + const implementations: string[] = await Promise.all( + Object.values(PROXY_IMPLEMENTATION_METHODS).map(async (method) => { + try { + return await web3Provider.send('eth_call', [ + { + to: address, + data: `0x${method}`, + }, + ]); + } catch (error) { + return ''; + } + }) + ); + + // Search for a valid implementation address + const target = + implementations + .map((implementation) => decodeEVMAddress(implementation)) + .find((implementation) => implementation && ethers.isAddress(implementation)) || ''; + + return hasDelegateCall && target ? target : ''; +} + +export const getTokenName = async (token): Promise => { + try { + return (await token.methods.name().call()) as string; + } catch (error) { + console.log(`Name method not implemented.`); + return ''; + } +}; + +export const getTokenSymbol = async (token): Promise => { + try { + return (await token.methods.symbol().call()) as string; + } catch (error) { + console.log('Symbol method not implemented.'); + return ''; + } +}; + +export const getTokenDecimals = async (token): Promise => { + try { + return (await token.methods.decimals().call()) as number; + } catch (error) { + console.log('Decimals method not implemented.'); + return 18; + } +}; diff --git a/src/transformers/types.ts b/src/transformers/types.ts new file mode 100644 index 0000000..4b051d5 --- /dev/null +++ b/src/transformers/types.ts @@ -0,0 +1,380 @@ +// import { ethers } from 'ethers'; +export type StdObj = Record; + +// INTERFACES + +export type Config = { + async: boolean; + chains?: string[]; + checkMethod?: string; + method: string; + outputModel: 'block' | 'transaction'; + outputSource: 'json'; + phaseName: string; + rateLimit?: number; // measured in requests per second + sourcePhase: string; +}; + + +// PAYLOAD TYPES + +export type AssetTransfer = { + asset?: string; // === 'contractAddress' + burn?: boolean; + from: string; + mint?: boolean; + to: string; + tokenId?: string; + value?: string; + type: 'erc20' | 'erc721' | 'erc1155' | 'eth'; +}; + +export type NetAssetTransfer = { + asset: string; + from?: string; + to?: string; + id: string; + tokenId?: string; + type: AssetTransfer['type']; + value: string; +}; + +export type NetAssetTransfers = Record; + +export type RawBlock = StdObj & { + chainId?: number; + number: number; + timestamp: number; + transactions: RawTransaction[]; +}; + +export type RawLog = StdObj & { + address: string; + data: string; + logIndex: number; + topics: string[]; + decode?: LogDescription; +}; + +export type RawReceipt = StdObj & { + logs: RawLog[]; +}; + +export type RawTransaction = StdObj & { + accessList?: StdObj[]; + blockNumber: number; + from: string; + hash: string; + input: string; + value: string; + receipt: RawReceipt; + to: string; + traces: RawTrace[]; + contracts?: Contract[]; + decode?: TransactionDescription; + context: TxContext; + assetTransfers: AssetTransfer[]; + netAssetTransfers: NetAssetTransfers; +}; + +export type RawTraceAction = StdObj & { + address: string; + balance?: string; + callType?: string; + from: string; + refundAddress?: string; + to?: string; + value?: string; + input?: string; +}; + +export type RawTraceResult = StdObj & { + address?: string; + code: string; + hash: string; + receipt: StdObj; + to: string; + traces: RawTrace[]; + transactionIndex: number; +}; + +export type RawTrace = StdObj & { + action: RawTraceAction; + blockNumber: number; + blockhash: string; + error?: string; + result: RawTraceResult; + subtraces: number; + traceAddress: number[]; + transactionHash: string; + transactionPosition: number; + type: string; + decode?: TransactionDescription; +}; + +export type SupportedInterfaces = Record; + +export type ContractMetadata = { + isUniswapV3: boolean; + isUniswapV2: boolean; + isUniswapV1: boolean; + uniswapPairs: string[]; + isPropHouseToken: boolean; + isPropHouseMetadata: boolean; + isPropHouseAuction: boolean; + isPropHouseTreasury: boolean; + isPropHouseGovernor: boolean; + isGenericGovernance: boolean; + isGnosisSafe: boolean; + + alchemy?: StdObj; + coingecko?: StdObj; + etherscan?: StdObj; + opensea?: StdObj; + simplehash?: StdObj; + tally?: TallyMetadata; + whatsAbiSelectors: string[]; + // whatsAbiAbi: ethers.InterfaceAbi; + isProxy: boolean; + implementationAddress?: string; + tokenMetadata?: TokenMetadata; +}; + +export type UniswapPair = { + address: string; + tokens: string[]; +}; + +export type Contract = { + chainId?: number; + deployer: string; + directDeployer: string; + address: string; + bytecode: string; + fingerprint: string; + gas: unknown; // TOOD - do we convert with bignumber here? + gasUsed: unknown; // TODO - do we convert with bignumber here? + blockNumber: number; + transactionHash: string; + type: 'create' | 'create2'; + metadata?: ContractMetadata; + supportedInterfaces?: SupportedInterfaces; + sigHash: string; + internalSigHashes: string[]; + transactionIndex: number; + traceIndex: number; + ethTransfer: boolean; + timestamp: number; + isoTimestamp: string; +}; + +export type TokenStandard = 'erc20' | 'erc721' | 'erc777' | 'erc1155' | ''; + +export type TokenMetadata = { + tokenStandard: TokenStandard; + name?: string; + symbol?: string; + decimals?: number; +}; + +/** ABI */ + +export type AbiType = 'function' | 'constructor' | 'event' | 'fallback' | 'receive'; +export type StateMutabilityType = 'pure' | 'view' | 'nonpayable' | 'payable'; + +export interface AbiItem { + anonymous?: boolean; + constant?: boolean; + inputs?: AbiInput[]; + name?: string; + outputs?: AbiOutput[]; + payable?: boolean; + stateMutability?: StateMutabilityType; + type: AbiType; + gas?: number; +} + +export interface AbiInput { + name: string; + type: string; + indexed?: boolean; + components?: AbiInput[]; + internalType?: string; +} + +export interface AbiOutput { + name: string; + type: string; + components?: AbiOutput[]; + internalType?: string; +} + +export type TransactionContract = { + hash: string; + contracts: Contract[]; +}; + +export type transactionAssetTransfers = { + hash: string; + assetTransfers: AssetTransfer[]; +}; + +export type InternalHashType = { + sigHash: string; + from: string; + to: string; +}; + +export type TransactionWithHash = { + hash: string; + sigHash: string; + internalSigHashes: InternalHashType[]; +}; + +export type TransactionDescription = { + fragment: { + name: string; + // type: ethers.FragmentType; + // inputs: ReadonlyArray; + // outputs: ReadonlyArray; + constant: boolean; + stateMutability: 'payable' | 'nonpayable' | 'view' | 'pure'; + payable: boolean; + gas: null | string; + }; + name: string; + args: string[]; + signature: string; + selector: string; + value: string; +}; + +export type LogDescription = { + fragment: { + name: string; + // type: ethers.FragmentType; + // inputs: ReadonlyArray; + anonymous: boolean; + }; + name: string; + signature: string; + args: string[]; + topic: string; +}; + +export type DecodeStatistics = { + totalLogs: number; + parsedLogs: number; + totalTraces: number; + parsedTraces: number; + isParsed: boolean; +}; + +export type TransactionDecode = { + hash: string; + decode?: TransactionDescription; + receipt?: RawReceipt; + traces?: RawTrace[]; +}; + +export type TransactionWithIDM = { + hash: string; + idm: boolean; +}; + +export type PropHouseDao = { + token: string; + metadata: string; + auction: string; + treasury: string; + governor: string; +}; + +export type TallyGovernorAPIResponse = { + data: { + governors: TallyMetadata[]; + }; +}; + +export type TallyMetadata = { + type: string; + name: string; + quorum: string; + timelockId: string; + parameters: { + quorumVotes: string; + proposalThreshold: string; + votingDelay: string; + votingPeriod: string; + quorumNumerator: string; + quorumDenominator: string; + }; + proposalStats: { + total: number; + active: number; + failed: number; + passed: number; + }; + tokens: [ + { + id: string; + type: string; + address: string; + name: string; + symbol: string; + supply: string; + lastBlock: number; + decimals: number; + } + ]; + slug: string; +}; + +export type AddressInteractedWith = { + hash: string; + addressInteractedWith: { + address: string; + interactedWith: string; + }; +}; + +export type AddressesPartiedWith = { + hash: string; + addressesPartiedWith: { + address: string; + interactedWith: string; + }[]; +}; + +export type Neighbor = { + hash: string; + neighbor: { + address: string; + neighbor: string; + }; +}; + +export type TransactionWithContext = { + hash: string; + context: TxContext; +}; + +export type TxContextValueType = { + type: string; + value: string; +}; + +export type TxContext = { + type: string; +}; + +export type TransactionDecodeGnosisSafe = { + hash: string; + decodeGnosis?: GnosisSafeDecode; +}; + +export type GnosisSafeDecode = { + target: string; + data: string; + decode: TransactionDescription; +}; From 1da57d9299e43783bfb5b3b5361c2bc07ec1cf4e Mon Sep 17 00:00:00 2001 From: ponyjackal Date: Thu, 25 Jan 2024 09:03:26 -0800 Subject: [PATCH 2/9] feat: add types --- src/types/assetTransfer.ts | 12 +++++ src/types/block.ts | 10 ++++ src/types/contract.ts | 97 +++++++++++++++++++++++++++++++++++ src/types/index.ts | 9 +++- src/types/log.ts | 26 ++++++++++ src/types/netAssetTransfer.ts | 13 +++++ src/types/shared.ts | 3 ++ src/types/transaction.ts | 79 ++++++++++++++++++++++++++++ 8 files changed, 247 insertions(+), 2 deletions(-) create mode 100644 src/types/assetTransfer.ts create mode 100644 src/types/block.ts create mode 100644 src/types/contract.ts create mode 100644 src/types/log.ts create mode 100644 src/types/netAssetTransfer.ts create mode 100644 src/types/shared.ts create mode 100644 src/types/transaction.ts diff --git a/src/types/assetTransfer.ts b/src/types/assetTransfer.ts new file mode 100644 index 0000000..cc56fe9 --- /dev/null +++ b/src/types/assetTransfer.ts @@ -0,0 +1,12 @@ +import {AssetType} from "./shared" + +export type AssetTransfer = { + asset?: string; // === 'contractAddress' + burn?: boolean; + from: string; + mint?: boolean; + to: string; + tokenId?: string; + value?: string; + type: AssetType; +}; \ No newline at end of file diff --git a/src/types/block.ts b/src/types/block.ts new file mode 100644 index 0000000..4322bb8 --- /dev/null +++ b/src/types/block.ts @@ -0,0 +1,10 @@ +import {StdObj} from "./shared" +import {RawTransaction} from "./transaction" + +export type RawBlock = StdObj & { + chainId?: number; + number: number; + timestamp: number; + transactions: RawTransaction[]; + }; + \ No newline at end of file diff --git a/src/types/contract.ts b/src/types/contract.ts new file mode 100644 index 0000000..307c0b8 --- /dev/null +++ b/src/types/contract.ts @@ -0,0 +1,97 @@ + +import {StdObj} from "./shared" + +export type Contract = { + chainId?: number; + deployer: string; + directDeployer: string; + address: string; + bytecode: string; + fingerprint: string; + gas: unknown; // TOOD - do we convert with bignumber here? + gasUsed: unknown; // TODO - do we convert with bignumber here? + blockNumber: number; + transactionHash: string; + type: 'create' | 'create2'; + metadata?: ContractMetadata; + supportedInterfaces?: SupportedInterfaces; + sigHash: string; + internalSigHashes: string[]; + transactionIndex: number; + traceIndex: number; + ethTransfer: boolean; + timestamp: number; + isoTimestamp: string; +}; + +export type ContractMetadata = { + isUniswapV3: boolean; + isUniswapV2: boolean; + isUniswapV1: boolean; + uniswapPairs: string[]; + isPropHouseToken: boolean; + isPropHouseMetadata: boolean; + isPropHouseAuction: boolean; + isPropHouseTreasury: boolean; + isPropHouseGovernor: boolean; + isGenericGovernance: boolean; + isGnosisSafe: boolean; + + alchemy?: StdObj; + coingecko?: StdObj; + etherscan?: StdObj; + opensea?: StdObj; + simplehash?: StdObj; + tally?: TallyMetadata; + whatsAbiSelectors: string[]; + // whatsAbiAbi: ethers.InterfaceAbi; + isProxy: boolean; + implementationAddress?: string; + tokenMetadata?: TokenMetadata; +}; + +export type SupportedInterfaces = Record; + + +export type TallyMetadata = { + type: string; + name: string; + quorum: string; + timelockId: string; + parameters: { + quorumVotes: string; + proposalThreshold: string; + votingDelay: string; + votingPeriod: string; + quorumNumerator: string; + quorumDenominator: string; + }; + proposalStats: { + total: number; + active: number; + failed: number; + passed: number; + }; + tokens: [ + { + id: string; + type: string; + address: string; + name: string; + symbol: string; + supply: string; + lastBlock: number; + decimals: number; + } + ]; + slug: string; +}; + +export type TokenStandard = 'erc20' | 'erc721' | 'erc777' | 'erc1155' | ''; + +export type TokenMetadata = { + tokenStandard: TokenStandard; + name?: string; + symbol?: string; + decimals?: number; +}; \ No newline at end of file diff --git a/src/types/index.ts b/src/types/index.ts index d20a0df..df39353 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,2 +1,7 @@ -// export * from './rawTransaction'; -// export * from './usableTransaction'; \ No newline at end of file +export * from "./assetTransfer" +export * from "./block" +export * from "./contract" +export * from "./log" +export * from "./netAssetTransfer" +export * from "./shared" +export * from "./transaction" \ No newline at end of file diff --git a/src/types/log.ts b/src/types/log.ts new file mode 100644 index 0000000..00eafcf --- /dev/null +++ b/src/types/log.ts @@ -0,0 +1,26 @@ +import {StdObj} from "./shared" + +export type LogDescription = { + fragment: { + name: string; + // type: ethers.FragmentType; + // inputs: ReadonlyArray; + anonymous: boolean; + }; + name: string; + signature: string; + args: string[]; + topic: string; +}; + +export type RawLog = StdObj & { + address: string; + data: string; + logIndex: number; + topics: string[]; + decode?: LogDescription; + }; + +export type RawReceipt = StdObj & { + logs: RawLog[]; +}; \ No newline at end of file diff --git a/src/types/netAssetTransfer.ts b/src/types/netAssetTransfer.ts new file mode 100644 index 0000000..e09d4c6 --- /dev/null +++ b/src/types/netAssetTransfer.ts @@ -0,0 +1,13 @@ +import {AssetType} from "./shared" + +export type NetAssetTransfer = { + asset: string; + from?: string; + to?: string; + id: string; + tokenId?: string; + type: AssetType; + value: string; +}; + +export type NetAssetTransfers = Record; diff --git a/src/types/shared.ts b/src/types/shared.ts new file mode 100644 index 0000000..f0a0f3a --- /dev/null +++ b/src/types/shared.ts @@ -0,0 +1,3 @@ +export type StdObj = Record; + +export type AssetType = 'erc20' | 'erc721' | 'erc1155' | 'eth'; diff --git a/src/types/transaction.ts b/src/types/transaction.ts new file mode 100644 index 0000000..3bc4466 --- /dev/null +++ b/src/types/transaction.ts @@ -0,0 +1,79 @@ +import {StdObj} from "./shared" +import {AssetTransfer} from "./assetTransfer" +import {NetAssetTransfers} from "./netAssetTransfer" +import {RawReceipt} from "./log" +import { Contract } from "./contract" + +export type RawTransaction = StdObj & { + accessList?: StdObj[]; + blockNumber: number; + from: string; + hash: string; + input: string; + value: string; + receipt: RawReceipt; + to: string; + traces: RawTrace[]; + contracts?: Contract[]; + decode?: TransactionDescription; + context: TxContext; + assetTransfers: AssetTransfer[]; + netAssetTransfers: NetAssetTransfers; +}; + +export type RawTraceAction = StdObj & { + address: string; + balance?: string; + callType?: string; + from: string; + refundAddress?: string; + to?: string; + value?: string; + input?: string; +}; + +export type RawTraceResult = StdObj & { + address?: string; + code: string; + hash: string; + receipt: StdObj; + to: string; + traces: RawTrace[]; + transactionIndex: number; +}; + +export type RawTrace = StdObj & { + action: RawTraceAction; + blockNumber: number; + blockhash: string; + error?: string; + result: RawTraceResult; + subtraces: number; + traceAddress: number[]; + transactionHash: string; + transactionPosition: number; + type: string; + decode?: TransactionDescription; +}; + +export type TransactionDescription = { + fragment: { + name: string; + // type: ethers.FragmentType; + // inputs: ReadonlyArray; + // outputs: ReadonlyArray; + constant: boolean; + stateMutability: 'payable' | 'nonpayable' | 'view' | 'pure'; + payable: boolean; + gas: null | string; + }; + name: string; + args: string[]; + signature: string; + selector: string; + value: string; +}; + +export type TxContext = { + type: string; +}; \ No newline at end of file From c5b1da12fb3ddbbed4f530527d729142d489b1e9 Mon Sep 17 00:00:00 2001 From: ponyjackal Date: Thu, 25 Jan 2024 09:11:07 -0800 Subject: [PATCH 3/9] feat: mv helper utils --- package-lock.json | 342 ++++- package.json | 3 +- src/{transformers => }/helpers/constants.ts | 91 +- src/helpers/utils.ts | 172 ++- .../_common/transactionAssetTransfers.ts | 2 +- .../_common/transactionProxyUpgrades.ts | 2 +- src/transformers/ethereum/blockFork.ts | 2 +- .../ethereum/contractPropHouseDetection.ts | 2 +- .../ethereum/contractUniswapDetection.ts | 2 +- .../transactionAssetTransfersOldNFTs.ts | 2 +- src/transformers/ethereum/transactionFees.ts | 2 +- src/transformers/ethereum/transactionForks.ts | 2 +- .../helpers/etherscan_prices.json | 1299 ----------------- src/transformers/helpers/reqCache.ts | 57 - src/transformers/helpers/sigMapper.ts | 150 -- src/transformers/helpers/utils.ts | 208 --- src/transformers/types.ts | 380 ----- src/types/assetTransfer.ts | 20 +- src/types/block.ts | 15 +- src/types/contract.ts | 162 +- src/types/index.ts | 14 +- src/types/log.ts | 36 +- src/types/netAssetTransfer.ts | 21 +- src/types/shared.ts | 36 + src/types/transaction.ts | 126 +- 25 files changed, 801 insertions(+), 2347 deletions(-) rename src/{transformers => }/helpers/constants.ts (85%) delete mode 100644 src/transformers/helpers/etherscan_prices.json delete mode 100644 src/transformers/helpers/reqCache.ts delete mode 100644 src/transformers/helpers/sigMapper.ts delete mode 100644 src/transformers/helpers/utils.ts delete mode 100644 src/transformers/types.ts diff --git a/package-lock.json b/package-lock.json index 1a9ec9d..5f511b2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,8 @@ "dotenv": "^16.3.1", "handlebars": "^4.7.8", "path": "^0.12.7", - "viem": "^1.19.13" + "viem": "^1.19.13", + "web3-utils": "^4.1.1" }, "devDependencies": { "@types/jest": "^29.5.8", @@ -1858,6 +1859,17 @@ "node": ">=8" } }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/babel-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", @@ -2060,6 +2072,19 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, + "node_modules/call-bind": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "dependencies": { + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -2293,6 +2318,19 @@ "node": ">=0.10.0" } }, + "node_modules/define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "dependencies": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -2619,6 +2657,64 @@ "node": ">=0.10.0" } }, + "node_modules/ethereum-cryptography": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.1.3.tgz", + "integrity": "sha512-BlwbIL7/P45W8FGW2r7LGuvoEZ+7PWsniMvQ4p5s2xCyw9tmaDlpfsN9HjAucbF+t/qpVHwZUisgfK24TCW8aA==", + "dependencies": { + "@noble/curves": "1.3.0", + "@noble/hashes": "1.3.3", + "@scure/bip32": "1.3.3", + "@scure/bip39": "1.2.2" + } + }, + "node_modules/ethereum-cryptography/node_modules/@noble/curves": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.3.0.tgz", + "integrity": "sha512-t01iSXPuN+Eqzb4eBX0S5oubSqXbK/xXa1Ne18Hj8f9pStxztHCE2gfboSp/dZRLSqfuLpRK2nDXDK+W9puocA==", + "dependencies": { + "@noble/hashes": "1.3.3" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ethereum-cryptography/node_modules/@noble/hashes": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.3.tgz", + "integrity": "sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ethereum-cryptography/node_modules/@scure/bip32": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.3.tgz", + "integrity": "sha512-LJaN3HwRbfQK0X1xFSi0Q9amqOgzQnnDngIt+ZlsBC3Bm7/nE7K0kwshZHyaru79yIVRv/e1mQAjZyuZG6jOFQ==", + "dependencies": { + "@noble/curves": "~1.3.0", + "@noble/hashes": "~1.3.2", + "@scure/base": "~1.1.4" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ethereum-cryptography/node_modules/@scure/bip39": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.2.tgz", + "integrity": "sha512-HYf9TUXG80beW+hGAt3TRM8wU6pQoYur9iNypTROm42dorCGmLnFe3eWjz3gOq6G62H2WRh0FCzAR1PI+29zIA==", + "dependencies": { + "@noble/hashes": "~1.3.2", + "@scure/base": "~1.1.4" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -2797,6 +2893,14 @@ "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", "dev": true }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dependencies": { + "is-callable": "^1.1.3" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -2821,7 +2925,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -2844,6 +2947,20 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-intrinsic": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "dependencies": { + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/get-package-type": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", @@ -2954,6 +3071,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -2995,11 +3123,57 @@ "node": ">=8" } }, + "node_modules/has-property-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "dependencies": { + "get-intrinsic": "^1.2.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/hasown": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", - "dev": true, "dependencies": { "function-bind": "^1.1.2" }, @@ -3088,8 +3262,22 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/is-arrayish": { "version": "0.2.1", @@ -3097,6 +3285,17 @@ "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "dev": true }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-core-module": { "version": "2.13.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", @@ -3136,6 +3335,20 @@ "node": ">=6" } }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -3178,6 +3391,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dependencies": { + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -4639,6 +4866,21 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "node_modules/set-function-length": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.0.tgz", + "integrity": "sha512-4DBHDoyHlM1IRPGYcoxexgh67y4ueR53FKV1yyxwFMY7aCqcN/38M1+SwZ/qJQ8iLv7+ck385ot4CcisOAPT9w==", + "dependencies": { + "define-data-property": "^1.1.1", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.2", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -5133,6 +5375,70 @@ "makeerror": "1.0.12" } }, + "node_modules/web3-errors": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/web3-errors/-/web3-errors-1.1.4.tgz", + "integrity": "sha512-WahtszSqILez+83AxGecVroyZsMuuRT+KmQp4Si5P4Rnqbczno1k748PCrZTS1J4UCPmXMG2/Vt+0Bz2zwXkwQ==", + "dependencies": { + "web3-types": "^1.3.1" + }, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/web3-types/-/web3-types-1.3.1.tgz", + "integrity": "sha512-8fXi7h/t95VKRtgU4sxprLPZpsTh3jYDfSghshIDBgUD/OoGe5S+syP24SUzBZYllZ/L+hMr2gdp/0bGJa8pYQ==", + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-utils": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-4.1.1.tgz", + "integrity": "sha512-5AOmLKH6QuwHunLCNdVFlPSDE+T88bJYRQP+HWYoKNbI4STALCYQiJvj7LXE+Ed6cPfqANaK/LwKNbMPLCPFwA==", + "dependencies": { + "ethereum-cryptography": "^2.0.0", + "web3-errors": "^1.1.4", + "web3-types": "^1.3.1", + "web3-validator": "^2.0.4" + }, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-validator": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/web3-validator/-/web3-validator-2.0.4.tgz", + "integrity": "sha512-qRxVePwdW+SByOmTpDZFWHIUAa7PswvxNszrOua6BoGqAhERo5oJZBN+EbWtK/+O+ApNxt5FR3nCPmiZldiOQA==", + "dependencies": { + "ethereum-cryptography": "^2.0.0", + "util": "^0.12.5", + "web3-errors": "^1.1.4", + "web3-types": "^1.3.1", + "zod": "^3.21.4" + }, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-validator/node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -5148,6 +5454,24 @@ "node": ">= 8" } }, + "node_modules/which-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", + "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.4", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", @@ -5262,6 +5586,14 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zod": { + "version": "3.22.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", + "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } } } } diff --git a/package.json b/package.json index 206b153..7fe5c5f 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "dotenv": "^16.3.1", "handlebars": "^4.7.8", "path": "^0.12.7", - "viem": "^1.19.13" + "viem": "^1.19.13", + "web3-utils": "^4.1.1" } } diff --git a/src/transformers/helpers/constants.ts b/src/helpers/constants.ts similarity index 85% rename from src/transformers/helpers/constants.ts rename to src/helpers/constants.ts index ea7323a..7b28f81 100644 --- a/src/transformers/helpers/constants.ts +++ b/src/helpers/constants.ts @@ -109,7 +109,9 @@ export const ERC1155_METHOD_SIGNATURES = [ 'safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)', ]; -export const ERC1155_METHODS = createSignatureMapping(ERC1155_METHOD_SIGNATURES); +export const ERC1155_METHODS = createSignatureMapping( + ERC1155_METHOD_SIGNATURES, +); //https://eips.ethereum.org/EIPS/eip-165 export const ERC165_METHOD_SIGNATURES = ['supportsInterface(bytes4)']; @@ -118,8 +120,11 @@ export const ERC165_METHODS = createSignatureMapping(ERC165_METHOD_SIGNATURES); // Contract Addresses export const OPENSEA_REGISTRY_SIGNATURES = ['registerProxy()']; -export const OPENSEA_REGISTRY_METHODS = createSignatureMapping(OPENSEA_REGISTRY_SIGNATURES); -export const OPENSEA_REGISTRY_ADDRESS = '0xa5409ec958c83c3f309868babaca7c86dcb077c1'; +export const OPENSEA_REGISTRY_METHODS = createSignatureMapping( + OPENSEA_REGISTRY_SIGNATURES, +); +export const OPENSEA_REGISTRY_ADDRESS = + '0xa5409ec958c83c3f309868babaca7c86dcb077c1'; // Gnosis Safe export const GNOSIS_SAFE_FACTORY_METHOD_SIGNATURES = [ @@ -128,13 +133,20 @@ export const GNOSIS_SAFE_FACTORY_METHOD_SIGNATURES = [ 'createProxyWithCallback(address,bytes,uint256,address)', ]; -export const GNOSIS_SAFE_FACTORY_METHODS = createSignatureMapping(GNOSIS_SAFE_FACTORY_METHOD_SIGNATURES); +export const GNOSIS_SAFE_FACTORY_METHODS = createSignatureMapping( + GNOSIS_SAFE_FACTORY_METHOD_SIGNATURES, +); -export const GNOSIS_SAFE_FACTORY_0_1_0_ADDRESS = '0x88cd603a5dc47857d02865bbc7941b588c533263'; // Not used often -export const GNOSIS_SAFE_FACTORY_1_0_0_ADDRESS = '0x12302fe9c02ff50939baaaaf415fc226c078613c'; // This release appears to have been buggy and didn't deploy contracts often -export const GNOSIS_SAFE_FACTORY_1_0_1_ADDRESS = '0x50e55af101c777ba7a1d560a774a82ef002ced9f'; // Not used often -export const GNOSIS_SAFE_FACTORY_1_1_1_ADDRESS = '0x76e2cfc1f5fa8f6a5b3fc4c8f4788f0116861f9b'; -export const GNOSIS_SAFE_FACTORY_1_3_0_ADDRESS = '0xa6b71e26c5e0845f74c812102ca7114b6a896ab2'; +export const GNOSIS_SAFE_FACTORY_0_1_0_ADDRESS = + '0x88cd603a5dc47857d02865bbc7941b588c533263'; // Not used often +export const GNOSIS_SAFE_FACTORY_1_0_0_ADDRESS = + '0x12302fe9c02ff50939baaaaf415fc226c078613c'; // This release appears to have been buggy and didn't deploy contracts often +export const GNOSIS_SAFE_FACTORY_1_0_1_ADDRESS = + '0x50e55af101c777ba7a1d560a774a82ef002ced9f'; // Not used often +export const GNOSIS_SAFE_FACTORY_1_1_1_ADDRESS = + '0x76e2cfc1f5fa8f6a5b3fc4c8f4788f0116861f9b'; +export const GNOSIS_SAFE_FACTORY_1_3_0_ADDRESS = + '0xa6b71e26c5e0845f74c812102ca7114b6a896ab2'; export const KNOWN_ADDRESSES = { CryptoKitties: '0x06012c8cf97bead5deae237070f9587f8e7a266d', // Meow @@ -155,10 +167,12 @@ const createEventSignatureMapping = (signatures: string[]) => { }; // https://eips.ethereum.org/EIPS/eip-1967 -export const TRANSPARENT_UPGRADEABLE_PROXY_EVENT_SIGNATURES = ['Upgraded(address)']; +export const TRANSPARENT_UPGRADEABLE_PROXY_EVENT_SIGNATURES = [ + 'Upgraded(address)', +]; export const TRANSPARENT_UPGRADEABLE_PROXY_EVENTS = createEventSignatureMapping( - TRANSPARENT_UPGRADEABLE_PROXY_EVENT_SIGNATURES + TRANSPARENT_UPGRADEABLE_PROXY_EVENT_SIGNATURES, ); export const ERC20ABI: AbiItem[] = [ @@ -251,26 +265,38 @@ export const INTERFACE_IDS = { ERC777TokensRecipient: '0x9a20483d', }; -export const GENERIC_GOVERNANCE_INTERFACES = ['0xbf26d897', '0x79dd796f', '0x3938f78a']; +export const GENERIC_GOVERNANCE_INTERFACES = [ + '0xbf26d897', + '0x79dd796f', + '0x3938f78a', +]; export const UNISWAP_V3_FACTORY = '0x1f98431c8ad98523631ae4a59f267346ea31f984'; export const UNISWAP_V2_FACTORY = '0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f'; export const UNISWAP_V1_FACTORY = '0xc0a47dfe034b400b47bdad5fecda2621de6c4d95'; -export const PROP_HOUSE_PROXY_CONTRACT = '0xd310a3041dfcf14def5ccbc508668974b5da7174'; -export const PROP_HOUSE_IMPLEMENTATION_CONTRACT = '0x138d8aef5cbbbb9ea8da98cc0847fe0f3b573b40'; - -export const UNISWAP_V3_POOL_CREATED_EVENT_HASH = '0x783cca1c0412dd0d695e784568c96da2e9c22ff989357a2e8b1d9b2b4e6b7118'; -export const UNISWAP_V2_PAIR_CREATED_EVENT_HASH = '0x0d3648bd0f6ba80134a33ba9275ac585d9d315f0ad8355cddefde31afa28d0e9'; -export const UNISWAP_V1_NEW_EXCHANGE_EVENT_HASH = '0x9d42cb017eb05bd8944ab536a8b35bc68085931dd5f4356489801453923953f9'; - -export const UNISWAP_V1_NEW_EXCHANGE_EVENT = 'event NewExchange(address,address)'; +export const PROP_HOUSE_PROXY_CONTRACT = + '0xd310a3041dfcf14def5ccbc508668974b5da7174'; +export const PROP_HOUSE_IMPLEMENTATION_CONTRACT = + '0x138d8aef5cbbbb9ea8da98cc0847fe0f3b573b40'; + +export const UNISWAP_V3_POOL_CREATED_EVENT_HASH = + '0x783cca1c0412dd0d695e784568c96da2e9c22ff989357a2e8b1d9b2b4e6b7118'; +export const UNISWAP_V2_PAIR_CREATED_EVENT_HASH = + '0x0d3648bd0f6ba80134a33ba9275ac585d9d315f0ad8355cddefde31afa28d0e9'; +export const UNISWAP_V1_NEW_EXCHANGE_EVENT_HASH = + '0x9d42cb017eb05bd8944ab536a8b35bc68085931dd5f4356489801453923953f9'; + +export const UNISWAP_V1_NEW_EXCHANGE_EVENT = + 'event NewExchange(address,address)'; export const UNISWAP_V2_PAIR_CREATED_EVENT = 'event PairCreated(address indexed token0, address indexed token1, address pair, uint)'; export const UNISWAP_V3_POOL_CREATED_EVENT = 'event PoolCreated(address indexed token0, address indexed token1, uint24 indexed fee, int24 tickSpacing, address pool)'; -export const PROP_HOUSE_DAO_DEPLOYED_EVENT_HASH = '0x456d2baf5a87d70e586ec06fb91c2d7849778dd41d80fa826a6ea5bf8d28e3a6'; -export const PROP_HOUSE_DAO_DEPLOYED_EVENT = 'event DAODeployed(address,address,address,address,address)'; +export const PROP_HOUSE_DAO_DEPLOYED_EVENT_HASH = + '0x456d2baf5a87d70e586ec06fb91c2d7849778dd41d80fa826a6ea5bf8d28e3a6'; +export const PROP_HOUSE_DAO_DEPLOYED_EVENT = + 'event DAODeployed(address,address,address,address,address)'; // https://docs.openzeppelin.com/contracts/4.x/api/governance#IGovernor export const GOVERNOR_METHOD_SIGNATURES = [ @@ -292,7 +318,9 @@ export const GOVERNOR_METHOD_SIGNATURES = [ 'castVoteWithReason(uint256,uint8,string)', 'castVoteBySig(uint256,uint8,uint8,bytes32,bytes32)', ]; -export const GOVERNOR_METHODS = createSignatureMapping(GOVERNOR_METHOD_SIGNATURES); +export const GOVERNOR_METHODS = createSignatureMapping( + GOVERNOR_METHOD_SIGNATURES, +); export const TOKEN_SWAP_CONTRACTS = [ '0xe592427a0aece92de3edee1f18e0157c05861564', // Uniswap V3 Router @@ -388,9 +416,16 @@ export const OLD_NFT_ADDRESSES = [ '0x323a3e1693e7a0959f65972f3bf2dfcb93239dfe', // Digital Art Chain '0x552d72f86f04098a4eaeda6d7b665ac12f846ad2', // Dark Winds ]; -export const ERC721_TRANSFER_EVENT_1 = 'event Transfer(address indexed,address indexed,uint256)'; -export const ERC721_TRANSFER_EVENT_2 = 'event Transfer(address,address,uint256)'; - -export const PROXY_IMPLEMENTATION_METHOD_SIGNATURES = ['implementation()', 'IMPL()']; +export const ERC721_TRANSFER_EVENT_1 = + 'event Transfer(address indexed,address indexed,uint256)'; +export const ERC721_TRANSFER_EVENT_2 = + 'event Transfer(address,address,uint256)'; + +export const PROXY_IMPLEMENTATION_METHOD_SIGNATURES = [ + 'implementation()', + 'IMPL()', +]; -export const PROXY_IMPLEMENTATION_METHODS = createSignatureMapping(PROXY_IMPLEMENTATION_METHOD_SIGNATURES); +export const PROXY_IMPLEMENTATION_METHODS = createSignatureMapping( + PROXY_IMPLEMENTATION_METHOD_SIGNATURES, +); diff --git a/src/helpers/utils.ts b/src/helpers/utils.ts index 8d9e43f..27750f7 100644 --- a/src/helpers/utils.ts +++ b/src/helpers/utils.ts @@ -1,18 +1,162 @@ +import { + ERC20_METHODS, + ERC777_METHODS, + ERC721_METHODS, + ERC1155_METHODS, + ERC165_METHODS, + GOVERNOR_METHODS, + SAFE_METHODS, +} from './constants'; +import { RawBlock, StdObj } from '../types'; + export const makeTransform = ( - children: Record any>, - ) => { - return (transaction: any): any => { - for (const childTransformer of Object.values(children)) { - const result = childTransformer(transaction); - if (result) { - return result; - } + children: Record any>, +) => { + return (transaction: any): any => { + for (const childTransformer of Object.values(children)) { + const result = childTransformer(transaction); + if (result) { + return result; } - return transaction; - }; + } + return transaction; }; +}; + +export function shortenTxHash(hash: string): string { + if (hash.length <= 10) return hash; + return hash.substr(0, 6) + hash.substr(-4); +} + +// monkey-patch BigInt to serialize as JSON +// more context here: https://github.com/GoogleChromeLabs/jsbi/issues/30 +(BigInt.prototype as any).toJSON = function () { + return this.toString(); +}; + +export const bytecodeIsERC = ( + standard: Record, + bytecode: string, +): boolean => { + const ercMethodsDetected = Object.keys(standard).filter( + (key: string): boolean => bytecode.includes(standard[key]), + ); + return ercMethodsDetected.length == Object.keys(standard).length; +}; + +export const bytecodeIsERC20 = (bytecode: string): boolean => + bytecodeIsERC(ERC20_METHODS, bytecode); +export const bytecodeIsERC777 = (bytecode: string): boolean => + bytecodeIsERC(ERC777_METHODS, bytecode); +export const bytecodeIsERC721 = (bytecode: string): boolean => + bytecodeIsERC(ERC721_METHODS, bytecode); +export const bytecodeIsERC1155 = (bytecode: string): boolean => + bytecodeIsERC(ERC1155_METHODS, bytecode); +export const bytecodeIsERC165 = (bytecode: string): boolean => + bytecodeIsERC(ERC165_METHODS, bytecode); +export const bytecodeIsIGovernor = (bytecode: string): boolean => + bytecodeIsERC(GOVERNOR_METHODS, bytecode); +export const bytecodeIsGnosisSafe = (bytecode: string): boolean => + bytecodeIsERC(SAFE_METHODS, bytecode); + +export const normalizeBlock = (block: StdObj): RawBlock => { + // console.log('block', block); + + let str = JSON.stringify(block); + + // replace all EVM addresses with lowercased versions + str = str.replace(/("0x[A-z0-9]{40}")/g, (v) => v.toLowerCase()); + + return JSON.parse(str) as RawBlock; +}; + +const VALID_CHARS = + 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890.? '; + +export const countValidChars = (stringToCount: string) => { + let count = 0; + for (let i = 0; i < stringToCount.length; i++) { + if (VALID_CHARS.indexOf(stringToCount[i]) >= 0) { + count++; + } + } + return count; +}; + +export const convertToString = (value: any): string => { + // Check if the value is not null or undefined, and it has a toString() method. + if ( + value !== null && + value !== undefined && + typeof value?.toString === 'function' + ) { + return value.toString(); + } else { + // Return an empty string if the value is not convertible to a string. + return ''; + } +}; + +export function splitStringIntoChunks( + inputString: string, + chunkSize: number, +): string[] { + const chunks: string[] = []; + for (let i = 0; i < inputString.length; i += chunkSize) { + chunks.push(inputString.slice(i, i + chunkSize)); + } + return chunks; +} + +export function objectToDotNotation( + obj: Record, + current?: string, +) { + if (!obj || typeof obj !== 'object') { + return obj; + } + + const newObj = {}; + + for (const key in obj) { + const val = obj[key]; + const newKey = current ? `${current}.${key}` : key; + if (val && typeof val === 'object') { + Object.assign( + newObj, + objectToDotNotation(val as Record, newKey), + ); + } else { + newObj[newKey] = val; + } + } + + return newObj; +} + +export const getTokenName = async (token): Promise => { + try { + return (await token.methods.name().call()) as string; + } catch (error) { + console.log(`Name method not implemented.`); + return ''; + } +}; + +export const getTokenSymbol = async (token): Promise => { + try { + return (await token.methods.symbol().call()) as string; + } catch (error) { + console.log('Symbol method not implemented.'); + return ''; + } +}; - export function shortenTxHash(hash: string): string { - if (hash.length <= 10) return hash; - return hash.substr(0, 6) + hash.substr(-4); - } \ No newline at end of file +export const getTokenDecimals = async (token): Promise => { + try { + return (await token.methods.decimals().call()) as number; + } catch (error) { + console.log('Decimals method not implemented.'); + return 18; + } +}; diff --git a/src/transformers/_common/transactionAssetTransfers.ts b/src/transformers/_common/transactionAssetTransfers.ts index 3cd1a11..788007e 100644 --- a/src/transformers/_common/transactionAssetTransfers.ts +++ b/src/transformers/_common/transactionAssetTransfers.ts @@ -3,7 +3,7 @@ import Web3 from 'web3'; import { decodeEVMAddress, toBigNumber } from '../helpers/utils'; import type { AssetTransfer, RawBlock, RawTransaction } from '../types'; -import { KNOWN_ADDRESSES } from '../helpers/constants'; +import { KNOWN_ADDRESSES } from '../../helpers/constants'; // 1. pull out token transfers from logs // 2. pull out ETH transfers from traces (this covers tx.value transfers) diff --git a/src/transformers/_common/transactionProxyUpgrades.ts b/src/transformers/_common/transactionProxyUpgrades.ts index 45b9425..59e8bfa 100644 --- a/src/transformers/_common/transactionProxyUpgrades.ts +++ b/src/transformers/_common/transactionProxyUpgrades.ts @@ -1,5 +1,5 @@ import type { RawBlock, RawTransaction } from '../types'; -import { TRANSPARENT_UPGRADEABLE_PROXY_EVENTS } from '../helpers/constants'; +import { TRANSPARENT_UPGRADEABLE_PROXY_EVENTS } from '../../helpers/constants'; import { decodeEVMAddress } from '../helpers/utils'; type ProxyUpgrade = { hash: string; address: string; upgradedAddress: string }; diff --git a/src/transformers/ethereum/blockFork.ts b/src/transformers/ethereum/blockFork.ts index edc88e3..e046407 100644 --- a/src/transformers/ethereum/blockFork.ts +++ b/src/transformers/ethereum/blockFork.ts @@ -1,5 +1,5 @@ import type { RawBlock } from '../types'; -import { FORKS } from '../helpers/constants'; +import { FORKS } from '../../helpers/constants'; export function transform(block: RawBlock) { let fork: string; diff --git a/src/transformers/ethereum/contractPropHouseDetection.ts b/src/transformers/ethereum/contractPropHouseDetection.ts index ebc7c06..0065713 100644 --- a/src/transformers/ethereum/contractPropHouseDetection.ts +++ b/src/transformers/ethereum/contractPropHouseDetection.ts @@ -4,7 +4,7 @@ import { PROP_HOUSE_PROXY_CONTRACT, PROP_HOUSE_DAO_DEPLOYED_EVENT_HASH, PROP_HOUSE_DAO_DEPLOYED_EVENT, -} from '../helpers/constants'; +} from '../../helpers/constants'; export function transform(block: RawBlock): TransactionContract[] { const result: TransactionContract[] = block.transactions diff --git a/src/transformers/ethereum/contractUniswapDetection.ts b/src/transformers/ethereum/contractUniswapDetection.ts index 0649407..0b07449 100644 --- a/src/transformers/ethereum/contractUniswapDetection.ts +++ b/src/transformers/ethereum/contractUniswapDetection.ts @@ -10,7 +10,7 @@ import { UNISWAP_V1_NEW_EXCHANGE_EVENT_HASH, UNISWAP_V2_PAIR_CREATED_EVENT_HASH, UNISWAP_V3_POOL_CREATED_EVENT_HASH, -} from '../helpers/constants'; +} from '../../helpers/constants'; export function transform(block: RawBlock): TransactionContract[] { const result: TransactionContract[] = block.transactions diff --git a/src/transformers/ethereum/transactionAssetTransfersOldNFTs.ts b/src/transformers/ethereum/transactionAssetTransfersOldNFTs.ts index 55b1acf..52dc8d9 100644 --- a/src/transformers/ethereum/transactionAssetTransfersOldNFTs.ts +++ b/src/transformers/ethereum/transactionAssetTransfersOldNFTs.ts @@ -5,7 +5,7 @@ import { OLD_NFT_ADDRESSES, ERC721_TRANSFER_EVENT_1, ERC721_TRANSFER_EVENT_2, -} from '../helpers/constants'; +} from '../../helpers/constants'; import { decodeEvent } from '../helpers/sigMapper'; const TRANSFER_SIGNATURES = { diff --git a/src/transformers/ethereum/transactionFees.ts b/src/transformers/ethereum/transactionFees.ts index ca823d7..1a2801d 100644 --- a/src/transformers/ethereum/transactionFees.ts +++ b/src/transformers/ethereum/transactionFees.ts @@ -1,6 +1,6 @@ import type { RawBlock, RawTransaction } from '../types'; import { toBigNumber } from '../helpers/utils'; -import { FORKS } from '../helpers/constants'; +import { FORKS } from '../../helpers/constants'; export function transform(block: RawBlock) { const newTxs: Partial[] = []; diff --git a/src/transformers/ethereum/transactionForks.ts b/src/transformers/ethereum/transactionForks.ts index 4c0dd7f..3b5ac38 100644 --- a/src/transformers/ethereum/transactionForks.ts +++ b/src/transformers/ethereum/transactionForks.ts @@ -1,5 +1,5 @@ import type { RawBlock } from '../types'; -import { FORKS } from '../helpers/constants'; +import { FORKS } from '../../helpers/constants'; export function transform(block: RawBlock) { let fork: string; diff --git a/src/transformers/helpers/etherscan_prices.json b/src/transformers/helpers/etherscan_prices.json deleted file mode 100644 index e248b6f..0000000 --- a/src/transformers/helpers/etherscan_prices.json +++ /dev/null @@ -1,1299 +0,0 @@ -{ - "status": "1", - "message": "OK", - "result": [ - { "UTCDate": "2015-07-30", "unixTimeStamp": "1438214400", "value": "0.00" }, - { "UTCDate": "2015-07-31", "unixTimeStamp": "1438300800", "value": "0.00" }, - { "UTCDate": "2015-08-01", "unixTimeStamp": "1438387200", "value": "0.00" }, - { "UTCDate": "2015-08-02", "unixTimeStamp": "1438473600", "value": "0.00" }, - { "UTCDate": "2015-08-03", "unixTimeStamp": "1438560000", "value": "0.00" }, - { "UTCDate": "2015-08-04", "unixTimeStamp": "1438646400", "value": "0.00" }, - { "UTCDate": "2015-08-05", "unixTimeStamp": "1438732800", "value": "0.00" }, - { "UTCDate": "2015-08-06", "unixTimeStamp": "1438819200", "value": "0.00" }, - { "UTCDate": "2015-08-07", "unixTimeStamp": "1438905600", "value": "2.77" }, - { "UTCDate": "2015-08-08", "unixTimeStamp": "1438992000", "value": "0.81" }, - { "UTCDate": "2015-08-09", "unixTimeStamp": "1439078400", "value": "0.74" }, - { "UTCDate": "2015-08-10", "unixTimeStamp": "1439164800", "value": "0.68" }, - { "UTCDate": "2015-08-11", "unixTimeStamp": "1439251200", "value": "1.06" }, - { "UTCDate": "2015-08-12", "unixTimeStamp": "1439337600", "value": "1.25" }, - { "UTCDate": "2015-08-13", "unixTimeStamp": "1439424000", "value": "1.78" }, - { "UTCDate": "2015-08-14", "unixTimeStamp": "1439510400", "value": "1.80" }, - { "UTCDate": "2015-08-15", "unixTimeStamp": "1439596800", "value": "1.79" }, - { "UTCDate": "2015-08-16", "unixTimeStamp": "1439683200", "value": "1.37" }, - { "UTCDate": "2015-08-17", "unixTimeStamp": "1439769600", "value": "1.20" }, - { "UTCDate": "2015-08-18", "unixTimeStamp": "1439856000", "value": "1.27" }, - { "UTCDate": "2015-08-19", "unixTimeStamp": "1439942400", "value": "1.26" }, - { "UTCDate": "2015-08-20", "unixTimeStamp": "1440028800", "value": "1.48" }, - { "UTCDate": "2015-08-21", "unixTimeStamp": "1440115200", "value": "1.44" }, - { "UTCDate": "2015-08-22", "unixTimeStamp": "1440201600", "value": "1.39" }, - { "UTCDate": "2015-08-23", "unixTimeStamp": "1440288000", "value": "1.35" }, - { "UTCDate": "2015-08-24", "unixTimeStamp": "1440374400", "value": "1.24" }, - { "UTCDate": "2015-08-25", "unixTimeStamp": "1440460800", "value": "1.17" }, - { "UTCDate": "2015-08-26", "unixTimeStamp": "1440547200", "value": "1.16" }, - { "UTCDate": "2015-08-27", "unixTimeStamp": "1440633600", "value": "1.13" }, - { "UTCDate": "2015-08-28", "unixTimeStamp": "1440720000", "value": "1.30" }, - { "UTCDate": "2015-08-29", "unixTimeStamp": "1440806400", "value": "1.18" }, - { "UTCDate": "2015-08-30", "unixTimeStamp": "1440892800", "value": "1.32" }, - { "UTCDate": "2015-08-31", "unixTimeStamp": "1440979200", "value": "1.35" }, - { "UTCDate": "2015-09-01", "unixTimeStamp": "1441065600", "value": "1.35" }, - { "UTCDate": "2015-09-02", "unixTimeStamp": "1441152000", "value": "1.29" }, - { "UTCDate": "2015-09-03", "unixTimeStamp": "1441238400", "value": "1.26" }, - { "UTCDate": "2015-09-04", "unixTimeStamp": "1441324800", "value": "1.27" }, - { "UTCDate": "2015-09-05", "unixTimeStamp": "1441411200", "value": "1.37" }, - { "UTCDate": "2015-09-06", "unixTimeStamp": "1441497600", "value": "1.30" }, - { "UTCDate": "2015-09-07", "unixTimeStamp": "1441584000", "value": "1.24" }, - { "UTCDate": "2015-09-08", "unixTimeStamp": "1441670400", "value": "1.23" }, - { "UTCDate": "2015-09-09", "unixTimeStamp": "1441756800", "value": "1.21" }, - { "UTCDate": "2015-09-10", "unixTimeStamp": "1441843200", "value": "1.16" }, - { "UTCDate": "2015-09-11", "unixTimeStamp": "1441929600", "value": "0.98" }, - { "UTCDate": "2015-09-12", "unixTimeStamp": "1442016000", "value": "1.04" }, - { "UTCDate": "2015-09-13", "unixTimeStamp": "1442102400", "value": "0.94" }, - { "UTCDate": "2015-09-14", "unixTimeStamp": "1442188800", "value": "0.87" }, - { "UTCDate": "2015-09-15", "unixTimeStamp": "1442275200", "value": "0.94" }, - { "UTCDate": "2015-09-16", "unixTimeStamp": "1442361600", "value": "0.90" }, - { "UTCDate": "2015-09-17", "unixTimeStamp": "1442448000", "value": "0.89" }, - { "UTCDate": "2015-09-18", "unixTimeStamp": "1442534400", "value": "0.85" }, - { "UTCDate": "2015-09-19", "unixTimeStamp": "1442620800", "value": "0.89" }, - { "UTCDate": "2015-09-20", "unixTimeStamp": "1442707200", "value": "0.94" }, - { "UTCDate": "2015-09-21", "unixTimeStamp": "1442793600", "value": "0.90" }, - { "UTCDate": "2015-09-22", "unixTimeStamp": "1442880000", "value": "0.90" }, - { "UTCDate": "2015-09-23", "unixTimeStamp": "1442966400", "value": "0.90" }, - { "UTCDate": "2015-09-24", "unixTimeStamp": "1443052800", "value": "0.81" }, - { "UTCDate": "2015-09-25", "unixTimeStamp": "1443139200", "value": "0.74" }, - { "UTCDate": "2015-09-26", "unixTimeStamp": "1443225600", "value": "0.78" }, - { "UTCDate": "2015-09-27", "unixTimeStamp": "1443312000", "value": "0.72" }, - { "UTCDate": "2015-09-28", "unixTimeStamp": "1443398400", "value": "0.59" }, - { "UTCDate": "2015-09-29", "unixTimeStamp": "1443484800", "value": "0.68" }, - { "UTCDate": "2015-09-30", "unixTimeStamp": "1443571200", "value": "0.72" }, - { "UTCDate": "2015-10-01", "unixTimeStamp": "1443657600", "value": "0.68" }, - { "UTCDate": "2015-10-02", "unixTimeStamp": "1443744000", "value": "0.68" }, - { "UTCDate": "2015-10-03", "unixTimeStamp": "1443830400", "value": "0.69" }, - { "UTCDate": "2015-10-04", "unixTimeStamp": "1443916800", "value": "0.67" }, - { "UTCDate": "2015-10-05", "unixTimeStamp": "1444003200", "value": "0.63" }, - { "UTCDate": "2015-10-06", "unixTimeStamp": "1444089600", "value": "0.66" }, - { "UTCDate": "2015-10-07", "unixTimeStamp": "1444176000", "value": "0.61" }, - { "UTCDate": "2015-10-08", "unixTimeStamp": "1444262400", "value": "0.62" }, - { "UTCDate": "2015-10-09", "unixTimeStamp": "1444348800", "value": "0.65" }, - { "UTCDate": "2015-10-10", "unixTimeStamp": "1444435200", "value": "0.63" }, - { "UTCDate": "2015-10-11", "unixTimeStamp": "1444521600", "value": "0.63" }, - { "UTCDate": "2015-10-12", "unixTimeStamp": "1444608000", "value": "0.63" }, - { "UTCDate": "2015-10-13", "unixTimeStamp": "1444694400", "value": "0.60" }, - { "UTCDate": "2015-10-14", "unixTimeStamp": "1444780800", "value": "0.51" }, - { "UTCDate": "2015-10-15", "unixTimeStamp": "1444867200", "value": "0.56" }, - { "UTCDate": "2015-10-16", "unixTimeStamp": "1444953600", "value": "0.53" }, - { "UTCDate": "2015-10-17", "unixTimeStamp": "1445040000", "value": "0.55" }, - { "UTCDate": "2015-10-18", "unixTimeStamp": "1445126400", "value": "0.52" }, - { "UTCDate": "2015-10-19", "unixTimeStamp": "1445212800", "value": "0.49" }, - { "UTCDate": "2015-10-20", "unixTimeStamp": "1445299200", "value": "0.44" }, - { "UTCDate": "2015-10-21", "unixTimeStamp": "1445385600", "value": "0.44" }, - { "UTCDate": "2015-10-22", "unixTimeStamp": "1445472000", "value": "0.59" }, - { "UTCDate": "2015-10-23", "unixTimeStamp": "1445558400", "value": "0.52" }, - { "UTCDate": "2015-10-24", "unixTimeStamp": "1445644800", "value": "0.57" }, - { "UTCDate": "2015-10-25", "unixTimeStamp": "1445731200", "value": "0.65" }, - { "UTCDate": "2015-10-26", "unixTimeStamp": "1445817600", "value": "0.74" }, - { "UTCDate": "2015-10-27", "unixTimeStamp": "1445904000", "value": "0.87" }, - { "UTCDate": "2015-10-28", "unixTimeStamp": "1445990400", "value": "1.01" }, - { "UTCDate": "2015-10-29", "unixTimeStamp": "1446076800", "value": "1.16" }, - { "UTCDate": "2015-10-30", "unixTimeStamp": "1446163200", "value": "1.04" }, - { "UTCDate": "2015-10-31", "unixTimeStamp": "1446249600", "value": "0.89" }, - { "UTCDate": "2015-11-01", "unixTimeStamp": "1446336000", "value": "1.05" }, - { "UTCDate": "2015-11-02", "unixTimeStamp": "1446422400", "value": "0.96" }, - { "UTCDate": "2015-11-03", "unixTimeStamp": "1446508800", "value": "1.00" }, - { "UTCDate": "2015-11-04", "unixTimeStamp": "1446595200", "value": "0.87" }, - { "UTCDate": "2015-11-05", "unixTimeStamp": "1446681600", "value": "0.89" }, - { "UTCDate": "2015-11-06", "unixTimeStamp": "1446768000", "value": "0.92" }, - { "UTCDate": "2015-11-07", "unixTimeStamp": "1446854400", "value": "0.92" }, - { "UTCDate": "2015-11-08", "unixTimeStamp": "1446940800", "value": "1.02" }, - { "UTCDate": "2015-11-09", "unixTimeStamp": "1447027200", "value": "1.00" }, - { "UTCDate": "2015-11-10", "unixTimeStamp": "1447113600", "value": "0.92" }, - { "UTCDate": "2015-11-11", "unixTimeStamp": "1447200000", "value": "0.78" }, - { "UTCDate": "2015-11-12", "unixTimeStamp": "1447286400", "value": "0.89" }, - { "UTCDate": "2015-11-13", "unixTimeStamp": "1447372800", "value": "0.89" }, - { "UTCDate": "2015-11-14", "unixTimeStamp": "1447459200", "value": "0.89" }, - { "UTCDate": "2015-11-15", "unixTimeStamp": "1447545600", "value": "0.90" }, - { "UTCDate": "2015-11-16", "unixTimeStamp": "1447632000", "value": "0.94" }, - { "UTCDate": "2015-11-17", "unixTimeStamp": "1447718400", "value": "1.00" }, - { "UTCDate": "2015-11-18", "unixTimeStamp": "1447804800", "value": "0.99" }, - { "UTCDate": "2015-11-19", "unixTimeStamp": "1447891200", "value": "0.95" }, - { "UTCDate": "2015-11-20", "unixTimeStamp": "1447977600", "value": "0.93" }, - { "UTCDate": "2015-11-21", "unixTimeStamp": "1448064000", "value": "0.97" }, - { "UTCDate": "2015-11-22", "unixTimeStamp": "1448150400", "value": "0.96" }, - { "UTCDate": "2015-11-23", "unixTimeStamp": "1448236800", "value": "0.94" }, - { "UTCDate": "2015-11-24", "unixTimeStamp": "1448323200", "value": "0.91" }, - { "UTCDate": "2015-11-25", "unixTimeStamp": "1448409600", "value": "0.86" }, - { "UTCDate": "2015-11-26", "unixTimeStamp": "1448496000", "value": "0.88" }, - { "UTCDate": "2015-11-27", "unixTimeStamp": "1448582400", "value": "0.87" }, - { "UTCDate": "2015-11-28", "unixTimeStamp": "1448668800", "value": "0.91" }, - { "UTCDate": "2015-11-29", "unixTimeStamp": "1448755200", "value": "0.87" }, - { "UTCDate": "2015-11-30", "unixTimeStamp": "1448841600", "value": "0.88" }, - { "UTCDate": "2015-12-01", "unixTimeStamp": "1448928000", "value": "0.87" }, - { "UTCDate": "2015-12-02", "unixTimeStamp": "1449014400", "value": "0.83" }, - { "UTCDate": "2015-12-03", "unixTimeStamp": "1449100800", "value": "0.82" }, - { "UTCDate": "2015-12-04", "unixTimeStamp": "1449187200", "value": "0.84" }, - { "UTCDate": "2015-12-05", "unixTimeStamp": "1449273600", "value": "0.85" }, - { "UTCDate": "2015-12-06", "unixTimeStamp": "1449360000", "value": "0.84" }, - { "UTCDate": "2015-12-07", "unixTimeStamp": "1449446400", "value": "0.80" }, - { "UTCDate": "2015-12-08", "unixTimeStamp": "1449532800", "value": "0.83" }, - { "UTCDate": "2015-12-09", "unixTimeStamp": "1449619200", "value": "0.79" }, - { "UTCDate": "2015-12-10", "unixTimeStamp": "1449705600", "value": "0.84" }, - { "UTCDate": "2015-12-11", "unixTimeStamp": "1449792000", "value": "0.91" }, - { "UTCDate": "2015-12-12", "unixTimeStamp": "1449878400", "value": "0.97" }, - { "UTCDate": "2015-12-13", "unixTimeStamp": "1449964800", "value": "0.96" }, - { "UTCDate": "2015-12-14", "unixTimeStamp": "1450051200", "value": "0.99" }, - { "UTCDate": "2015-12-15", "unixTimeStamp": "1450137600", "value": "1.01" }, - { "UTCDate": "2015-12-16", "unixTimeStamp": "1450224000", "value": "0.99" }, - { "UTCDate": "2015-12-17", "unixTimeStamp": "1450310400", "value": "0.94" }, - { "UTCDate": "2015-12-18", "unixTimeStamp": "1450396800", "value": "0.91" }, - { "UTCDate": "2015-12-19", "unixTimeStamp": "1450483200", "value": "0.90" }, - { "UTCDate": "2015-12-20", "unixTimeStamp": "1450569600", "value": "0.90" }, - { "UTCDate": "2015-12-21", "unixTimeStamp": "1450656000", "value": "0.89" }, - { "UTCDate": "2015-12-22", "unixTimeStamp": "1450742400", "value": "0.87" }, - { "UTCDate": "2015-12-23", "unixTimeStamp": "1450828800", "value": "0.85" }, - { "UTCDate": "2015-12-24", "unixTimeStamp": "1450915200", "value": "0.85" }, - { "UTCDate": "2015-12-25", "unixTimeStamp": "1451001600", "value": "0.87" }, - { "UTCDate": "2015-12-26", "unixTimeStamp": "1451088000", "value": "0.85" }, - { "UTCDate": "2015-12-27", "unixTimeStamp": "1451174400", "value": "0.85" }, - { "UTCDate": "2015-12-28", "unixTimeStamp": "1451260800", "value": "0.84" }, - { "UTCDate": "2015-12-29", "unixTimeStamp": "1451347200", "value": "0.87" }, - { "UTCDate": "2015-12-30", "unixTimeStamp": "1451433600", "value": "0.90" }, - { "UTCDate": "2015-12-31", "unixTimeStamp": "1451520000", "value": "0.93" }, - { "UTCDate": "2016-01-01", "unixTimeStamp": "1451606400", "value": "0.93" }, - { "UTCDate": "2016-01-02", "unixTimeStamp": "1451692800", "value": "0.93" }, - { "UTCDate": "2016-01-03", "unixTimeStamp": "1451779200", "value": "0.97" }, - { "UTCDate": "2016-01-04", "unixTimeStamp": "1451865600", "value": "0.95" }, - { "UTCDate": "2016-01-05", "unixTimeStamp": "1451952000", "value": "0.95" }, - { "UTCDate": "2016-01-06", "unixTimeStamp": "1452038400", "value": "0.96" }, - { "UTCDate": "2016-01-07", "unixTimeStamp": "1452124800", "value": "0.95" }, - { "UTCDate": "2016-01-08", "unixTimeStamp": "1452211200", "value": "0.99" }, - { "UTCDate": "2016-01-09", "unixTimeStamp": "1452297600", "value": "0.99" }, - { "UTCDate": "2016-01-10", "unixTimeStamp": "1452384000", "value": "0.99" }, - { "UTCDate": "2016-01-11", "unixTimeStamp": "1452470400", "value": "1.05" }, - { "UTCDate": "2016-01-12", "unixTimeStamp": "1452556800", "value": "1.23" }, - { "UTCDate": "2016-01-13", "unixTimeStamp": "1452643200", "value": "1.13" }, - { "UTCDate": "2016-01-14", "unixTimeStamp": "1452729600", "value": "1.16" }, - { "UTCDate": "2016-01-15", "unixTimeStamp": "1452816000", "value": "1.22" }, - { "UTCDate": "2016-01-16", "unixTimeStamp": "1452902400", "value": "1.22" }, - { "UTCDate": "2016-01-17", "unixTimeStamp": "1452988800", "value": "1.31" }, - { "UTCDate": "2016-01-18", "unixTimeStamp": "1453075200", "value": "1.47" }, - { "UTCDate": "2016-01-19", "unixTimeStamp": "1453161600", "value": "1.37" }, - { "UTCDate": "2016-01-20", "unixTimeStamp": "1453248000", "value": "1.53" }, - { "UTCDate": "2016-01-21", "unixTimeStamp": "1453334400", "value": "1.54" }, - { "UTCDate": "2016-01-22", "unixTimeStamp": "1453420800", "value": "1.52" }, - { "UTCDate": "2016-01-23", "unixTimeStamp": "1453507200", "value": "2.03" }, - { "UTCDate": "2016-01-24", "unixTimeStamp": "1453593600", "value": "2.10" }, - { "UTCDate": "2016-01-25", "unixTimeStamp": "1453680000", "value": "2.50" }, - { "UTCDate": "2016-01-26", "unixTimeStamp": "1453766400", "value": "2.30" }, - { "UTCDate": "2016-01-27", "unixTimeStamp": "1453852800", "value": "2.42" }, - { "UTCDate": "2016-01-28", "unixTimeStamp": "1453939200", "value": "2.55" }, - { "UTCDate": "2016-01-29", "unixTimeStamp": "1454025600", "value": "2.41" }, - { "UTCDate": "2016-01-30", "unixTimeStamp": "1454112000", "value": "2.43" }, - { "UTCDate": "2016-01-31", "unixTimeStamp": "1454198400", "value": "2.20" }, - { "UTCDate": "2016-02-01", "unixTimeStamp": "1454284800", "value": "2.17" }, - { "UTCDate": "2016-02-02", "unixTimeStamp": "1454371200", "value": "2.45" }, - { "UTCDate": "2016-02-03", "unixTimeStamp": "1454457600", "value": "2.53" }, - { "UTCDate": "2016-02-04", "unixTimeStamp": "1454544000", "value": "2.57" }, - { "UTCDate": "2016-02-05", "unixTimeStamp": "1454630400", "value": "2.57" }, - { "UTCDate": "2016-02-06", "unixTimeStamp": "1454716800", "value": "2.53" }, - { "UTCDate": "2016-02-07", "unixTimeStamp": "1454803200", "value": "3.00" }, - { "UTCDate": "2016-02-08", "unixTimeStamp": "1454889600", "value": "3.16" }, - { "UTCDate": "2016-02-09", "unixTimeStamp": "1454976000", "value": "3.76" }, - { "UTCDate": "2016-02-10", "unixTimeStamp": "1455062400", "value": "4.35" }, - { "UTCDate": "2016-02-11", "unixTimeStamp": "1455148800", "value": "6.38" }, - { "UTCDate": "2016-02-12", "unixTimeStamp": "1455235200", "value": "5.27" }, - { "UTCDate": "2016-02-13", "unixTimeStamp": "1455321600", "value": "5.22" }, - { "UTCDate": "2016-02-14", "unixTimeStamp": "1455408000", "value": "5.20" }, - { "UTCDate": "2016-02-15", "unixTimeStamp": "1455494400", "value": "5.22" }, - { "UTCDate": "2016-02-16", "unixTimeStamp": "1455580800", "value": "4.25" }, - { "UTCDate": "2016-02-17", "unixTimeStamp": "1455667200", "value": "3.86" }, - { "UTCDate": "2016-02-18", "unixTimeStamp": "1455753600", "value": "4.36" }, - { "UTCDate": "2016-02-19", "unixTimeStamp": "1455840000", "value": "4.45" }, - { "UTCDate": "2016-02-20", "unixTimeStamp": "1455926400", "value": "4.37" }, - { "UTCDate": "2016-02-21", "unixTimeStamp": "1456012800", "value": "4.63" }, - { "UTCDate": "2016-02-22", "unixTimeStamp": "1456099200", "value": "5.60" }, - { "UTCDate": "2016-02-23", "unixTimeStamp": "1456185600", "value": "5.70" }, - { "UTCDate": "2016-02-24", "unixTimeStamp": "1456272000", "value": "6.23" }, - { "UTCDate": "2016-02-25", "unixTimeStamp": "1456358400", "value": "5.93" }, - { "UTCDate": "2016-02-26", "unixTimeStamp": "1456444800", "value": "6.03" }, - { "UTCDate": "2016-02-27", "unixTimeStamp": "1456531200", "value": "6.31" }, - { "UTCDate": "2016-02-28", "unixTimeStamp": "1456617600", "value": "6.50" }, - { "UTCDate": "2016-02-29", "unixTimeStamp": "1456704000", "value": "6.35" }, - { "UTCDate": "2016-03-01", "unixTimeStamp": "1456790400", "value": "7.59" }, - { "UTCDate": "2016-03-02", "unixTimeStamp": "1456876800", "value": "8.70" }, - { "UTCDate": "2016-03-03", "unixTimeStamp": "1456963200", "value": "9.35" }, - { "UTCDate": "2016-03-04", "unixTimeStamp": "1457049600", "value": "9.96" }, - { "UTCDate": "2016-03-05", "unixTimeStamp": "1457136000", "value": "11.00" }, - { "UTCDate": "2016-03-06", "unixTimeStamp": "1457222400", "value": "10.98" }, - { "UTCDate": "2016-03-07", "unixTimeStamp": "1457308800", "value": "9.50" }, - { "UTCDate": "2016-03-08", "unixTimeStamp": "1457395200", "value": "9.88" }, - { "UTCDate": "2016-03-09", "unixTimeStamp": "1457481600", "value": "11.55" }, - { "UTCDate": "2016-03-10", "unixTimeStamp": "1457568000", "value": "11.11" }, - { "UTCDate": "2016-03-11", "unixTimeStamp": "1457654400", "value": "11.25" }, - { "UTCDate": "2016-03-12", "unixTimeStamp": "1457740800", "value": "13.25" }, - { "UTCDate": "2016-03-13", "unixTimeStamp": "1457827200", "value": "15.00" }, - { "UTCDate": "2016-03-14", "unixTimeStamp": "1457913600", "value": "12.50" }, - { "UTCDate": "2016-03-15", "unixTimeStamp": "1458000000", "value": "13.09" }, - { "UTCDate": "2016-03-16", "unixTimeStamp": "1458086400", "value": "12.92" }, - { "UTCDate": "2016-03-17", "unixTimeStamp": "1458172800", "value": "11.14" }, - { "UTCDate": "2016-03-18", "unixTimeStamp": "1458259200", "value": "10.75" }, - { "UTCDate": "2016-03-19", "unixTimeStamp": "1458345600", "value": "10.55" }, - { "UTCDate": "2016-03-20", "unixTimeStamp": "1458432000", "value": "10.06" }, - { "UTCDate": "2016-03-21", "unixTimeStamp": "1458518400", "value": "11.97" }, - { "UTCDate": "2016-03-22", "unixTimeStamp": "1458604800", "value": "10.96" }, - { "UTCDate": "2016-03-23", "unixTimeStamp": "1458691200", "value": "12.29" }, - { "UTCDate": "2016-03-24", "unixTimeStamp": "1458777600", "value": "11.13" }, - { "UTCDate": "2016-03-25", "unixTimeStamp": "1458864000", "value": "10.69" }, - { "UTCDate": "2016-03-26", "unixTimeStamp": "1458950400", "value": "11.00" }, - { "UTCDate": "2016-03-27", "unixTimeStamp": "1459036800", "value": "10.50" }, - { "UTCDate": "2016-03-28", "unixTimeStamp": "1459123200", "value": "11.58" }, - { "UTCDate": "2016-03-29", "unixTimeStamp": "1459209600", "value": "11.73" }, - { "UTCDate": "2016-03-30", "unixTimeStamp": "1459296000", "value": "11.88" }, - { "UTCDate": "2016-03-31", "unixTimeStamp": "1459382400", "value": "11.41" }, - { "UTCDate": "2016-04-01", "unixTimeStamp": "1459468800", "value": "11.63" }, - { "UTCDate": "2016-04-02", "unixTimeStamp": "1459555200", "value": "11.61" }, - { "UTCDate": "2016-04-03", "unixTimeStamp": "1459641600", "value": "11.58" }, - { "UTCDate": "2016-04-04", "unixTimeStamp": "1459728000", "value": "11.10" }, - { "UTCDate": "2016-04-05", "unixTimeStamp": "1459814400", "value": "10.39" }, - { "UTCDate": "2016-04-06", "unixTimeStamp": "1459900800", "value": "10.79" }, - { "UTCDate": "2016-04-07", "unixTimeStamp": "1459987200", "value": "10.08" }, - { "UTCDate": "2016-04-08", "unixTimeStamp": "1460073600", "value": "9.74" }, - { "UTCDate": "2016-04-09", "unixTimeStamp": "1460160000", "value": "9.16" }, - { "UTCDate": "2016-04-10", "unixTimeStamp": "1460246400", "value": "8.80" }, - { "UTCDate": "2016-04-11", "unixTimeStamp": "1460332800", "value": "8.72" }, - { "UTCDate": "2016-04-12", "unixTimeStamp": "1460419200", "value": "7.54" }, - { "UTCDate": "2016-04-13", "unixTimeStamp": "1460505600", "value": "8.02" }, - { "UTCDate": "2016-04-14", "unixTimeStamp": "1460592000", "value": "8.48" }, - { "UTCDate": "2016-04-15", "unixTimeStamp": "1460678400", "value": "8.22" }, - { "UTCDate": "2016-04-16", "unixTimeStamp": "1460764800", "value": "8.48" }, - { "UTCDate": "2016-04-17", "unixTimeStamp": "1460851200", "value": "9.45" }, - { "UTCDate": "2016-04-18", "unixTimeStamp": "1460937600", "value": "8.92" }, - { "UTCDate": "2016-04-19", "unixTimeStamp": "1461024000", "value": "8.77" }, - { "UTCDate": "2016-04-20", "unixTimeStamp": "1461110400", "value": "8.54" }, - { "UTCDate": "2016-04-21", "unixTimeStamp": "1461196800", "value": "8.16" }, - { "UTCDate": "2016-04-22", "unixTimeStamp": "1461283200", "value": "7.83" }, - { "UTCDate": "2016-04-23", "unixTimeStamp": "1461369600", "value": "8.31" }, - { "UTCDate": "2016-04-24", "unixTimeStamp": "1461456000", "value": "8.00" }, - { "UTCDate": "2016-04-25", "unixTimeStamp": "1461542400", "value": "7.43" }, - { "UTCDate": "2016-04-26", "unixTimeStamp": "1461628800", "value": "7.50" }, - { "UTCDate": "2016-04-27", "unixTimeStamp": "1461715200", "value": "7.77" }, - { "UTCDate": "2016-04-28", "unixTimeStamp": "1461801600", "value": "7.30" }, - { "UTCDate": "2016-04-29", "unixTimeStamp": "1461888000", "value": "7.52" }, - { "UTCDate": "2016-04-30", "unixTimeStamp": "1461974400", "value": "8.83" }, - { "UTCDate": "2016-05-01", "unixTimeStamp": "1462060800", "value": "8.76" }, - { "UTCDate": "2016-05-02", "unixTimeStamp": "1462147200", "value": "10.03" }, - { "UTCDate": "2016-05-03", "unixTimeStamp": "1462233600", "value": "9.37" }, - { "UTCDate": "2016-05-04", "unixTimeStamp": "1462320000", "value": "9.43" }, - { "UTCDate": "2016-05-05", "unixTimeStamp": "1462406400", "value": "9.79" }, - { "UTCDate": "2016-05-06", "unixTimeStamp": "1462492800", "value": "9.27" }, - { "UTCDate": "2016-05-07", "unixTimeStamp": "1462579200", "value": "9.30" }, - { "UTCDate": "2016-05-08", "unixTimeStamp": "1462665600", "value": "9.44" }, - { "UTCDate": "2016-05-09", "unixTimeStamp": "1462752000", "value": "9.32" }, - { "UTCDate": "2016-05-10", "unixTimeStamp": "1462838400", "value": "9.39" }, - { "UTCDate": "2016-05-11", "unixTimeStamp": "1462924800", "value": "9.97" }, - { "UTCDate": "2016-05-12", "unixTimeStamp": "1463011200", "value": "10.10" }, - { "UTCDate": "2016-05-13", "unixTimeStamp": "1463097600", "value": "10.48" }, - { "UTCDate": "2016-05-14", "unixTimeStamp": "1463184000", "value": "10.14" }, - { "UTCDate": "2016-05-15", "unixTimeStamp": "1463270400", "value": "9.94" }, - { "UTCDate": "2016-05-16", "unixTimeStamp": "1463356800", "value": "11.04" }, - { "UTCDate": "2016-05-17", "unixTimeStamp": "1463443200", "value": "12.26" }, - { "UTCDate": "2016-05-18", "unixTimeStamp": "1463529600", "value": "13.29" }, - { "UTCDate": "2016-05-19", "unixTimeStamp": "1463616000", "value": "14.49" }, - { "UTCDate": "2016-05-20", "unixTimeStamp": "1463702400", "value": "13.73" }, - { "UTCDate": "2016-05-21", "unixTimeStamp": "1463788800", "value": "13.95" }, - { "UTCDate": "2016-05-22", "unixTimeStamp": "1463875200", "value": "14.21" }, - { "UTCDate": "2016-05-23", "unixTimeStamp": "1463961600", "value": "13.45" }, - { "UTCDate": "2016-05-24", "unixTimeStamp": "1464048000", "value": "12.62" }, - { "UTCDate": "2016-05-25", "unixTimeStamp": "1464134400", "value": "12.53" }, - { "UTCDate": "2016-05-26", "unixTimeStamp": "1464220800", "value": "12.37" }, - { "UTCDate": "2016-05-27", "unixTimeStamp": "1464307200", "value": "11.11" }, - { "UTCDate": "2016-05-28", "unixTimeStamp": "1464393600", "value": "11.56" }, - { "UTCDate": "2016-05-29", "unixTimeStamp": "1464480000", "value": "12.28" }, - { "UTCDate": "2016-05-30", "unixTimeStamp": "1464566400", "value": "12.48" }, - { "UTCDate": "2016-05-31", "unixTimeStamp": "1464652800", "value": "13.85" }, - { "UTCDate": "2016-06-01", "unixTimeStamp": "1464739200", "value": "13.83" }, - { "UTCDate": "2016-06-02", "unixTimeStamp": "1464825600", "value": "13.78" }, - { "UTCDate": "2016-06-03", "unixTimeStamp": "1464912000", "value": "13.78" }, - { "UTCDate": "2016-06-04", "unixTimeStamp": "1464998400", "value": "13.66" }, - { "UTCDate": "2016-06-05", "unixTimeStamp": "1465084800", "value": "13.85" }, - { "UTCDate": "2016-06-06", "unixTimeStamp": "1465171200", "value": "13.96" }, - { "UTCDate": "2016-06-07", "unixTimeStamp": "1465257600", "value": "14.41" }, - { "UTCDate": "2016-06-08", "unixTimeStamp": "1465344000", "value": "14.44" }, - { "UTCDate": "2016-06-09", "unixTimeStamp": "1465430400", "value": "14.49" }, - { "UTCDate": "2016-06-10", "unixTimeStamp": "1465516800", "value": "13.97" }, - { "UTCDate": "2016-06-11", "unixTimeStamp": "1465603200", "value": "14.01" }, - { "UTCDate": "2016-06-12", "unixTimeStamp": "1465689600", "value": "15.57" }, - { "UTCDate": "2016-06-13", "unixTimeStamp": "1465776000", "value": "17.55" }, - { "UTCDate": "2016-06-14", "unixTimeStamp": "1465862400", "value": "18.70" }, - { "UTCDate": "2016-06-15", "unixTimeStamp": "1465948800", "value": "18.30" }, - { "UTCDate": "2016-06-16", "unixTimeStamp": "1466035200", "value": "20.61" }, - { "UTCDate": "2016-06-17", "unixTimeStamp": "1466121600", "value": "15.49" }, - { "UTCDate": "2016-06-18", "unixTimeStamp": "1466208000", "value": "11.36" }, - { "UTCDate": "2016-06-19", "unixTimeStamp": "1466294400", "value": "12.33" }, - { "UTCDate": "2016-06-20", "unixTimeStamp": "1466380800", "value": "11.70" }, - { "UTCDate": "2016-06-21", "unixTimeStamp": "1466467200", "value": "12.71" }, - { "UTCDate": "2016-06-22", "unixTimeStamp": "1466553600", "value": "13.21" }, - { "UTCDate": "2016-06-23", "unixTimeStamp": "1466640000", "value": "13.58" }, - { "UTCDate": "2016-06-24", "unixTimeStamp": "1466726400", "value": "14.25" }, - { "UTCDate": "2016-06-25", "unixTimeStamp": "1466812800", "value": "14.28" }, - { "UTCDate": "2016-06-26", "unixTimeStamp": "1466899200", "value": "13.82" }, - { "UTCDate": "2016-06-27", "unixTimeStamp": "1466985600", "value": "14.04" }, - { "UTCDate": "2016-06-28", "unixTimeStamp": "1467072000", "value": "12.15" }, - { "UTCDate": "2016-06-29", "unixTimeStamp": "1467158400", "value": "12.76" }, - { "UTCDate": "2016-06-30", "unixTimeStamp": "1467244800", "value": "12.40" }, - { "UTCDate": "2016-07-01", "unixTimeStamp": "1467331200", "value": "12.23" }, - { "UTCDate": "2016-07-02", "unixTimeStamp": "1467417600", "value": "12.04" }, - { "UTCDate": "2016-07-03", "unixTimeStamp": "1467504000", "value": "11.85" }, - { "UTCDate": "2016-07-04", "unixTimeStamp": "1467590400", "value": "11.34" }, - { "UTCDate": "2016-07-05", "unixTimeStamp": "1467676800", "value": "10.45" }, - { "UTCDate": "2016-07-06", "unixTimeStamp": "1467763200", "value": "10.51" }, - { "UTCDate": "2016-07-07", "unixTimeStamp": "1467849600", "value": "10.07" }, - { "UTCDate": "2016-07-08", "unixTimeStamp": "1467936000", "value": "11.30" }, - { "UTCDate": "2016-07-09", "unixTimeStamp": "1468022400", "value": "10.92" }, - { "UTCDate": "2016-07-10", "unixTimeStamp": "1468108800", "value": "10.97" }, - { "UTCDate": "2016-07-11", "unixTimeStamp": "1468195200", "value": "10.58" }, - { "UTCDate": "2016-07-12", "unixTimeStamp": "1468281600", "value": "10.54" }, - { "UTCDate": "2016-07-13", "unixTimeStamp": "1468368000", "value": "10.44" }, - { "UTCDate": "2016-07-14", "unixTimeStamp": "1468454400", "value": "11.55" }, - { "UTCDate": "2016-07-15", "unixTimeStamp": "1468540800", "value": "11.88" }, - { "UTCDate": "2016-07-16", "unixTimeStamp": "1468627200", "value": "11.59" }, - { "UTCDate": "2016-07-17", "unixTimeStamp": "1468713600", "value": "11.19" }, - { "UTCDate": "2016-07-18", "unixTimeStamp": "1468800000", "value": "11.03" }, - { "UTCDate": "2016-07-19", "unixTimeStamp": "1468886400", "value": "11.63" }, - { "UTCDate": "2016-07-20", "unixTimeStamp": "1468972800", "value": "12.54" }, - { "UTCDate": "2016-07-21", "unixTimeStamp": "1469059200", "value": "12.66" }, - { "UTCDate": "2016-07-22", "unixTimeStamp": "1469145600", "value": "14.82" }, - { "UTCDate": "2016-07-23", "unixTimeStamp": "1469232000", "value": "14.40" }, - { "UTCDate": "2016-07-24", "unixTimeStamp": "1469318400", "value": "12.63" }, - { "UTCDate": "2016-07-25", "unixTimeStamp": "1469404800", "value": "13.84" }, - { "UTCDate": "2016-07-26", "unixTimeStamp": "1469491200", "value": "12.08" }, - { "UTCDate": "2016-07-27", "unixTimeStamp": "1469577600", "value": "13.05" }, - { "UTCDate": "2016-07-28", "unixTimeStamp": "1469664000", "value": "12.87" }, - { "UTCDate": "2016-07-29", "unixTimeStamp": "1469750400", "value": "12.87" }, - { "UTCDate": "2016-07-30", "unixTimeStamp": "1469836800", "value": "12.57" }, - { "UTCDate": "2016-07-31", "unixTimeStamp": "1469923200", "value": "11.86" }, - { "UTCDate": "2016-08-01", "unixTimeStamp": "1470009600", "value": "11.04" }, - { "UTCDate": "2016-08-02", "unixTimeStamp": "1470096000", "value": "8.30" }, - { "UTCDate": "2016-08-03", "unixTimeStamp": "1470182400", "value": "10.42" }, - { "UTCDate": "2016-08-04", "unixTimeStamp": "1470268800", "value": "11.21" }, - { "UTCDate": "2016-08-05", "unixTimeStamp": "1470355200", "value": "11.05" }, - { "UTCDate": "2016-08-06", "unixTimeStamp": "1470441600", "value": "10.95" }, - { "UTCDate": "2016-08-07", "unixTimeStamp": "1470528000", "value": "10.98" }, - { "UTCDate": "2016-08-08", "unixTimeStamp": "1470614400", "value": "11.29" }, - { "UTCDate": "2016-08-09", "unixTimeStamp": "1470700800", "value": "12.22" }, - { "UTCDate": "2016-08-10", "unixTimeStamp": "1470787200", "value": "12.22" }, - { "UTCDate": "2016-08-11", "unixTimeStamp": "1470873600", "value": "11.68" }, - { "UTCDate": "2016-08-12", "unixTimeStamp": "1470960000", "value": "11.78" }, - { "UTCDate": "2016-08-13", "unixTimeStamp": "1471046400", "value": "11.56" }, - { "UTCDate": "2016-08-14", "unixTimeStamp": "1471132800", "value": "11.21" }, - { "UTCDate": "2016-08-15", "unixTimeStamp": "1471219200", "value": "11.21" }, - { "UTCDate": "2016-08-16", "unixTimeStamp": "1471305600", "value": "11.17" }, - { "UTCDate": "2016-08-17", "unixTimeStamp": "1471392000", "value": "10.77" }, - { "UTCDate": "2016-08-18", "unixTimeStamp": "1471478400", "value": "10.77" }, - { "UTCDate": "2016-08-19", "unixTimeStamp": "1471564800", "value": "10.71" }, - { "UTCDate": "2016-08-20", "unixTimeStamp": "1471651200", "value": "11.28" }, - { "UTCDate": "2016-08-21", "unixTimeStamp": "1471737600", "value": "11.14" }, - { "UTCDate": "2016-08-22", "unixTimeStamp": "1471824000", "value": "11.07" }, - { "UTCDate": "2016-08-23", "unixTimeStamp": "1471910400", "value": "11.01" }, - { "UTCDate": "2016-08-24", "unixTimeStamp": "1471996800", "value": "11.01" }, - { "UTCDate": "2016-08-25", "unixTimeStamp": "1472083200", "value": "11.35" }, - { "UTCDate": "2016-08-26", "unixTimeStamp": "1472169600", "value": "11.26" }, - { "UTCDate": "2016-08-27", "unixTimeStamp": "1472256000", "value": "11.19" }, - { "UTCDate": "2016-08-28", "unixTimeStamp": "1472342400", "value": "10.99" }, - { "UTCDate": "2016-08-29", "unixTimeStamp": "1472428800", "value": "10.95" }, - { "UTCDate": "2016-08-30", "unixTimeStamp": "1472515200", "value": "11.21" }, - { "UTCDate": "2016-08-31", "unixTimeStamp": "1472601600", "value": "11.55" }, - { "UTCDate": "2016-09-01", "unixTimeStamp": "1472688000", "value": "12.21" }, - { "UTCDate": "2016-09-02", "unixTimeStamp": "1472774400", "value": "12.08" }, - { "UTCDate": "2016-09-03", "unixTimeStamp": "1472860800", "value": "11.85" }, - { "UTCDate": "2016-09-04", "unixTimeStamp": "1472947200", "value": "11.71" }, - { "UTCDate": "2016-09-05", "unixTimeStamp": "1473033600", "value": "11.75" }, - { "UTCDate": "2016-09-06", "unixTimeStamp": "1473120000", "value": "11.70" }, - { "UTCDate": "2016-09-07", "unixTimeStamp": "1473206400", "value": "11.59" }, - { "UTCDate": "2016-09-08", "unixTimeStamp": "1473292800", "value": "11.39" }, - { "UTCDate": "2016-09-09", "unixTimeStamp": "1473379200", "value": "11.72" }, - { "UTCDate": "2016-09-10", "unixTimeStamp": "1473465600", "value": "12.05" }, - { "UTCDate": "2016-09-11", "unixTimeStamp": "1473552000", "value": "11.64" }, - { "UTCDate": "2016-09-12", "unixTimeStamp": "1473638400", "value": "11.89" }, - { "UTCDate": "2016-09-13", "unixTimeStamp": "1473724800", "value": "11.92" }, - { "UTCDate": "2016-09-14", "unixTimeStamp": "1473811200", "value": "11.97" }, - { "UTCDate": "2016-09-15", "unixTimeStamp": "1473897600", "value": "11.96" }, - { "UTCDate": "2016-09-16", "unixTimeStamp": "1473984000", "value": "12.61" }, - { "UTCDate": "2016-09-17", "unixTimeStamp": "1474070400", "value": "12.83" }, - { "UTCDate": "2016-09-18", "unixTimeStamp": "1474156800", "value": "12.39" }, - { "UTCDate": "2016-09-19", "unixTimeStamp": "1474243200", "value": "12.93" }, - { "UTCDate": "2016-09-20", "unixTimeStamp": "1474329600", "value": "14.72" }, - { "UTCDate": "2016-09-21", "unixTimeStamp": "1474416000", "value": "13.72" }, - { "UTCDate": "2016-09-22", "unixTimeStamp": "1474502400", "value": "13.11" }, - { "UTCDate": "2016-09-23", "unixTimeStamp": "1474588800", "value": "13.36" }, - { "UTCDate": "2016-09-24", "unixTimeStamp": "1474675200", "value": "12.91" }, - { "UTCDate": "2016-09-25", "unixTimeStamp": "1474761600", "value": "13.05" }, - { "UTCDate": "2016-09-26", "unixTimeStamp": "1474848000", "value": "12.89" }, - { "UTCDate": "2016-09-27", "unixTimeStamp": "1474934400", "value": "13.09" }, - { "UTCDate": "2016-09-28", "unixTimeStamp": "1475020800", "value": "13.30" }, - { "UTCDate": "2016-09-29", "unixTimeStamp": "1475107200", "value": "13.17" }, - { "UTCDate": "2016-09-30", "unixTimeStamp": "1475193600", "value": "13.24" }, - { "UTCDate": "2016-10-01", "unixTimeStamp": "1475280000", "value": "13.21" }, - { "UTCDate": "2016-10-02", "unixTimeStamp": "1475366400", "value": "13.23" }, - { "UTCDate": "2016-10-03", "unixTimeStamp": "1475452800", "value": "13.45" }, - { "UTCDate": "2016-10-04", "unixTimeStamp": "1475539200", "value": "13.32" }, - { "UTCDate": "2016-10-05", "unixTimeStamp": "1475625600", "value": "13.09" }, - { "UTCDate": "2016-10-06", "unixTimeStamp": "1475712000", "value": "12.87" }, - { "UTCDate": "2016-10-07", "unixTimeStamp": "1475798400", "value": "12.68" }, - { "UTCDate": "2016-10-08", "unixTimeStamp": "1475884800", "value": "12.24" }, - { "UTCDate": "2016-10-09", "unixTimeStamp": "1475971200", "value": "12.06" }, - { "UTCDate": "2016-10-10", "unixTimeStamp": "1476057600", "value": "11.74" }, - { "UTCDate": "2016-10-11", "unixTimeStamp": "1476144000", "value": "11.75" }, - { "UTCDate": "2016-10-12", "unixTimeStamp": "1476230400", "value": "11.77" }, - { "UTCDate": "2016-10-13", "unixTimeStamp": "1476316800", "value": "12.02" }, - { "UTCDate": "2016-10-14", "unixTimeStamp": "1476403200", "value": "11.90" }, - { "UTCDate": "2016-10-15", "unixTimeStamp": "1476489600", "value": "11.96" }, - { "UTCDate": "2016-10-16", "unixTimeStamp": "1476576000", "value": "11.93" }, - { "UTCDate": "2016-10-17", "unixTimeStamp": "1476662400", "value": "11.98" }, - { "UTCDate": "2016-10-18", "unixTimeStamp": "1476748800", "value": "12.50" }, - { "UTCDate": "2016-10-19", "unixTimeStamp": "1476835200", "value": "11.98" }, - { "UTCDate": "2016-10-20", "unixTimeStamp": "1476921600", "value": "12.05" }, - { "UTCDate": "2016-10-21", "unixTimeStamp": "1477008000", "value": "12.07" }, - { "UTCDate": "2016-10-22", "unixTimeStamp": "1477094400", "value": "12.06" }, - { "UTCDate": "2016-10-23", "unixTimeStamp": "1477180800", "value": "11.95" }, - { "UTCDate": "2016-10-24", "unixTimeStamp": "1477267200", "value": "11.93" }, - { "UTCDate": "2016-10-25", "unixTimeStamp": "1477353600", "value": "11.38" }, - { "UTCDate": "2016-10-26", "unixTimeStamp": "1477440000", "value": "11.50" }, - { "UTCDate": "2016-10-27", "unixTimeStamp": "1477526400", "value": "11.43" }, - { "UTCDate": "2016-10-28", "unixTimeStamp": "1477612800", "value": "11.08" }, - { "UTCDate": "2016-10-29", "unixTimeStamp": "1477699200", "value": "10.39" }, - { "UTCDate": "2016-10-30", "unixTimeStamp": "1477785600", "value": "11.22" }, - { "UTCDate": "2016-10-31", "unixTimeStamp": "1477872000", "value": "10.91" }, - { "UTCDate": "2016-11-01", "unixTimeStamp": "1477958400", "value": "10.75" }, - { "UTCDate": "2016-11-02", "unixTimeStamp": "1478044800", "value": "10.82" }, - { "UTCDate": "2016-11-03", "unixTimeStamp": "1478131200", "value": "10.86" }, - { "UTCDate": "2016-11-04", "unixTimeStamp": "1478217600", "value": "11.13" }, - { "UTCDate": "2016-11-05", "unixTimeStamp": "1478304000", "value": "11.11" }, - { "UTCDate": "2016-11-06", "unixTimeStamp": "1478390400", "value": "10.97" }, - { "UTCDate": "2016-11-07", "unixTimeStamp": "1478476800", "value": "10.90" }, - { "UTCDate": "2016-11-08", "unixTimeStamp": "1478563200", "value": "10.86" }, - { "UTCDate": "2016-11-09", "unixTimeStamp": "1478649600", "value": "10.64" }, - { "UTCDate": "2016-11-10", "unixTimeStamp": "1478736000", "value": "10.52" }, - { "UTCDate": "2016-11-11", "unixTimeStamp": "1478822400", "value": "10.29" }, - { "UTCDate": "2016-11-12", "unixTimeStamp": "1478908800", "value": "9.96" }, - { "UTCDate": "2016-11-13", "unixTimeStamp": "1478995200", "value": "10.13" }, - { "UTCDate": "2016-11-14", "unixTimeStamp": "1479081600", "value": "10.00" }, - { "UTCDate": "2016-11-15", "unixTimeStamp": "1479168000", "value": "10.22" }, - { "UTCDate": "2016-11-16", "unixTimeStamp": "1479254400", "value": "10.01" }, - { "UTCDate": "2016-11-17", "unixTimeStamp": "1479340800", "value": "9.95" }, - { "UTCDate": "2016-11-18", "unixTimeStamp": "1479427200", "value": "9.53" }, - { "UTCDate": "2016-11-19", "unixTimeStamp": "1479513600", "value": "9.70" }, - { "UTCDate": "2016-11-20", "unixTimeStamp": "1479600000", "value": "9.57" }, - { "UTCDate": "2016-11-21", "unixTimeStamp": "1479686400", "value": "9.56" }, - { "UTCDate": "2016-11-22", "unixTimeStamp": "1479772800", "value": "9.84" }, - { "UTCDate": "2016-11-23", "unixTimeStamp": "1479859200", "value": "9.78" }, - { "UTCDate": "2016-11-24", "unixTimeStamp": "1479945600", "value": "9.22" }, - { "UTCDate": "2016-11-25", "unixTimeStamp": "1480032000", "value": "9.39" }, - { "UTCDate": "2016-11-26", "unixTimeStamp": "1480118400", "value": "9.34" }, - { "UTCDate": "2016-11-27", "unixTimeStamp": "1480204800", "value": "8.91" }, - { "UTCDate": "2016-11-28", "unixTimeStamp": "1480291200", "value": "8.67" }, - { "UTCDate": "2016-11-29", "unixTimeStamp": "1480377600", "value": "8.18" }, - { "UTCDate": "2016-11-30", "unixTimeStamp": "1480464000", "value": "8.59" }, - { "UTCDate": "2016-12-01", "unixTimeStamp": "1480550400", "value": "8.44" }, - { "UTCDate": "2016-12-02", "unixTimeStamp": "1480636800", "value": "7.65" }, - { "UTCDate": "2016-12-03", "unixTimeStamp": "1480723200", "value": "7.90" }, - { "UTCDate": "2016-12-04", "unixTimeStamp": "1480809600", "value": "7.54" }, - { "UTCDate": "2016-12-05", "unixTimeStamp": "1480896000", "value": "6.69" }, - { "UTCDate": "2016-12-06", "unixTimeStamp": "1480982400", "value": "7.61" }, - { "UTCDate": "2016-12-07", "unixTimeStamp": "1481068800", "value": "8.35" }, - { "UTCDate": "2016-12-08", "unixTimeStamp": "1481155200", "value": "8.30" }, - { "UTCDate": "2016-12-09", "unixTimeStamp": "1481241600", "value": "8.52" }, - { "UTCDate": "2016-12-10", "unixTimeStamp": "1481328000", "value": "8.09" }, - { "UTCDate": "2016-12-11", "unixTimeStamp": "1481414400", "value": "8.20" }, - { "UTCDate": "2016-12-12", "unixTimeStamp": "1481500800", "value": "8.45" }, - { "UTCDate": "2016-12-13", "unixTimeStamp": "1481587200", "value": "8.40" }, - { "UTCDate": "2016-12-14", "unixTimeStamp": "1481673600", "value": "8.23" }, - { "UTCDate": "2016-12-15", "unixTimeStamp": "1481760000", "value": "7.76" }, - { "UTCDate": "2016-12-16", "unixTimeStamp": "1481846400", "value": "7.85" }, - { "UTCDate": "2016-12-17", "unixTimeStamp": "1481932800", "value": "7.66" }, - { "UTCDate": "2016-12-18", "unixTimeStamp": "1482019200", "value": "7.89" }, - { "UTCDate": "2016-12-19", "unixTimeStamp": "1482105600", "value": "7.61" }, - { "UTCDate": "2016-12-20", "unixTimeStamp": "1482192000", "value": "7.59" }, - { "UTCDate": "2016-12-21", "unixTimeStamp": "1482278400", "value": "7.87" }, - { "UTCDate": "2016-12-22", "unixTimeStamp": "1482364800", "value": "7.64" }, - { "UTCDate": "2016-12-23", "unixTimeStamp": "1482451200", "value": "7.16" }, - { "UTCDate": "2016-12-24", "unixTimeStamp": "1482537600", "value": "7.23" }, - { "UTCDate": "2016-12-25", "unixTimeStamp": "1482624000", "value": "7.19" }, - { "UTCDate": "2016-12-26", "unixTimeStamp": "1482710400", "value": "7.21" }, - { "UTCDate": "2016-12-27", "unixTimeStamp": "1482796800", "value": "7.15" }, - { "UTCDate": "2016-12-28", "unixTimeStamp": "1482883200", "value": "7.57" }, - { "UTCDate": "2016-12-29", "unixTimeStamp": "1482969600", "value": "8.21" }, - { "UTCDate": "2016-12-30", "unixTimeStamp": "1483056000", "value": "8.16" }, - { "UTCDate": "2016-12-31", "unixTimeStamp": "1483142400", "value": "8.05" }, - { "UTCDate": "2017-01-01", "unixTimeStamp": "1483228800", "value": "8.14" }, - { "UTCDate": "2017-01-02", "unixTimeStamp": "1483315200", "value": "8.34" }, - { "UTCDate": "2017-01-03", "unixTimeStamp": "1483401600", "value": "9.60" }, - { "UTCDate": "2017-01-04", "unixTimeStamp": "1483488000", "value": "10.88" }, - { "UTCDate": "2017-01-05", "unixTimeStamp": "1483574400", "value": "10.20" }, - { "UTCDate": "2017-01-06", "unixTimeStamp": "1483660800", "value": "10.07" }, - { "UTCDate": "2017-01-07", "unixTimeStamp": "1483747200", "value": "9.79" }, - { "UTCDate": "2017-01-08", "unixTimeStamp": "1483833600", "value": "10.27" }, - { "UTCDate": "2017-01-09", "unixTimeStamp": "1483920000", "value": "10.20" }, - { "UTCDate": "2017-01-10", "unixTimeStamp": "1484006400", "value": "10.55" }, - { "UTCDate": "2017-01-11", "unixTimeStamp": "1484092800", "value": "9.83" }, - { "UTCDate": "2017-01-12", "unixTimeStamp": "1484179200", "value": "9.81" }, - { "UTCDate": "2017-01-13", "unixTimeStamp": "1484265600", "value": "9.78" }, - { "UTCDate": "2017-01-14", "unixTimeStamp": "1484352000", "value": "9.78" }, - { "UTCDate": "2017-01-15", "unixTimeStamp": "1484438400", "value": "9.88" }, - { "UTCDate": "2017-01-16", "unixTimeStamp": "1484524800", "value": "9.59" }, - { "UTCDate": "2017-01-17", "unixTimeStamp": "1484611200", "value": "10.14" }, - { "UTCDate": "2017-01-18", "unixTimeStamp": "1484697600", "value": "10.19" }, - { "UTCDate": "2017-01-19", "unixTimeStamp": "1484784000", "value": "10.43" }, - { "UTCDate": "2017-01-20", "unixTimeStamp": "1484870400", "value": "10.60" }, - { "UTCDate": "2017-01-21", "unixTimeStamp": "1484956800", "value": "10.91" }, - { "UTCDate": "2017-01-22", "unixTimeStamp": "1485043200", "value": "10.71" }, - { "UTCDate": "2017-01-23", "unixTimeStamp": "1485129600", "value": "10.78" }, - { "UTCDate": "2017-01-24", "unixTimeStamp": "1485216000", "value": "10.51" }, - { "UTCDate": "2017-01-25", "unixTimeStamp": "1485302400", "value": "10.51" }, - { "UTCDate": "2017-01-26", "unixTimeStamp": "1485388800", "value": "10.65" }, - { "UTCDate": "2017-01-27", "unixTimeStamp": "1485475200", "value": "10.51" }, - { "UTCDate": "2017-01-28", "unixTimeStamp": "1485561600", "value": "10.54" }, - { "UTCDate": "2017-01-29", "unixTimeStamp": "1485648000", "value": "10.47" }, - { "UTCDate": "2017-01-30", "unixTimeStamp": "1485734400", "value": "10.62" }, - { "UTCDate": "2017-01-31", "unixTimeStamp": "1485820800", "value": "10.71" }, - { "UTCDate": "2017-02-01", "unixTimeStamp": "1485907200", "value": "10.71" }, - { "UTCDate": "2017-02-02", "unixTimeStamp": "1485993600", "value": "10.78" }, - { "UTCDate": "2017-02-03", "unixTimeStamp": "1486080000", "value": "10.95" }, - { "UTCDate": "2017-02-04", "unixTimeStamp": "1486166400", "value": "11.32" }, - { "UTCDate": "2017-02-05", "unixTimeStamp": "1486252800", "value": "11.22" }, - { "UTCDate": "2017-02-06", "unixTimeStamp": "1486339200", "value": "11.32" }, - { "UTCDate": "2017-02-07", "unixTimeStamp": "1486425600", "value": "11.45" }, - { "UTCDate": "2017-02-08", "unixTimeStamp": "1486512000", "value": "11.39" }, - { "UTCDate": "2017-02-09", "unixTimeStamp": "1486598400", "value": "10.94" }, - { "UTCDate": "2017-02-10", "unixTimeStamp": "1486684800", "value": "11.34" }, - { "UTCDate": "2017-02-11", "unixTimeStamp": "1486771200", "value": "11.43" }, - { "UTCDate": "2017-02-12", "unixTimeStamp": "1486857600", "value": "11.42" }, - { "UTCDate": "2017-02-13", "unixTimeStamp": "1486944000", "value": "11.39" }, - { "UTCDate": "2017-02-14", "unixTimeStamp": "1487030400", "value": "13.00" }, - { "UTCDate": "2017-02-15", "unixTimeStamp": "1487116800", "value": "12.97" }, - { "UTCDate": "2017-02-16", "unixTimeStamp": "1487203200", "value": "12.95" }, - { "UTCDate": "2017-02-17", "unixTimeStamp": "1487289600", "value": "12.72" }, - { "UTCDate": "2017-02-18", "unixTimeStamp": "1487376000", "value": "12.83" }, - { "UTCDate": "2017-02-19", "unixTimeStamp": "1487462400", "value": "12.82" }, - { "UTCDate": "2017-02-20", "unixTimeStamp": "1487548800", "value": "12.52" }, - { "UTCDate": "2017-02-21", "unixTimeStamp": "1487635200", "value": "12.77" }, - { "UTCDate": "2017-02-22", "unixTimeStamp": "1487721600", "value": "12.69" }, - { "UTCDate": "2017-02-23", "unixTimeStamp": "1487808000", "value": "13.13" }, - { "UTCDate": "2017-02-24", "unixTimeStamp": "1487894400", "value": "13.11" }, - { "UTCDate": "2017-02-25", "unixTimeStamp": "1487980800", "value": "13.57" }, - { "UTCDate": "2017-02-26", "unixTimeStamp": "1488067200", "value": "14.59" }, - { "UTCDate": "2017-02-27", "unixTimeStamp": "1488153600", "value": "15.55" }, - { "UTCDate": "2017-02-28", "unixTimeStamp": "1488240000", "value": "16.07" }, - { "UTCDate": "2017-03-01", "unixTimeStamp": "1488326400", "value": "17.55" }, - { "UTCDate": "2017-03-02", "unixTimeStamp": "1488412800", "value": "19.08" }, - { "UTCDate": "2017-03-03", "unixTimeStamp": "1488499200", "value": "19.48" }, - { "UTCDate": "2017-03-04", "unixTimeStamp": "1488585600", "value": "18.61" }, - { "UTCDate": "2017-03-05", "unixTimeStamp": "1488672000", "value": "19.22" }, - { "UTCDate": "2017-03-06", "unixTimeStamp": "1488758400", "value": "19.75" }, - { "UTCDate": "2017-03-07", "unixTimeStamp": "1488844800", "value": "18.91" }, - { "UTCDate": "2017-03-08", "unixTimeStamp": "1488931200", "value": "16.54" }, - { "UTCDate": "2017-03-09", "unixTimeStamp": "1489017600", "value": "17.71" }, - { "UTCDate": "2017-03-10", "unixTimeStamp": "1489104000", "value": "19.13" }, - { "UTCDate": "2017-03-11", "unixTimeStamp": "1489190400", "value": "21.45" }, - { "UTCDate": "2017-03-12", "unixTimeStamp": "1489276800", "value": "23.31" }, - { "UTCDate": "2017-03-13", "unixTimeStamp": "1489363200", "value": "28.45" }, - { "UTCDate": "2017-03-14", "unixTimeStamp": "1489449600", "value": "28.58" }, - { "UTCDate": "2017-03-15", "unixTimeStamp": "1489536000", "value": "35.18" }, - { "UTCDate": "2017-03-16", "unixTimeStamp": "1489622400", "value": "45.51" }, - { "UTCDate": "2017-03-17", "unixTimeStamp": "1489708800", "value": "44.48" }, - { "UTCDate": "2017-03-18", "unixTimeStamp": "1489795200", "value": "34.00" }, - { "UTCDate": "2017-03-19", "unixTimeStamp": "1489881600", "value": "43.12" }, - { "UTCDate": "2017-03-20", "unixTimeStamp": "1489968000", "value": "42.51" }, - { "UTCDate": "2017-03-21", "unixTimeStamp": "1490054400", "value": "42.67" }, - { "UTCDate": "2017-03-22", "unixTimeStamp": "1490140800", "value": "41.65" }, - { "UTCDate": "2017-03-23", "unixTimeStamp": "1490227200", "value": "43.20" }, - { "UTCDate": "2017-03-24", "unixTimeStamp": "1490313600", "value": "53.19" }, - { "UTCDate": "2017-03-25", "unixTimeStamp": "1490400000", "value": "50.62" }, - { "UTCDate": "2017-03-26", "unixTimeStamp": "1490486400", "value": "50.63" }, - { "UTCDate": "2017-03-27", "unixTimeStamp": "1490572800", "value": "49.06" }, - { "UTCDate": "2017-03-28", "unixTimeStamp": "1490659200", "value": "50.25" }, - { "UTCDate": "2017-03-29", "unixTimeStamp": "1490745600", "value": "53.07" }, - { "UTCDate": "2017-03-30", "unixTimeStamp": "1490832000", "value": "51.91" }, - { "UTCDate": "2017-03-31", "unixTimeStamp": "1490918400", "value": "49.91" }, - { "UTCDate": "2017-04-01", "unixTimeStamp": "1491004800", "value": "50.60" }, - { "UTCDate": "2017-04-02", "unixTimeStamp": "1491091200", "value": "48.55" }, - { "UTCDate": "2017-04-03", "unixTimeStamp": "1491177600", "value": "44.13" }, - { "UTCDate": "2017-04-04", "unixTimeStamp": "1491264000", "value": "44.43" }, - { "UTCDate": "2017-04-05", "unixTimeStamp": "1491350400", "value": "44.90" }, - { "UTCDate": "2017-04-06", "unixTimeStamp": "1491436800", "value": "43.23" }, - { "UTCDate": "2017-04-07", "unixTimeStamp": "1491523200", "value": "42.31" }, - { "UTCDate": "2017-04-08", "unixTimeStamp": "1491609600", "value": "44.37" }, - { "UTCDate": "2017-04-09", "unixTimeStamp": "1491696000", "value": "43.72" }, - { "UTCDate": "2017-04-10", "unixTimeStamp": "1491782400", "value": "43.74" }, - { "UTCDate": "2017-04-11", "unixTimeStamp": "1491868800", "value": "43.74" }, - { "UTCDate": "2017-04-12", "unixTimeStamp": "1491955200", "value": "46.38" }, - { "UTCDate": "2017-04-13", "unixTimeStamp": "1492041600", "value": "49.97" }, - { "UTCDate": "2017-04-14", "unixTimeStamp": "1492128000", "value": "47.32" }, - { "UTCDate": "2017-04-15", "unixTimeStamp": "1492214400", "value": "48.89" }, - { "UTCDate": "2017-04-16", "unixTimeStamp": "1492300800", "value": "48.22" }, - { "UTCDate": "2017-04-17", "unixTimeStamp": "1492387200", "value": "47.94" }, - { "UTCDate": "2017-04-18", "unixTimeStamp": "1492473600", "value": "49.88" }, - { "UTCDate": "2017-04-19", "unixTimeStamp": "1492560000", "value": "47.88" }, - { "UTCDate": "2017-04-20", "unixTimeStamp": "1492646400", "value": "49.36" }, - { "UTCDate": "2017-04-21", "unixTimeStamp": "1492732800", "value": "48.27" }, - { "UTCDate": "2017-04-22", "unixTimeStamp": "1492819200", "value": "48.41" }, - { "UTCDate": "2017-04-23", "unixTimeStamp": "1492905600", "value": "48.75" }, - { "UTCDate": "2017-04-24", "unixTimeStamp": "1492992000", "value": "49.94" }, - { "UTCDate": "2017-04-25", "unixTimeStamp": "1493078400", "value": "50.09" }, - { "UTCDate": "2017-04-26", "unixTimeStamp": "1493164800", "value": "53.28" }, - { "UTCDate": "2017-04-27", "unixTimeStamp": "1493251200", "value": "63.14" }, - { "UTCDate": "2017-04-28", "unixTimeStamp": "1493337600", "value": "72.42" }, - { "UTCDate": "2017-04-29", "unixTimeStamp": "1493424000", "value": "69.83" }, - { "UTCDate": "2017-04-30", "unixTimeStamp": "1493510400", "value": "79.83" }, - { "UTCDate": "2017-05-01", "unixTimeStamp": "1493596800", "value": "77.53" }, - { "UTCDate": "2017-05-02", "unixTimeStamp": "1493683200", "value": "77.25" }, - { "UTCDate": "2017-05-03", "unixTimeStamp": "1493769600", "value": "80.37" }, - { "UTCDate": "2017-05-04", "unixTimeStamp": "1493856000", "value": "94.55" }, - { "UTCDate": "2017-05-05", "unixTimeStamp": "1493942400", "value": "90.79" }, - { "UTCDate": "2017-05-06", "unixTimeStamp": "1494028800", "value": "94.82" }, - { "UTCDate": "2017-05-07", "unixTimeStamp": "1494115200", "value": "90.46" }, - { "UTCDate": "2017-05-08", "unixTimeStamp": "1494201600", "value": "88.39" }, - { "UTCDate": "2017-05-09", "unixTimeStamp": "1494288000", "value": "86.27" }, - { "UTCDate": "2017-05-10", "unixTimeStamp": "1494374400", "value": "87.83" }, - { "UTCDate": "2017-05-11", "unixTimeStamp": "1494460800", "value": "88.20" }, - { "UTCDate": "2017-05-12", "unixTimeStamp": "1494547200", "value": "85.15" }, - { "UTCDate": "2017-05-13", "unixTimeStamp": "1494633600", "value": "87.96" }, - { "UTCDate": "2017-05-14", "unixTimeStamp": "1494720000", "value": "88.72" }, - { "UTCDate": "2017-05-15", "unixTimeStamp": "1494806400", "value": "90.32" }, - { "UTCDate": "2017-05-16", "unixTimeStamp": "1494892800", "value": "87.80" }, - { "UTCDate": "2017-05-17", "unixTimeStamp": "1494979200", "value": "86.98" }, - { "UTCDate": "2017-05-18", "unixTimeStamp": "1495065600", "value": "95.88" }, - { "UTCDate": "2017-05-19", "unixTimeStamp": "1495152000", "value": "124.38" }, - { "UTCDate": "2017-05-20", "unixTimeStamp": "1495238400", "value": "123.06" }, - { "UTCDate": "2017-05-21", "unixTimeStamp": "1495324800", "value": "148.00" }, - { "UTCDate": "2017-05-22", "unixTimeStamp": "1495411200", "value": "160.39" }, - { "UTCDate": "2017-05-23", "unixTimeStamp": "1495497600", "value": "169.50" }, - { "UTCDate": "2017-05-24", "unixTimeStamp": "1495584000", "value": "193.03" }, - { "UTCDate": "2017-05-25", "unixTimeStamp": "1495670400", "value": "177.33" }, - { "UTCDate": "2017-05-26", "unixTimeStamp": "1495756800", "value": "162.83" }, - { "UTCDate": "2017-05-27", "unixTimeStamp": "1495843200", "value": "156.63" }, - { "UTCDate": "2017-05-28", "unixTimeStamp": "1495929600", "value": "172.86" }, - { "UTCDate": "2017-05-29", "unixTimeStamp": "1496016000", "value": "194.17" }, - { "UTCDate": "2017-05-30", "unixTimeStamp": "1496102400", "value": "228.58" }, - { "UTCDate": "2017-05-31", "unixTimeStamp": "1496188800", "value": "228.64" }, - { "UTCDate": "2017-06-01", "unixTimeStamp": "1496275200", "value": "220.70" }, - { "UTCDate": "2017-06-02", "unixTimeStamp": "1496361600", "value": "222.04" }, - { "UTCDate": "2017-06-03", "unixTimeStamp": "1496448000", "value": "224.30" }, - { "UTCDate": "2017-06-04", "unixTimeStamp": "1496534400", "value": "244.96" }, - { "UTCDate": "2017-06-05", "unixTimeStamp": "1496620800", "value": "247.75" }, - { "UTCDate": "2017-06-06", "unixTimeStamp": "1496707200", "value": "264.26" }, - { "UTCDate": "2017-06-07", "unixTimeStamp": "1496793600", "value": "255.77" }, - { "UTCDate": "2017-06-08", "unixTimeStamp": "1496880000", "value": "259.41" }, - { "UTCDate": "2017-06-09", "unixTimeStamp": "1496966400", "value": "279.11" }, - { "UTCDate": "2017-06-10", "unixTimeStamp": "1497052800", "value": "335.95" }, - { "UTCDate": "2017-06-11", "unixTimeStamp": "1497139200", "value": "339.68" }, - { "UTCDate": "2017-06-12", "unixTimeStamp": "1497225600", "value": "394.66" }, - { "UTCDate": "2017-06-13", "unixTimeStamp": "1497312000", "value": "388.09" }, - { "UTCDate": "2017-06-14", "unixTimeStamp": "1497398400", "value": "343.84" }, - { "UTCDate": "2017-06-15", "unixTimeStamp": "1497484800", "value": "344.68" }, - { "UTCDate": "2017-06-16", "unixTimeStamp": "1497571200", "value": "353.61" }, - { "UTCDate": "2017-06-17", "unixTimeStamp": "1497657600", "value": "368.10" }, - { "UTCDate": "2017-06-18", "unixTimeStamp": "1497744000", "value": "351.53" }, - { "UTCDate": "2017-06-19", "unixTimeStamp": "1497830400", "value": "358.20" }, - { "UTCDate": "2017-06-20", "unixTimeStamp": "1497916800", "value": "350.53" }, - { "UTCDate": "2017-06-21", "unixTimeStamp": "1498003200", "value": "325.30" }, - { "UTCDate": "2017-06-22", "unixTimeStamp": "1498089600", "value": "320.97" }, - { "UTCDate": "2017-06-23", "unixTimeStamp": "1498176000", "value": "326.85" }, - { "UTCDate": "2017-06-24", "unixTimeStamp": "1498262400", "value": "304.54" }, - { "UTCDate": "2017-06-25", "unixTimeStamp": "1498348800", "value": "279.36" }, - { "UTCDate": "2017-06-26", "unixTimeStamp": "1498435200", "value": "253.68" }, - { "UTCDate": "2017-06-27", "unixTimeStamp": "1498521600", "value": "286.14" }, - { "UTCDate": "2017-06-28", "unixTimeStamp": "1498608000", "value": "315.86" }, - { "UTCDate": "2017-06-29", "unixTimeStamp": "1498694400", "value": "292.90" }, - { "UTCDate": "2017-06-30", "unixTimeStamp": "1498780800", "value": "280.68" }, - { "UTCDate": "2017-07-01", "unixTimeStamp": "1498867200", "value": "261.00" }, - { "UTCDate": "2017-07-02", "unixTimeStamp": "1498953600", "value": "283.99" }, - { "UTCDate": "2017-07-03", "unixTimeStamp": "1499040000", "value": "276.41" }, - { "UTCDate": "2017-07-04", "unixTimeStamp": "1499126400", "value": "269.05" }, - { "UTCDate": "2017-07-05", "unixTimeStamp": "1499212800", "value": "266.00" }, - { "UTCDate": "2017-07-06", "unixTimeStamp": "1499299200", "value": "265.88" }, - { "UTCDate": "2017-07-07", "unixTimeStamp": "1499385600", "value": "240.94" }, - { "UTCDate": "2017-07-08", "unixTimeStamp": "1499472000", "value": "245.67" }, - { "UTCDate": "2017-07-09", "unixTimeStamp": "1499558400", "value": "237.72" }, - { "UTCDate": "2017-07-10", "unixTimeStamp": "1499644800", "value": "205.76" }, - { "UTCDate": "2017-07-11", "unixTimeStamp": "1499731200", "value": "190.55" }, - { "UTCDate": "2017-07-12", "unixTimeStamp": "1499817600", "value": "224.15" }, - { "UTCDate": "2017-07-13", "unixTimeStamp": "1499904000", "value": "205.41" }, - { "UTCDate": "2017-07-14", "unixTimeStamp": "1499990400", "value": "197.14" }, - { "UTCDate": "2017-07-15", "unixTimeStamp": "1500076800", "value": "169.10" }, - { "UTCDate": "2017-07-16", "unixTimeStamp": "1500163200", "value": "155.42" }, - { "UTCDate": "2017-07-17", "unixTimeStamp": "1500249600", "value": "189.97" }, - { "UTCDate": "2017-07-18", "unixTimeStamp": "1500336000", "value": "227.09" }, - { "UTCDate": "2017-07-19", "unixTimeStamp": "1500422400", "value": "194.41" }, - { "UTCDate": "2017-07-20", "unixTimeStamp": "1500508800", "value": "226.33" }, - { "UTCDate": "2017-07-21", "unixTimeStamp": "1500595200", "value": "216.33" }, - { "UTCDate": "2017-07-22", "unixTimeStamp": "1500681600", "value": "230.47" }, - { "UTCDate": "2017-07-23", "unixTimeStamp": "1500768000", "value": "228.32" }, - { "UTCDate": "2017-07-24", "unixTimeStamp": "1500854400", "value": "225.48" }, - { "UTCDate": "2017-07-25", "unixTimeStamp": "1500940800", "value": "203.59" }, - { "UTCDate": "2017-07-26", "unixTimeStamp": "1501027200", "value": "202.88" }, - { "UTCDate": "2017-07-27", "unixTimeStamp": "1501113600", "value": "202.93" }, - { "UTCDate": "2017-07-28", "unixTimeStamp": "1501200000", "value": "191.21" }, - { "UTCDate": "2017-07-29", "unixTimeStamp": "1501286400", "value": "206.14" }, - { "UTCDate": "2017-07-30", "unixTimeStamp": "1501372800", "value": "196.78" }, - { "UTCDate": "2017-07-31", "unixTimeStamp": "1501459200", "value": "201.33" }, - { "UTCDate": "2017-08-01", "unixTimeStamp": "1501545600", "value": "225.90" }, - { "UTCDate": "2017-08-02", "unixTimeStamp": "1501632000", "value": "218.12" }, - { "UTCDate": "2017-08-03", "unixTimeStamp": "1501718400", "value": "224.39" }, - { "UTCDate": "2017-08-04", "unixTimeStamp": "1501804800", "value": "220.60" }, - { "UTCDate": "2017-08-05", "unixTimeStamp": "1501891200", "value": "253.09" }, - { "UTCDate": "2017-08-06", "unixTimeStamp": "1501977600", "value": "264.56" }, - { "UTCDate": "2017-08-07", "unixTimeStamp": "1502064000", "value": "269.94" }, - { "UTCDate": "2017-08-08", "unixTimeStamp": "1502150400", "value": "296.51" }, - { "UTCDate": "2017-08-09", "unixTimeStamp": "1502236800", "value": "295.28" }, - { "UTCDate": "2017-08-10", "unixTimeStamp": "1502323200", "value": "298.28" }, - { "UTCDate": "2017-08-11", "unixTimeStamp": "1502409600", "value": "309.32" }, - { "UTCDate": "2017-08-12", "unixTimeStamp": "1502496000", "value": "308.02" }, - { "UTCDate": "2017-08-13", "unixTimeStamp": "1502582400", "value": "296.62" }, - { "UTCDate": "2017-08-14", "unixTimeStamp": "1502668800", "value": "299.16" }, - { "UTCDate": "2017-08-15", "unixTimeStamp": "1502755200", "value": "286.52" }, - { "UTCDate": "2017-08-16", "unixTimeStamp": "1502841600", "value": "301.38" }, - { "UTCDate": "2017-08-17", "unixTimeStamp": "1502928000", "value": "300.30" }, - { "UTCDate": "2017-08-18", "unixTimeStamp": "1503014400", "value": "292.62" }, - { "UTCDate": "2017-08-19", "unixTimeStamp": "1503100800", "value": "293.02" }, - { "UTCDate": "2017-08-20", "unixTimeStamp": "1503187200", "value": "298.20" }, - { "UTCDate": "2017-08-21", "unixTimeStamp": "1503273600", "value": "321.85" }, - { "UTCDate": "2017-08-22", "unixTimeStamp": "1503360000", "value": "313.37" }, - { "UTCDate": "2017-08-23", "unixTimeStamp": "1503446400", "value": "317.40" }, - { "UTCDate": "2017-08-24", "unixTimeStamp": "1503532800", "value": "325.28" }, - { "UTCDate": "2017-08-25", "unixTimeStamp": "1503619200", "value": "330.06" }, - { "UTCDate": "2017-08-26", "unixTimeStamp": "1503705600", "value": "332.86" }, - { "UTCDate": "2017-08-27", "unixTimeStamp": "1503792000", "value": "347.88" }, - { "UTCDate": "2017-08-28", "unixTimeStamp": "1503878400", "value": "347.66" }, - { "UTCDate": "2017-08-29", "unixTimeStamp": "1503964800", "value": "372.35" }, - { "UTCDate": "2017-08-30", "unixTimeStamp": "1504051200", "value": "383.86" }, - { "UTCDate": "2017-08-31", "unixTimeStamp": "1504137600", "value": "388.33" }, - { "UTCDate": "2017-09-01", "unixTimeStamp": "1504224000", "value": "391.42" }, - { "UTCDate": "2017-09-02", "unixTimeStamp": "1504310400", "value": "351.03" }, - { "UTCDate": "2017-09-03", "unixTimeStamp": "1504396800", "value": "352.45" }, - { "UTCDate": "2017-09-04", "unixTimeStamp": "1504483200", "value": "303.70" }, - { "UTCDate": "2017-09-05", "unixTimeStamp": "1504569600", "value": "317.94" }, - { "UTCDate": "2017-09-06", "unixTimeStamp": "1504656000", "value": "338.92" }, - { "UTCDate": "2017-09-07", "unixTimeStamp": "1504742400", "value": "335.37" }, - { "UTCDate": "2017-09-08", "unixTimeStamp": "1504828800", "value": "306.72" }, - { "UTCDate": "2017-09-09", "unixTimeStamp": "1504915200", "value": "303.79" }, - { "UTCDate": "2017-09-10", "unixTimeStamp": "1505001600", "value": "299.21" }, - { "UTCDate": "2017-09-11", "unixTimeStamp": "1505088000", "value": "297.95" }, - { "UTCDate": "2017-09-12", "unixTimeStamp": "1505174400", "value": "294.10" }, - { "UTCDate": "2017-09-13", "unixTimeStamp": "1505260800", "value": "275.84" }, - { "UTCDate": "2017-09-14", "unixTimeStamp": "1505347200", "value": "223.14" }, - { "UTCDate": "2017-09-15", "unixTimeStamp": "1505433600", "value": "259.57" }, - { "UTCDate": "2017-09-16", "unixTimeStamp": "1505520000", "value": "254.49" }, - { "UTCDate": "2017-09-17", "unixTimeStamp": "1505606400", "value": "258.40" }, - { "UTCDate": "2017-09-18", "unixTimeStamp": "1505692800", "value": "297.53" }, - { "UTCDate": "2017-09-19", "unixTimeStamp": "1505779200", "value": "283.00" }, - { "UTCDate": "2017-09-20", "unixTimeStamp": "1505865600", "value": "283.56" }, - { "UTCDate": "2017-09-21", "unixTimeStamp": "1505952000", "value": "257.77" }, - { "UTCDate": "2017-09-22", "unixTimeStamp": "1506038400", "value": "262.94" }, - { "UTCDate": "2017-09-23", "unixTimeStamp": "1506124800", "value": "286.14" }, - { "UTCDate": "2017-09-24", "unixTimeStamp": "1506211200", "value": "282.60" }, - { "UTCDate": "2017-09-25", "unixTimeStamp": "1506297600", "value": "294.89" }, - { "UTCDate": "2017-09-26", "unixTimeStamp": "1506384000", "value": "288.64" }, - { "UTCDate": "2017-09-27", "unixTimeStamp": "1506470400", "value": "309.97" }, - { "UTCDate": "2017-09-28", "unixTimeStamp": "1506556800", "value": "302.77" }, - { "UTCDate": "2017-09-29", "unixTimeStamp": "1506643200", "value": "292.58" }, - { "UTCDate": "2017-09-30", "unixTimeStamp": "1506729600", "value": "302.77" }, - { "UTCDate": "2017-10-01", "unixTimeStamp": "1506816000", "value": "303.95" }, - { "UTCDate": "2017-10-02", "unixTimeStamp": "1506902400", "value": "296.81" }, - { "UTCDate": "2017-10-03", "unixTimeStamp": "1506988800", "value": "291.81" }, - { "UTCDate": "2017-10-04", "unixTimeStamp": "1507075200", "value": "291.68" }, - { "UTCDate": "2017-10-05", "unixTimeStamp": "1507161600", "value": "294.99" }, - { "UTCDate": "2017-10-06", "unixTimeStamp": "1507248000", "value": "308.33" }, - { "UTCDate": "2017-10-07", "unixTimeStamp": "1507334400", "value": "311.26" }, - { "UTCDate": "2017-10-08", "unixTimeStamp": "1507420800", "value": "309.49" }, - { "UTCDate": "2017-10-09", "unixTimeStamp": "1507507200", "value": "296.95" }, - { "UTCDate": "2017-10-10", "unixTimeStamp": "1507593600", "value": "298.46" }, - { "UTCDate": "2017-10-11", "unixTimeStamp": "1507680000", "value": "302.86" }, - { "UTCDate": "2017-10-12", "unixTimeStamp": "1507766400", "value": "302.89" }, - { "UTCDate": "2017-10-13", "unixTimeStamp": "1507852800", "value": "336.83" }, - { "UTCDate": "2017-10-14", "unixTimeStamp": "1507939200", "value": "338.81" }, - { "UTCDate": "2017-10-15", "unixTimeStamp": "1508025600", "value": "336.58" }, - { "UTCDate": "2017-10-16", "unixTimeStamp": "1508112000", "value": "334.23" }, - { "UTCDate": "2017-10-17", "unixTimeStamp": "1508198400", "value": "316.14" }, - { "UTCDate": "2017-10-18", "unixTimeStamp": "1508284800", "value": "313.54" }, - { "UTCDate": "2017-10-19", "unixTimeStamp": "1508371200", "value": "307.41" }, - { "UTCDate": "2017-10-20", "unixTimeStamp": "1508457600", "value": "303.08" }, - { "UTCDate": "2017-10-21", "unixTimeStamp": "1508544000", "value": "299.55" }, - { "UTCDate": "2017-10-22", "unixTimeStamp": "1508630400", "value": "294.03" }, - { "UTCDate": "2017-10-23", "unixTimeStamp": "1508716800", "value": "285.27" }, - { "UTCDate": "2017-10-24", "unixTimeStamp": "1508803200", "value": "296.50" }, - { "UTCDate": "2017-10-25", "unixTimeStamp": "1508889600", "value": "296.35" }, - { "UTCDate": "2017-10-26", "unixTimeStamp": "1508976000", "value": "295.54" }, - { "UTCDate": "2017-10-27", "unixTimeStamp": "1509062400", "value": "296.36" }, - { "UTCDate": "2017-10-28", "unixTimeStamp": "1509148800", "value": "293.35" }, - { "UTCDate": "2017-10-29", "unixTimeStamp": "1509235200", "value": "304.04" }, - { "UTCDate": "2017-10-30", "unixTimeStamp": "1509321600", "value": "306.80" }, - { "UTCDate": "2017-10-31", "unixTimeStamp": "1509408000", "value": "303.64" }, - { "UTCDate": "2017-11-01", "unixTimeStamp": "1509494400", "value": "289.42" }, - { "UTCDate": "2017-11-02", "unixTimeStamp": "1509580800", "value": "284.92" }, - { "UTCDate": "2017-11-03", "unixTimeStamp": "1509667200", "value": "304.51" }, - { "UTCDate": "2017-11-04", "unixTimeStamp": "1509753600", "value": "300.04" }, - { "UTCDate": "2017-11-05", "unixTimeStamp": "1509840000", "value": "296.23" }, - { "UTCDate": "2017-11-06", "unixTimeStamp": "1509926400", "value": "296.82" }, - { "UTCDate": "2017-11-07", "unixTimeStamp": "1510012800", "value": "291.84" }, - { "UTCDate": "2017-11-08", "unixTimeStamp": "1510099200", "value": "307.35" }, - { "UTCDate": "2017-11-09", "unixTimeStamp": "1510185600", "value": "319.66" }, - { "UTCDate": "2017-11-10", "unixTimeStamp": "1510272000", "value": "296.86" }, - { "UTCDate": "2017-11-11", "unixTimeStamp": "1510358400", "value": "314.23" }, - { "UTCDate": "2017-11-12", "unixTimeStamp": "1510444800", "value": "306.02" }, - { "UTCDate": "2017-11-13", "unixTimeStamp": "1510531200", "value": "314.60" }, - { "UTCDate": "2017-11-14", "unixTimeStamp": "1510617600", "value": "334.72" }, - { "UTCDate": "2017-11-15", "unixTimeStamp": "1510704000", "value": "331.20" }, - { "UTCDate": "2017-11-16", "unixTimeStamp": "1510790400", "value": "330.32" }, - { "UTCDate": "2017-11-17", "unixTimeStamp": "1510876800", "value": "331.72" }, - { "UTCDate": "2017-11-18", "unixTimeStamp": "1510963200", "value": "346.65" }, - { "UTCDate": "2017-11-19", "unixTimeStamp": "1511049600", "value": "354.60" }, - { "UTCDate": "2017-11-20", "unixTimeStamp": "1511136000", "value": "367.71" }, - { "UTCDate": "2017-11-21", "unixTimeStamp": "1511222400", "value": "360.52" }, - { "UTCDate": "2017-11-22", "unixTimeStamp": "1511308800", "value": "380.84" }, - { "UTCDate": "2017-11-23", "unixTimeStamp": "1511395200", "value": "406.57" }, - { "UTCDate": "2017-11-24", "unixTimeStamp": "1511481600", "value": "470.43" }, - { "UTCDate": "2017-11-25", "unixTimeStamp": "1511568000", "value": "464.61" }, - { "UTCDate": "2017-11-26", "unixTimeStamp": "1511654400", "value": "470.54" }, - { "UTCDate": "2017-11-27", "unixTimeStamp": "1511740800", "value": "475.24" }, - { "UTCDate": "2017-11-28", "unixTimeStamp": "1511827200", "value": "466.27" }, - { "UTCDate": "2017-11-29", "unixTimeStamp": "1511913600", "value": "427.42" }, - { "UTCDate": "2017-11-30", "unixTimeStamp": "1512000000", "value": "434.85" }, - { "UTCDate": "2017-12-01", "unixTimeStamp": "1512086400", "value": "461.58" }, - { "UTCDate": "2017-12-02", "unixTimeStamp": "1512172800", "value": "457.96" }, - { "UTCDate": "2017-12-03", "unixTimeStamp": "1512259200", "value": "462.81" }, - { "UTCDate": "2017-12-04", "unixTimeStamp": "1512345600", "value": "466.93" }, - { "UTCDate": "2017-12-05", "unixTimeStamp": "1512432000", "value": "453.96" }, - { "UTCDate": "2017-12-06", "unixTimeStamp": "1512518400", "value": "422.48" }, - { "UTCDate": "2017-12-07", "unixTimeStamp": "1512604800", "value": "421.15" }, - { "UTCDate": "2017-12-08", "unixTimeStamp": "1512691200", "value": "451.74" }, - { "UTCDate": "2017-12-09", "unixTimeStamp": "1512777600", "value": "472.86" }, - { "UTCDate": "2017-12-10", "unixTimeStamp": "1512864000", "value": "436.49" }, - { "UTCDate": "2017-12-11", "unixTimeStamp": "1512950400", "value": "513.29" }, - { "UTCDate": "2017-12-12", "unixTimeStamp": "1513036800", "value": "656.52" }, - { "UTCDate": "2017-12-13", "unixTimeStamp": "1513123200", "value": "699.09" }, - { "UTCDate": "2017-12-14", "unixTimeStamp": "1513209600", "value": "693.58" }, - { "UTCDate": "2017-12-15", "unixTimeStamp": "1513296000", "value": "684.27" }, - { "UTCDate": "2017-12-16", "unixTimeStamp": "1513382400", "value": "692.83" }, - { "UTCDate": "2017-12-17", "unixTimeStamp": "1513468800", "value": "717.71" }, - { "UTCDate": "2017-12-18", "unixTimeStamp": "1513555200", "value": "785.99" }, - { "UTCDate": "2017-12-19", "unixTimeStamp": "1513641600", "value": "812.50" }, - { "UTCDate": "2017-12-20", "unixTimeStamp": "1513728000", "value": "799.17" }, - { "UTCDate": "2017-12-21", "unixTimeStamp": "1513814400", "value": "789.39" }, - { "UTCDate": "2017-12-22", "unixTimeStamp": "1513900800", "value": "657.83" }, - { "UTCDate": "2017-12-23", "unixTimeStamp": "1513987200", "value": "700.44" }, - { "UTCDate": "2017-12-24", "unixTimeStamp": "1514073600", "value": "675.91" }, - { "UTCDate": "2017-12-25", "unixTimeStamp": "1514160000", "value": "723.14" }, - { "UTCDate": "2017-12-26", "unixTimeStamp": "1514246400", "value": "753.40" }, - { "UTCDate": "2017-12-27", "unixTimeStamp": "1514332800", "value": "739.94" }, - { "UTCDate": "2017-12-28", "unixTimeStamp": "1514419200", "value": "716.69" }, - { "UTCDate": "2017-12-29", "unixTimeStamp": "1514505600", "value": "739.60" }, - { "UTCDate": "2017-12-30", "unixTimeStamp": "1514592000", "value": "692.99" }, - { "UTCDate": "2017-12-31", "unixTimeStamp": "1514678400", "value": "741.13" }, - { "UTCDate": "2018-01-01", "unixTimeStamp": "1514764800", "value": "756.20" }, - { "UTCDate": "2018-01-02", "unixTimeStamp": "1514851200", "value": "861.97" }, - { "UTCDate": "2018-01-03", "unixTimeStamp": "1514937600", "value": "941.10" }, - { "UTCDate": "2018-01-04", "unixTimeStamp": "1515024000", "value": "944.83" }, - { "UTCDate": "2018-01-05", "unixTimeStamp": "1515110400", "value": "967.13" }, - { "UTCDate": "2018-01-06", "unixTimeStamp": "1515196800", "value": "1006.41" }, - { "UTCDate": "2018-01-07", "unixTimeStamp": "1515283200", "value": "1117.75" }, - { "UTCDate": "2018-01-08", "unixTimeStamp": "1515369600", "value": "1136.11" }, - { "UTCDate": "2018-01-09", "unixTimeStamp": "1515456000", "value": "1289.24" }, - { "UTCDate": "2018-01-10", "unixTimeStamp": "1515542400", "value": "1248.99" }, - { "UTCDate": "2018-01-11", "unixTimeStamp": "1515628800", "value": "1139.32" }, - { "UTCDate": "2018-01-12", "unixTimeStamp": "1515715200", "value": "1261.03" }, - { "UTCDate": "2018-01-13", "unixTimeStamp": "1515801600", "value": "1385.02" }, - { "UTCDate": "2018-01-14", "unixTimeStamp": "1515888000", "value": "1359.48" }, - { "UTCDate": "2018-01-15", "unixTimeStamp": "1515974400", "value": "1278.69" }, - { "UTCDate": "2018-01-16", "unixTimeStamp": "1516060800", "value": "1050.26" }, - { "UTCDate": "2018-01-17", "unixTimeStamp": "1516147200", "value": "1024.69" }, - { "UTCDate": "2018-01-18", "unixTimeStamp": "1516233600", "value": "1012.97" }, - { "UTCDate": "2018-01-19", "unixTimeStamp": "1516320000", "value": "1037.36" }, - { "UTCDate": "2018-01-20", "unixTimeStamp": "1516406400", "value": "1150.50" }, - { "UTCDate": "2018-01-21", "unixTimeStamp": "1516492800", "value": "1049.09" }, - { "UTCDate": "2018-01-22", "unixTimeStamp": "1516579200", "value": "999.64" }, - { "UTCDate": "2018-01-23", "unixTimeStamp": "1516665600", "value": "984.47" }, - { "UTCDate": "2018-01-24", "unixTimeStamp": "1516752000", "value": "1061.78" }, - { "UTCDate": "2018-01-25", "unixTimeStamp": "1516838400", "value": "1046.37" }, - { "UTCDate": "2018-01-26", "unixTimeStamp": "1516924800", "value": "1048.58" }, - { "UTCDate": "2018-01-27", "unixTimeStamp": "1517011200", "value": "1109.08" }, - { "UTCDate": "2018-01-28", "unixTimeStamp": "1517097600", "value": "1231.58" }, - { "UTCDate": "2018-01-29", "unixTimeStamp": "1517184000", "value": "1169.96" }, - { "UTCDate": "2018-01-30", "unixTimeStamp": "1517270400", "value": "1063.75" }, - { "UTCDate": "2018-01-31", "unixTimeStamp": "1517356800", "value": "1111.31" }, - { "UTCDate": "2018-02-01", "unixTimeStamp": "1517443200", "value": "1026.19" }, - { "UTCDate": "2018-02-02", "unixTimeStamp": "1517529600", "value": "917.47" }, - { "UTCDate": "2018-02-03", "unixTimeStamp": "1517616000", "value": "970.87" }, - { "UTCDate": "2018-02-04", "unixTimeStamp": "1517702400", "value": "827.59" }, - { "UTCDate": "2018-02-05", "unixTimeStamp": "1517788800", "value": "695.08" }, - { "UTCDate": "2018-02-06", "unixTimeStamp": "1517875200", "value": "785.01" }, - { "UTCDate": "2018-02-07", "unixTimeStamp": "1517961600", "value": "751.81" }, - { "UTCDate": "2018-02-08", "unixTimeStamp": "1518048000", "value": "813.55" }, - { "UTCDate": "2018-02-09", "unixTimeStamp": "1518134400", "value": "877.88" }, - { "UTCDate": "2018-02-10", "unixTimeStamp": "1518220800", "value": "850.75" }, - { "UTCDate": "2018-02-11", "unixTimeStamp": "1518307200", "value": "811.24" }, - { "UTCDate": "2018-02-12", "unixTimeStamp": "1518393600", "value": "865.27" }, - { "UTCDate": "2018-02-13", "unixTimeStamp": "1518480000", "value": "840.98" }, - { "UTCDate": "2018-02-14", "unixTimeStamp": "1518566400", "value": "920.11" }, - { "UTCDate": "2018-02-15", "unixTimeStamp": "1518652800", "value": "927.95" }, - { "UTCDate": "2018-02-16", "unixTimeStamp": "1518739200", "value": "938.02" }, - { "UTCDate": "2018-02-17", "unixTimeStamp": "1518825600", "value": "974.77" }, - { "UTCDate": "2018-02-18", "unixTimeStamp": "1518912000", "value": "913.90" }, - { "UTCDate": "2018-02-19", "unixTimeStamp": "1518998400", "value": "939.79" }, - { "UTCDate": "2018-02-20", "unixTimeStamp": "1519084800", "value": "885.52" }, - { "UTCDate": "2018-02-21", "unixTimeStamp": "1519171200", "value": "840.10" }, - { "UTCDate": "2018-02-22", "unixTimeStamp": "1519257600", "value": "804.63" }, - { "UTCDate": "2018-02-23", "unixTimeStamp": "1519344000", "value": "854.70" }, - { "UTCDate": "2018-02-24", "unixTimeStamp": "1519430400", "value": "833.49" }, - { "UTCDate": "2018-02-25", "unixTimeStamp": "1519516800", "value": "840.28" }, - { "UTCDate": "2018-02-26", "unixTimeStamp": "1519603200", "value": "867.62" }, - { "UTCDate": "2018-02-27", "unixTimeStamp": "1519689600", "value": "871.58" }, - { "UTCDate": "2018-02-28", "unixTimeStamp": "1519776000", "value": "851.50" }, - { "UTCDate": "2018-03-01", "unixTimeStamp": "1519862400", "value": "869.87" }, - { "UTCDate": "2018-03-02", "unixTimeStamp": "1519948800", "value": "855.60" }, - { "UTCDate": "2018-03-03", "unixTimeStamp": "1520035200", "value": "855.65" }, - { "UTCDate": "2018-03-04", "unixTimeStamp": "1520121600", "value": "864.83" }, - { "UTCDate": "2018-03-05", "unixTimeStamp": "1520208000", "value": "849.42" }, - { "UTCDate": "2018-03-06", "unixTimeStamp": "1520294400", "value": "815.69" }, - { "UTCDate": "2018-03-07", "unixTimeStamp": "1520380800", "value": "751.13" }, - { "UTCDate": "2018-03-08", "unixTimeStamp": "1520467200", "value": "698.83" }, - { "UTCDate": "2018-03-09", "unixTimeStamp": "1520553600", "value": "726.92" }, - { "UTCDate": "2018-03-10", "unixTimeStamp": "1520640000", "value": "682.30" }, - { "UTCDate": "2018-03-11", "unixTimeStamp": "1520726400", "value": "720.36" }, - { "UTCDate": "2018-03-12", "unixTimeStamp": "1520812800", "value": "697.02" }, - { "UTCDate": "2018-03-13", "unixTimeStamp": "1520899200", "value": "689.96" }, - { "UTCDate": "2018-03-14", "unixTimeStamp": "1520985600", "value": "613.15" }, - { "UTCDate": "2018-03-15", "unixTimeStamp": "1521072000", "value": "610.56" }, - { "UTCDate": "2018-03-16", "unixTimeStamp": "1521158400", "value": "600.53" }, - { "UTCDate": "2018-03-17", "unixTimeStamp": "1521244800", "value": "549.79" }, - { "UTCDate": "2018-03-18", "unixTimeStamp": "1521331200", "value": "537.38" }, - { "UTCDate": "2018-03-19", "unixTimeStamp": "1521417600", "value": "555.55" }, - { "UTCDate": "2018-03-20", "unixTimeStamp": "1521504000", "value": "557.57" }, - { "UTCDate": "2018-03-21", "unixTimeStamp": "1521590400", "value": "559.91" }, - { "UTCDate": "2018-03-22", "unixTimeStamp": "1521676800", "value": "539.89" }, - { "UTCDate": "2018-03-23", "unixTimeStamp": "1521763200", "value": "543.83" }, - { "UTCDate": "2018-03-24", "unixTimeStamp": "1521849600", "value": "520.16" }, - { "UTCDate": "2018-03-25", "unixTimeStamp": "1521936000", "value": "523.01" }, - { "UTCDate": "2018-03-26", "unixTimeStamp": "1522022400", "value": "486.25" }, - { "UTCDate": "2018-03-27", "unixTimeStamp": "1522108800", "value": "448.78" }, - { "UTCDate": "2018-03-28", "unixTimeStamp": "1522195200", "value": "445.93" }, - { "UTCDate": "2018-03-29", "unixTimeStamp": "1522281600", "value": "383.90" }, - { "UTCDate": "2018-03-30", "unixTimeStamp": "1522368000", "value": "393.82" }, - { "UTCDate": "2018-03-31", "unixTimeStamp": "1522454400", "value": "394.07" }, - { "UTCDate": "2018-04-01", "unixTimeStamp": "1522540800", "value": "378.85" }, - { "UTCDate": "2018-04-02", "unixTimeStamp": "1522627200", "value": "384.68" }, - { "UTCDate": "2018-04-03", "unixTimeStamp": "1522713600", "value": "415.93" }, - { "UTCDate": "2018-04-04", "unixTimeStamp": "1522800000", "value": "378.65" }, - { "UTCDate": "2018-04-05", "unixTimeStamp": "1522886400", "value": "381.36" }, - { "UTCDate": "2018-04-06", "unixTimeStamp": "1522972800", "value": "370.35" }, - { "UTCDate": "2018-04-07", "unixTimeStamp": "1523059200", "value": "384.98" }, - { "UTCDate": "2018-04-08", "unixTimeStamp": "1523145600", "value": "400.72" }, - { "UTCDate": "2018-04-09", "unixTimeStamp": "1523232000", "value": "399.02" }, - { "UTCDate": "2018-04-10", "unixTimeStamp": "1523318400", "value": "415.65" }, - { "UTCDate": "2018-04-11", "unixTimeStamp": "1523404800", "value": "430.42" }, - { "UTCDate": "2018-04-12", "unixTimeStamp": "1523491200", "value": "493.95" }, - { "UTCDate": "2018-04-13", "unixTimeStamp": "1523577600", "value": "494.96" }, - { "UTCDate": "2018-04-14", "unixTimeStamp": "1523664000", "value": "502.79" }, - { "UTCDate": "2018-04-15", "unixTimeStamp": "1523750400", "value": "534.15" }, - { "UTCDate": "2018-04-16", "unixTimeStamp": "1523836800", "value": "511.67" }, - { "UTCDate": "2018-04-17", "unixTimeStamp": "1523923200", "value": "503.03" }, - { "UTCDate": "2018-04-18", "unixTimeStamp": "1524009600", "value": "525.78" }, - { "UTCDate": "2018-04-19", "unixTimeStamp": "1524096000", "value": "567.25" }, - { "UTCDate": "2018-04-20", "unixTimeStamp": "1524182400", "value": "617.16" }, - { "UTCDate": "2018-04-21", "unixTimeStamp": "1524268800", "value": "605.17" }, - { "UTCDate": "2018-04-22", "unixTimeStamp": "1524355200", "value": "621.33" }, - { "UTCDate": "2018-04-23", "unixTimeStamp": "1524441600", "value": "644.13" }, - { "UTCDate": "2018-04-24", "unixTimeStamp": "1524528000", "value": "703.35" }, - { "UTCDate": "2018-04-25", "unixTimeStamp": "1524614400", "value": "617.73" }, - { "UTCDate": "2018-04-26", "unixTimeStamp": "1524700800", "value": "661.45" }, - { "UTCDate": "2018-04-27", "unixTimeStamp": "1524787200", "value": "643.33" }, - { "UTCDate": "2018-04-28", "unixTimeStamp": "1524873600", "value": "683.02" }, - { "UTCDate": "2018-04-29", "unixTimeStamp": "1524960000", "value": "689.31" }, - { "UTCDate": "2018-04-30", "unixTimeStamp": "1525046400", "value": "670.04" }, - { "UTCDate": "2018-05-01", "unixTimeStamp": "1525132800", "value": "670.81" }, - { "UTCDate": "2018-05-02", "unixTimeStamp": "1525219200", "value": "686.74" }, - { "UTCDate": "2018-05-03", "unixTimeStamp": "1525305600", "value": "777.62" }, - { "UTCDate": "2018-05-04", "unixTimeStamp": "1525392000", "value": "784.21" }, - { "UTCDate": "2018-05-05", "unixTimeStamp": "1525478400", "value": "816.58" }, - { "UTCDate": "2018-05-06", "unixTimeStamp": "1525564800", "value": "790.39" }, - { "UTCDate": "2018-05-07", "unixTimeStamp": "1525651200", "value": "752.40" }, - { "UTCDate": "2018-05-08", "unixTimeStamp": "1525737600", "value": "747.79" }, - { "UTCDate": "2018-05-09", "unixTimeStamp": "1525824000", "value": "751.27" }, - { "UTCDate": "2018-05-10", "unixTimeStamp": "1525910400", "value": "723.61" }, - { "UTCDate": "2018-05-11", "unixTimeStamp": "1525996800", "value": "677.80" }, - { "UTCDate": "2018-05-12", "unixTimeStamp": "1526083200", "value": "683.64" }, - { "UTCDate": "2018-05-13", "unixTimeStamp": "1526169600", "value": "729.34" }, - { "UTCDate": "2018-05-14", "unixTimeStamp": "1526256000", "value": "727.41" }, - { "UTCDate": "2018-05-15", "unixTimeStamp": "1526342400", "value": "705.64" }, - { "UTCDate": "2018-05-16", "unixTimeStamp": "1526428800", "value": "706.72" }, - { "UTCDate": "2018-05-17", "unixTimeStamp": "1526515200", "value": "668.38" }, - { "UTCDate": "2018-05-18", "unixTimeStamp": "1526601600", "value": "693.57" }, - { "UTCDate": "2018-05-19", "unixTimeStamp": "1526688000", "value": "696.05" }, - { "UTCDate": "2018-05-20", "unixTimeStamp": "1526774400", "value": "715.15" }, - { "UTCDate": "2018-05-21", "unixTimeStamp": "1526860800", "value": "696.73" }, - { "UTCDate": "2018-05-22", "unixTimeStamp": "1526947200", "value": "640.84" }, - { "UTCDate": "2018-05-23", "unixTimeStamp": "1527033600", "value": "577.01" }, - { "UTCDate": "2018-05-24", "unixTimeStamp": "1527120000", "value": "602.59" }, - { "UTCDate": "2018-05-25", "unixTimeStamp": "1527206400", "value": "584.77" }, - { "UTCDate": "2018-05-26", "unixTimeStamp": "1527292800", "value": "585.76" }, - { "UTCDate": "2018-05-27", "unixTimeStamp": "1527379200", "value": "569.64" }, - { "UTCDate": "2018-05-28", "unixTimeStamp": "1527465600", "value": "512.03" }, - { "UTCDate": "2018-05-29", "unixTimeStamp": "1527552000", "value": "566.59" }, - { "UTCDate": "2018-05-30", "unixTimeStamp": "1527638400", "value": "557.12" }, - { "UTCDate": "2018-05-31", "unixTimeStamp": "1527724800", "value": "577.23" }, - { "UTCDate": "2018-06-01", "unixTimeStamp": "1527811200", "value": "579.01" }, - { "UTCDate": "2018-06-02", "unixTimeStamp": "1527897600", "value": "590.53" }, - { "UTCDate": "2018-06-03", "unixTimeStamp": "1527984000", "value": "619.04" }, - { "UTCDate": "2018-06-04", "unixTimeStamp": "1528070400", "value": "591.31" }, - { "UTCDate": "2018-06-05", "unixTimeStamp": "1528156800", "value": "608.23" }, - { "UTCDate": "2018-06-06", "unixTimeStamp": "1528243200", "value": "606.30" }, - { "UTCDate": "2018-06-07", "unixTimeStamp": "1528329600", "value": "604.44" }, - { "UTCDate": "2018-06-08", "unixTimeStamp": "1528416000", "value": "599.55" }, - { "UTCDate": "2018-06-09", "unixTimeStamp": "1528502400", "value": "593.38" }, - { "UTCDate": "2018-06-10", "unixTimeStamp": "1528588800", "value": "524.74" }, - { "UTCDate": "2018-06-11", "unixTimeStamp": "1528675200", "value": "531.15" }, - { "UTCDate": "2018-06-12", "unixTimeStamp": "1528761600", "value": "494.53" }, - { "UTCDate": "2018-06-13", "unixTimeStamp": "1528848000", "value": "476.30" }, - { "UTCDate": "2018-06-14", "unixTimeStamp": "1528934400", "value": "519.83" }, - { "UTCDate": "2018-06-15", "unixTimeStamp": "1529020800", "value": "487.51" }, - { "UTCDate": "2018-06-16", "unixTimeStamp": "1529107200", "value": "497.22" }, - { "UTCDate": "2018-06-17", "unixTimeStamp": "1529193600", "value": "496.74" }, - { "UTCDate": "2018-06-18", "unixTimeStamp": "1529280000", "value": "517.63" }, - { "UTCDate": "2018-06-19", "unixTimeStamp": "1529366400", "value": "538.45" }, - { "UTCDate": "2018-06-20", "unixTimeStamp": "1529452800", "value": "536.16" }, - { "UTCDate": "2018-06-21", "unixTimeStamp": "1529539200", "value": "525.77" }, - { "UTCDate": "2018-06-22", "unixTimeStamp": "1529625600", "value": "462.16" }, - { "UTCDate": "2018-06-23", "unixTimeStamp": "1529712000", "value": "474.18" }, - { "UTCDate": "2018-06-24", "unixTimeStamp": "1529798400", "value": "455.25" }, - { "UTCDate": "2018-06-25", "unixTimeStamp": "1529884800", "value": "458.82" }, - { "UTCDate": "2018-06-26", "unixTimeStamp": "1529971200", "value": "429.58" }, - { "UTCDate": "2018-06-27", "unixTimeStamp": "1530057600", "value": "441.75" }, - { "UTCDate": "2018-06-28", "unixTimeStamp": "1530144000", "value": "420.72" }, - { "UTCDate": "2018-06-29", "unixTimeStamp": "1530230400", "value": "435.25" }, - { "UTCDate": "2018-06-30", "unixTimeStamp": "1530316800", "value": "453.42" }, - { "UTCDate": "2018-07-01", "unixTimeStamp": "1530403200", "value": "451.95" }, - { "UTCDate": "2018-07-02", "unixTimeStamp": "1530489600", "value": "476.58" }, - { "UTCDate": "2018-07-03", "unixTimeStamp": "1530576000", "value": "461.95" }, - { "UTCDate": "2018-07-04", "unixTimeStamp": "1530662400", "value": "467.19" }, - { "UTCDate": "2018-07-05", "unixTimeStamp": "1530748800", "value": "467.55" }, - { "UTCDate": "2018-07-06", "unixTimeStamp": "1530835200", "value": "469.93" }, - { "UTCDate": "2018-07-07", "unixTimeStamp": "1530921600", "value": "485.81" }, - { "UTCDate": "2018-07-08", "unixTimeStamp": "1531008000", "value": "486.19" }, - { "UTCDate": "2018-07-09", "unixTimeStamp": "1531094400", "value": "471.48" }, - { "UTCDate": "2018-07-10", "unixTimeStamp": "1531180800", "value": "432.69" }, - { "UTCDate": "2018-07-11", "unixTimeStamp": "1531267200", "value": "445.59" }, - { "UTCDate": "2018-07-12", "unixTimeStamp": "1531353600", "value": "430.91" }, - { "UTCDate": "2018-07-13", "unixTimeStamp": "1531440000", "value": "432.46" }, - { "UTCDate": "2018-07-14", "unixTimeStamp": "1531526400", "value": "433.74" }, - { "UTCDate": "2018-07-15", "unixTimeStamp": "1531612800", "value": "449.62" }, - { "UTCDate": "2018-07-16", "unixTimeStamp": "1531699200", "value": "478.75" }, - { "UTCDate": "2018-07-17", "unixTimeStamp": "1531785600", "value": "499.06" }, - { "UTCDate": "2018-07-18", "unixTimeStamp": "1531872000", "value": "479.02" }, - { "UTCDate": "2018-07-19", "unixTimeStamp": "1531958400", "value": "468.65" }, - { "UTCDate": "2018-07-20", "unixTimeStamp": "1532044800", "value": "448.84" }, - { "UTCDate": "2018-07-21", "unixTimeStamp": "1532131200", "value": "461.04" }, - { "UTCDate": "2018-07-22", "unixTimeStamp": "1532217600", "value": "457.65" }, - { "UTCDate": "2018-07-23", "unixTimeStamp": "1532304000", "value": "449.63" }, - { "UTCDate": "2018-07-24", "unixTimeStamp": "1532390400", "value": "479.47" }, - { "UTCDate": "2018-07-25", "unixTimeStamp": "1532476800", "value": "471.28" }, - { "UTCDate": "2018-07-26", "unixTimeStamp": "1532563200", "value": "462.03" }, - { "UTCDate": "2018-07-27", "unixTimeStamp": "1532649600", "value": "469.69" }, - { "UTCDate": "2018-07-28", "unixTimeStamp": "1532736000", "value": "468.55" }, - { "UTCDate": "2018-07-29", "unixTimeStamp": "1532822400", "value": "466.20" }, - { "UTCDate": "2018-07-30", "unixTimeStamp": "1532908800", "value": "456.56" }, - { "UTCDate": "2018-07-31", "unixTimeStamp": "1532995200", "value": "431.99" }, - { "UTCDate": "2018-08-01", "unixTimeStamp": "1533081600", "value": "419.87" }, - { "UTCDate": "2018-08-02", "unixTimeStamp": "1533168000", "value": "410.83" }, - { "UTCDate": "2018-08-03", "unixTimeStamp": "1533254400", "value": "417.62" }, - { "UTCDate": "2018-08-04", "unixTimeStamp": "1533340800", "value": "406.91" }, - { "UTCDate": "2018-08-05", "unixTimeStamp": "1533427200", "value": "408.81" }, - { "UTCDate": "2018-08-06", "unixTimeStamp": "1533513600", "value": "404.95" }, - { "UTCDate": "2018-08-07", "unixTimeStamp": "1533600000", "value": "377.94" }, - { "UTCDate": "2018-08-08", "unixTimeStamp": "1533686400", "value": "355.57" }, - { "UTCDate": "2018-08-09", "unixTimeStamp": "1533772800", "value": "363.51" }, - { "UTCDate": "2018-08-10", "unixTimeStamp": "1533859200", "value": "331.57" }, - { "UTCDate": "2018-08-11", "unixTimeStamp": "1533945600", "value": "318.01" }, - { "UTCDate": "2018-08-12", "unixTimeStamp": "1534032000", "value": "318.20" }, - { "UTCDate": "2018-08-13", "unixTimeStamp": "1534118400", "value": "284.03" }, - { "UTCDate": "2018-08-14", "unixTimeStamp": "1534204800", "value": "278.31" }, - { "UTCDate": "2018-08-15", "unixTimeStamp": "1534291200", "value": "281.24" }, - { "UTCDate": "2018-08-16", "unixTimeStamp": "1534377600", "value": "286.80" }, - { "UTCDate": "2018-08-17", "unixTimeStamp": "1534464000", "value": "317.57" }, - { "UTCDate": "2018-08-18", "unixTimeStamp": "1534550400", "value": "294.85" }, - { "UTCDate": "2018-08-19", "unixTimeStamp": "1534636800", "value": "299.62" }, - { "UTCDate": "2018-08-20", "unixTimeStamp": "1534723200", "value": "270.81" }, - { "UTCDate": "2018-08-21", "unixTimeStamp": "1534809600", "value": "281.13" }, - { "UTCDate": "2018-08-22", "unixTimeStamp": "1534896000", "value": "270.37" }, - { "UTCDate": "2018-08-23", "unixTimeStamp": "1534982400", "value": "275.83" }, - { "UTCDate": "2018-08-24", "unixTimeStamp": "1535068800", "value": "281.37" }, - { "UTCDate": "2018-08-25", "unixTimeStamp": "1535155200", "value": "277.56" }, - { "UTCDate": "2018-08-26", "unixTimeStamp": "1535241600", "value": "274.30" }, - { "UTCDate": "2018-08-27", "unixTimeStamp": "1535328000", "value": "288.02" }, - { "UTCDate": "2018-08-28", "unixTimeStamp": "1535414400", "value": "295.55" }, - { "UTCDate": "2018-08-29", "unixTimeStamp": "1535500800", "value": "288.67" }, - { "UTCDate": "2018-08-30", "unixTimeStamp": "1535587200", "value": "284.15" }, - { "UTCDate": "2018-08-31", "unixTimeStamp": "1535673600", "value": "281.66" }, - { "UTCDate": "2018-09-01", "unixTimeStamp": "1535760000", "value": "295.36" }, - { "UTCDate": "2018-09-02", "unixTimeStamp": "1535846400", "value": "295.02" }, - { "UTCDate": "2018-09-03", "unixTimeStamp": "1535932800", "value": "288.97" }, - { "UTCDate": "2018-09-04", "unixTimeStamp": "1536019200", "value": "285.23" }, - { "UTCDate": "2018-09-05", "unixTimeStamp": "1536105600", "value": "228.27" }, - { "UTCDate": "2018-09-06", "unixTimeStamp": "1536192000", "value": "229.52" }, - { "UTCDate": "2018-09-07", "unixTimeStamp": "1536278400", "value": "215.14" }, - { "UTCDate": "2018-09-08", "unixTimeStamp": "1536364800", "value": "196.77" }, - { "UTCDate": "2018-09-09", "unixTimeStamp": "1536451200", "value": "195.99" }, - { "UTCDate": "2018-09-10", "unixTimeStamp": "1536537600", "value": "197.14" }, - { "UTCDate": "2018-09-11", "unixTimeStamp": "1536624000", "value": "185.15" }, - { "UTCDate": "2018-09-12", "unixTimeStamp": "1536710400", "value": "183.03" }, - { "UTCDate": "2018-09-13", "unixTimeStamp": "1536796800", "value": "211.27" }, - { "UTCDate": "2018-09-14", "unixTimeStamp": "1536883200", "value": "208.87" }, - { "UTCDate": "2018-09-15", "unixTimeStamp": "1536969600", "value": "221.63" }, - { "UTCDate": "2018-09-16", "unixTimeStamp": "1537056000", "value": "220.12" }, - { "UTCDate": "2018-09-17", "unixTimeStamp": "1537142400", "value": "196.04" }, - { "UTCDate": "2018-09-18", "unixTimeStamp": "1537228800", "value": "208.39" }, - { "UTCDate": "2018-09-19", "unixTimeStamp": "1537315200", "value": "209.78" }, - { "UTCDate": "2018-09-20", "unixTimeStamp": "1537401600", "value": "224.76" }, - { "UTCDate": "2018-09-21", "unixTimeStamp": "1537488000", "value": "247.69" }, - { "UTCDate": "2018-09-22", "unixTimeStamp": "1537574400", "value": "240.78" }, - { "UTCDate": "2018-09-23", "unixTimeStamp": "1537660800", "value": "244.55" }, - { "UTCDate": "2018-09-24", "unixTimeStamp": "1537747200", "value": "227.92" }, - { "UTCDate": "2018-09-25", "unixTimeStamp": "1537833600", "value": "219.20" }, - { "UTCDate": "2018-09-26", "unixTimeStamp": "1537920000", "value": "214.21" }, - { "UTCDate": "2018-09-27", "unixTimeStamp": "1538006400", "value": "229.09" }, - { "UTCDate": "2018-09-28", "unixTimeStamp": "1538092800", "value": "221.56" }, - { "UTCDate": "2018-09-29", "unixTimeStamp": "1538179200", "value": "231.32" }, - { "UTCDate": "2018-09-30", "unixTimeStamp": "1538265600", "value": "232.60" }, - { "UTCDate": "2018-10-01", "unixTimeStamp": "1538352000", "value": "230.89" }, - { "UTCDate": "2018-10-02", "unixTimeStamp": "1538438400", "value": "225.41" }, - { "UTCDate": "2018-10-03", "unixTimeStamp": "1538524800", "value": "219.97" }, - { "UTCDate": "2018-10-04", "unixTimeStamp": "1538611200", "value": "221.76" }, - { "UTCDate": "2018-10-05", "unixTimeStamp": "1538697600", "value": "227.90" }, - { "UTCDate": "2018-10-06", "unixTimeStamp": "1538784000", "value": "224.62" }, - { "UTCDate": "2018-10-07", "unixTimeStamp": "1538870400", "value": "225.65" }, - { "UTCDate": "2018-10-08", "unixTimeStamp": "1538956800", "value": "229.33" }, - { "UTCDate": "2018-10-09", "unixTimeStamp": "1539043200", "value": "227.49" }, - { "UTCDate": "2018-10-10", "unixTimeStamp": "1539129600", "value": "225.26" }, - { "UTCDate": "2018-10-11", "unixTimeStamp": "1539216000", "value": "189.83" }, - { "UTCDate": "2018-10-12", "unixTimeStamp": "1539302400", "value": "195.97" }, - { "UTCDate": "2018-10-13", "unixTimeStamp": "1539388800", "value": "199.45" }, - { "UTCDate": "2018-10-14", "unixTimeStamp": "1539475200", "value": "194.99" }, - { "UTCDate": "2018-10-15", "unixTimeStamp": "1539561600", "value": "210.80" }, - { "UTCDate": "2018-10-16", "unixTimeStamp": "1539648000", "value": "210.22" }, - { "UTCDate": "2018-10-17", "unixTimeStamp": "1539734400", "value": "207.60" }, - { "UTCDate": "2018-10-18", "unixTimeStamp": "1539820800", "value": "202.49" }, - { "UTCDate": "2018-10-19", "unixTimeStamp": "1539907200", "value": "202.86" }, - { "UTCDate": "2018-10-20", "unixTimeStamp": "1539993600", "value": "205.08" }, - { "UTCDate": "2018-10-21", "unixTimeStamp": "1540080000", "value": "204.77" }, - { "UTCDate": "2018-10-22", "unixTimeStamp": "1540166400", "value": "203.60" }, - { "UTCDate": "2018-10-23", "unixTimeStamp": "1540252800", "value": "203.70" }, - { "UTCDate": "2018-10-24", "unixTimeStamp": "1540339200", "value": "202.92" }, - { "UTCDate": "2018-10-25", "unixTimeStamp": "1540425600", "value": "201.23" }, - { "UTCDate": "2018-10-26", "unixTimeStamp": "1540512000", "value": "203.37" }, - { "UTCDate": "2018-10-27", "unixTimeStamp": "1540598400", "value": "202.79" }, - { "UTCDate": "2018-10-28", "unixTimeStamp": "1540684800", "value": "203.72" }, - { "UTCDate": "2018-10-29", "unixTimeStamp": "1540771200", "value": "195.67" }, - { "UTCDate": "2018-10-30", "unixTimeStamp": "1540857600", "value": "196.19" }, - { "UTCDate": "2018-10-31", "unixTimeStamp": "1540944000", "value": "197.85" }, - { "UTCDate": "2018-11-01", "unixTimeStamp": "1541030400", "value": "198.73" }, - { "UTCDate": "2018-11-02", "unixTimeStamp": "1541116800", "value": "201.02" }, - { "UTCDate": "2018-11-03", "unixTimeStamp": "1541203200", "value": "199.47" }, - { "UTCDate": "2018-11-04", "unixTimeStamp": "1541289600", "value": "211.30" }, - { "UTCDate": "2018-11-05", "unixTimeStamp": "1541376000", "value": "209.70" }, - { "UTCDate": "2018-11-06", "unixTimeStamp": "1541462400", "value": "219.56" }, - { "UTCDate": "2018-11-07", "unixTimeStamp": "1541548800", "value": "217.99" }, - { "UTCDate": "2018-11-08", "unixTimeStamp": "1541635200", "value": "211.29" }, - { "UTCDate": "2018-11-09", "unixTimeStamp": "1541721600", "value": "209.39" }, - { "UTCDate": "2018-11-10", "unixTimeStamp": "1541808000", "value": "211.90" }, - { "UTCDate": "2018-11-11", "unixTimeStamp": "1541894400", "value": "211.70" }, - { "UTCDate": "2018-11-12", "unixTimeStamp": "1541980800", "value": "210.81" }, - { "UTCDate": "2018-11-13", "unixTimeStamp": "1542067200", "value": "206.42" }, - { "UTCDate": "2018-11-14", "unixTimeStamp": "1542153600", "value": "182.72" }, - { "UTCDate": "2018-11-15", "unixTimeStamp": "1542240000", "value": "181.53" }, - { "UTCDate": "2018-11-16", "unixTimeStamp": "1542326400", "value": "174.84" }, - { "UTCDate": "2018-11-17", "unixTimeStamp": "1542412800", "value": "174.22" }, - { "UTCDate": "2018-11-18", "unixTimeStamp": "1542499200", "value": "177.53" }, - { "UTCDate": "2018-11-19", "unixTimeStamp": "1542585600", "value": "148.22" }, - { "UTCDate": "2018-11-20", "unixTimeStamp": "1542672000", "value": "130.74" }, - { "UTCDate": "2018-11-21", "unixTimeStamp": "1542758400", "value": "136.50" }, - { "UTCDate": "2018-11-22", "unixTimeStamp": "1542844800", "value": "124.83" }, - { "UTCDate": "2018-11-23", "unixTimeStamp": "1542931200", "value": "123.37" }, - { "UTCDate": "2018-11-24", "unixTimeStamp": "1543017600", "value": "112.75" }, - { "UTCDate": "2018-11-25", "unixTimeStamp": "1543104000", "value": "116.75" }, - { "UTCDate": "2018-11-26", "unixTimeStamp": "1543190400", "value": "108.87" }, - { "UTCDate": "2018-11-27", "unixTimeStamp": "1543276800", "value": "110.19" }, - { "UTCDate": "2018-11-28", "unixTimeStamp": "1543363200", "value": "122.88" }, - { "UTCDate": "2018-11-29", "unixTimeStamp": "1543449600", "value": "117.48" }, - { "UTCDate": "2018-11-30", "unixTimeStamp": "1543536000", "value": "112.87" }, - { "UTCDate": "2018-12-01", "unixTimeStamp": "1543622400", "value": "118.50" }, - { "UTCDate": "2018-12-02", "unixTimeStamp": "1543708800", "value": "115.96" }, - { "UTCDate": "2018-12-03", "unixTimeStamp": "1543795200", "value": "108.23" }, - { "UTCDate": "2018-12-04", "unixTimeStamp": "1543881600", "value": "109.82" }, - { "UTCDate": "2018-12-05", "unixTimeStamp": "1543968000", "value": "101.57" }, - { "UTCDate": "2018-12-06", "unixTimeStamp": "1544054400", "value": "90.43" }, - { "UTCDate": "2018-12-07", "unixTimeStamp": "1544140800", "value": "93.61" }, - { "UTCDate": "2018-12-08", "unixTimeStamp": "1544227200", "value": "91.44" }, - { "UTCDate": "2018-12-09", "unixTimeStamp": "1544313600", "value": "94.42" }, - { "UTCDate": "2018-12-10", "unixTimeStamp": "1544400000", "value": "90.70" }, - { "UTCDate": "2018-12-11", "unixTimeStamp": "1544486400", "value": "88.05" }, - { "UTCDate": "2018-12-12", "unixTimeStamp": "1544572800", "value": "90.52" }, - { "UTCDate": "2018-12-13", "unixTimeStamp": "1544659200", "value": "86.39" }, - { "UTCDate": "2018-12-14", "unixTimeStamp": "1544745600", "value": "83.90" }, - { "UTCDate": "2018-12-15", "unixTimeStamp": "1544832000", "value": "84.27" }, - { "UTCDate": "2018-12-16", "unixTimeStamp": "1544918400", "value": "85.39" }, - { "UTCDate": "2018-12-17", "unixTimeStamp": "1545004800", "value": "95.44" }, - { "UTCDate": "2018-12-18", "unixTimeStamp": "1545091200", "value": "102.44" }, - { "UTCDate": "2018-12-19", "unixTimeStamp": "1545177600", "value": "100.63" }, - { "UTCDate": "2018-12-20", "unixTimeStamp": "1545264000", "value": "116.43" }, - { "UTCDate": "2018-12-21", "unixTimeStamp": "1545350400", "value": "109.44" }, - { "UTCDate": "2018-12-22", "unixTimeStamp": "1545436800", "value": "118.36" }, - { "UTCDate": "2018-12-23", "unixTimeStamp": "1545523200", "value": "131.56" }, - { "UTCDate": "2018-12-24", "unixTimeStamp": "1545609600", "value": "140.87" }, - { "UTCDate": "2018-12-25", "unixTimeStamp": "1545696000", "value": "130.99" }, - { "UTCDate": "2018-12-26", "unixTimeStamp": "1545782400", "value": "132.61" }, - { "UTCDate": "2018-12-27", "unixTimeStamp": "1545868800", "value": "116.72" }, - { "UTCDate": "2018-12-28", "unixTimeStamp": "1545955200", "value": "139.73" }, - { "UTCDate": "2018-12-29", "unixTimeStamp": "1546041600", "value": "137.30" }, - { "UTCDate": "2018-12-30", "unixTimeStamp": "1546128000", "value": "141.33" }, - { "UTCDate": "2018-12-31", "unixTimeStamp": "1546214400", "value": "133.49" }, - { "UTCDate": "2019-01-01", "unixTimeStamp": "1546300800", "value": "142.66" }, - { "UTCDate": "2019-01-02", "unixTimeStamp": "1546387200", "value": "156.57" }, - { "UTCDate": "2019-01-03", "unixTimeStamp": "1546473600", "value": "149.44" }, - { "UTCDate": "2019-01-04", "unixTimeStamp": "1546560000", "value": "156.04" }, - { "UTCDate": "2019-01-05", "unixTimeStamp": "1546646400", "value": "156.23" }, - { "UTCDate": "2019-01-06", "unixTimeStamp": "1546732800", "value": "158.61" }, - { "UTCDate": "2019-01-07", "unixTimeStamp": "1546819200", "value": "152.09" }, - { "UTCDate": "2019-01-08", "unixTimeStamp": "1546905600", "value": "151.10" }, - { "UTCDate": "2019-01-09", "unixTimeStamp": "1546992000", "value": "151.17" }, - { "UTCDate": "2019-01-10", "unixTimeStamp": "1547078400", "value": "127.96" }, - { "UTCDate": "2019-01-11", "unixTimeStamp": "1547164800", "value": "127.16" }, - { "UTCDate": "2019-01-12", "unixTimeStamp": "1547251200", "value": "125.83" }, - { "UTCDate": "2019-01-13", "unixTimeStamp": "1547337600", "value": "116.56" }, - { "UTCDate": "2019-01-14", "unixTimeStamp": "1547424000", "value": "129.74" }, - { "UTCDate": "2019-01-15", "unixTimeStamp": "1547510400", "value": "121.22" }, - { "UTCDate": "2019-01-16", "unixTimeStamp": "1547596800", "value": "123.12" }, - { "UTCDate": "2019-01-17", "unixTimeStamp": "1547683200", "value": "123.72" }, - { "UTCDate": "2019-01-18", "unixTimeStamp": "1547769600", "value": "120.57" }, - { "UTCDate": "2019-01-19", "unixTimeStamp": "1547856000", "value": "124.85" }, - { "UTCDate": "2019-01-20", "unixTimeStamp": "1547942400", "value": "118.41" }, - { "UTCDate": "2019-01-21", "unixTimeStamp": "1548028800", "value": "116.72" }, - { "UTCDate": "2019-01-22", "unixTimeStamp": "1548115200", "value": "119.12" }, - { "UTCDate": "2019-01-23", "unixTimeStamp": "1548201600", "value": "117.57" }, - { "UTCDate": "2019-01-24", "unixTimeStamp": "1548288000", "value": "117.70" }, - { "UTCDate": "2019-01-25", "unixTimeStamp": "1548374400", "value": "115.92" }, - { "UTCDate": "2019-01-26", "unixTimeStamp": "1548460800", "value": "116.33" }, - { "UTCDate": "2019-01-27", "unixTimeStamp": "1548547200", "value": "112.27" }, - { "UTCDate": "2019-01-28", "unixTimeStamp": "1548633600", "value": "106.36" }, - { "UTCDate": "2019-01-29", "unixTimeStamp": "1548720000", "value": "104.75" }, - { "UTCDate": "2019-01-30", "unixTimeStamp": "1548806400", "value": "109.04" }, - { "UTCDate": "2019-01-31", "unixTimeStamp": "1548892800", "value": "106.89" }, - { "UTCDate": "2019-02-01", "unixTimeStamp": "1548979200", "value": "107.03" }, - { "UTCDate": "2019-02-02", "unixTimeStamp": "1549065600", "value": "111.00" }, - { "UTCDate": "2019-02-03", "unixTimeStamp": "1549152000", "value": "107.21" }, - { "UTCDate": "2019-02-04", "unixTimeStamp": "1549238400", "value": "106.90" }, - { "UTCDate": "2019-02-05", "unixTimeStamp": "1549324800", "value": "106.93" }, - { "UTCDate": "2019-02-06", "unixTimeStamp": "1549411200", "value": "104.50" }, - { "UTCDate": "2019-02-07", "unixTimeStamp": "1549497600", "value": "104.30" }, - { "UTCDate": "2019-02-08", "unixTimeStamp": "1549584000", "value": "119.49" }, - { "UTCDate": "2019-02-09", "unixTimeStamp": "1549670400", "value": "119.46" }, - { "UTCDate": "2019-02-10", "unixTimeStamp": "1549756800", "value": "125.58" }, - { "UTCDate": "2019-02-11", "unixTimeStamp": "1549843200", "value": "120.76" } - ] -} diff --git a/src/transformers/helpers/reqCache.ts b/src/transformers/helpers/reqCache.ts deleted file mode 100644 index 68a6c5a..0000000 --- a/src/transformers/helpers/reqCache.ts +++ /dev/null @@ -1,57 +0,0 @@ -import Web3 from 'web3'; -import _fetch from 'isomorphic-fetch'; - -import { AsyncUtils, StdObj } from '../types'; - -function checkForRateLimitError(resp: StdObj) { - if (JSON.stringify(resp)?.toLowerCase().includes('rate limit')) { - return true; - } - return false; -} - -export async function wrapHttpReqInCache( - getMongoCache: AsyncUtils['getMongoCache'], - url: string, - opts?: { data?: StdObj; headers?: Record } -): Promise { - const cache = await getMongoCache(); - let resp: StdObj; - - const reqHash = Web3.utils.sha3(`${url}-${JSON.stringify(opts?.data)}`); - const existing = await cache.collection('cache').findOne({ reqHash }); - if (existing) { - resp = JSON.parse(existing.response as string) as StdObj; - if (!checkForRateLimitError(resp)) { - return resp; - } - } - - try { - let resp: StdObj; - if (opts?.data) { - resp = (await _fetch(url, { - method: 'POST', - body: JSON.stringify(opts.data), - headers: { 'content-type': 'application/json', ...opts.headers }, - }).then((r) => r.json())) as StdObj; - } else { - resp = (await _fetch(url, { headers: { ...opts?.headers } }).then((r) => r.json())) as StdObj; - } - - await cache - .collection('cache') - .updateOne({ reqHash }, { $set: { response: JSON.stringify(resp) } }, { upsert: true }); - } catch (e) { - if (['invalid argument'].find((msg) => (e as Error).message.includes(msg))) { - return null; - } - throw e; - } - - if (checkForRateLimitError(resp)) { - throw new Error('Hit rate limit for URI'); - } - - return resp; -} diff --git a/src/transformers/helpers/sigMapper.ts b/src/transformers/helpers/sigMapper.ts deleted file mode 100644 index d51b10e..0000000 --- a/src/transformers/helpers/sigMapper.ts +++ /dev/null @@ -1,150 +0,0 @@ -import { ethers } from 'ethers'; -import { AsyncUtils } from '../types'; - -function sortByValue(obj: Record): [string, string][] { - return Object.entries(obj).sort(([, aVal], [, bVal]) => parseInt(bVal) - parseInt(aVal)); -} - -export function decodeTx(abi: ethers.InterfaceAbi, input: string): ethers.TransactionDescription | undefined { - try { - const iface = new ethers.Interface(abi); - const transactionDescriptor = iface.parseTransaction({ - data: input, - }); - return transactionDescriptor; - } catch (err) { - return undefined; - } -} - -export function decodeEvent( - abi: ethers.InterfaceAbi, - topics: string[], - data: string -): ethers.LogDescription | undefined { - try { - const iface = new ethers.Interface(abi); - const logDescriptor = iface.parseLog({ - topics, - data, - }); - return logDescriptor; - } catch (err) { - return undefined; - } -} - -export async function decodeTransaction( - address: string, - input: string, - abiUtils: AsyncUtils['abi'] -): Promise { - // if input is nothing - if (input === '0x' || !input) return null; - - let abi: ethers.InterfaceAbi; - // check if contract is proxy, if yes, get implementation address - const implementationAddress = await abiUtils.getProxyImplementations(address); - if (implementationAddress?.length > 0) { - // grab abis from proxy implementations - const abiPromises = implementationAddress.map((addr) => abiUtils.get(addr)); - const abis = await Promise.all(abiPromises); - const uniqueAbiSet = new Set(abis.flat().map((ele) => JSON.stringify(ele))); - abi = Array.from(uniqueAbiSet).map((ele) => JSON.parse(ele) as string | ethers.Fragment | ethers.JsonFragment); - } else { - // fetch abi from address - abi = await abiUtils.get(address); - } - - if (abi) { - // decode with abi - try { - const transactionDescriptor = decodeTx(abi, input); - if (transactionDescriptor) { - return transactionDescriptor; - } - } catch (e) { - // ignore this for now - } - } - - // decode with hash - const sigHash = input.slice(0, 10); - const allMatchingFunctionVariants = await abiUtils.getHashMap(sigHash); - if (Object.keys(allMatchingFunctionVariants).length === 0) { - return undefined; - } - - const sortedFunctions = sortByValue(allMatchingFunctionVariants); - for (const functionHash of sortedFunctions) { - try { - const transactionDescriptor = decodeTx([`function ${functionHash[0]}`], input); - // if its correct hash - if (transactionDescriptor) { - return transactionDescriptor; - } - } catch (e) { - // ignore this for now - } - } - - return undefined; -} - -export async function decodeLog( - address: string, - topics: string[], - data: string, - abiUtils: AsyncUtils['abi'] -): Promise { - if (topics.length === 0) { - return null; - } - let abi: ethers.InterfaceAbi; - // check if contract is proxy, if yes, get implementation address - const implementationAddress = await abiUtils.getProxyImplementations(address); - if (implementationAddress?.length > 0) { - // grab abis from proxy implementations - const abiPromises = implementationAddress.map((addr) => abiUtils.get(addr)); - const abis = await Promise.all(abiPromises); - const uniqueAbiSet = new Set(abis.flat().map((ele) => JSON.stringify(ele))); - abi = Array.from(uniqueAbiSet).map((ele) => JSON.parse(ele) as string | ethers.Fragment | ethers.JsonFragment); - } else { - // fetch abi from address - abi = await abiUtils.get(address); - } - if (abi) { - // decode with abi - try { - const logDescriptor = decodeEvent(abi, topics, data); - if (logDescriptor) { - return logDescriptor; - } - } catch (e) { - // ignore this for now - } - } - - // decode with hash - const eventHash = topics[0]; - const eventSigResult = await abiUtils.getHashMap(eventHash); - const eventSig = Object.keys(eventSigResult)[0]; - const allMatchingEventVariants = await abiUtils.getHashMap(eventSig); - if (Object.keys(allMatchingEventVariants).length === 0) { - return undefined; - } - - const sortedEvents = sortByValue(allMatchingEventVariants); - for (const event of sortedEvents) { - try { - const logDescriptor = decodeEvent([`event ${event[0]}`], topics, data); - if (logDescriptor) { - return logDescriptor; - } - } catch (e) { - // ignore this for now - } - } - - return undefined; -} diff --git a/src/transformers/helpers/utils.ts b/src/transformers/helpers/utils.ts deleted file mode 100644 index 3f0f308..0000000 --- a/src/transformers/helpers/utils.ts +++ /dev/null @@ -1,208 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unsafe-return */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ -/* eslint-disable @typescript-eslint/no-unsafe-call */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -import BigNumber from 'bignumber.js'; -import { ethers } from 'ethers'; -import { EVM } from 'evm'; - -import { - ERC20_METHODS, - ERC777_METHODS, - ERC721_METHODS, - ERC1155_METHODS, - ERC165_METHODS, - GOVERNOR_METHODS, - SAFE_METHODS, - PROXY_IMPLEMENTATION_METHODS, -} from './constants'; -import { AsyncUtils, RawBlock, StdObj, TransactionDescription } from '../types'; - -// this configuration helps us handle wei -> integer -> string conversions being in scientific notation -// (we don't want scientific notation) -BigNumber.config({ EXPONENTIAL_AT: 1000 }); - -// monkey-patch BigInt to serialize as JSON -// more context here: https://github.com/GoogleChromeLabs/jsbi/issues/30 -(BigInt.prototype as any).toJSON = function () { - return this.toString(); -}; - -export const toBigNumber = (v: unknown) => new BigNumber(v as string); - -export const bytecodeIsERC = (standard: Record, bytecode: string): boolean => { - const ercMethodsDetected = Object.keys(standard).filter((key: string): boolean => bytecode.includes(standard[key])); - return ercMethodsDetected.length == Object.keys(standard).length; -}; - -export const bytecodeIsERC20 = (bytecode: string): boolean => bytecodeIsERC(ERC20_METHODS, bytecode); -export const bytecodeIsERC777 = (bytecode: string): boolean => bytecodeIsERC(ERC777_METHODS, bytecode); -export const bytecodeIsERC721 = (bytecode: string): boolean => bytecodeIsERC(ERC721_METHODS, bytecode); -export const bytecodeIsERC1155 = (bytecode: string): boolean => bytecodeIsERC(ERC1155_METHODS, bytecode); -export const bytecodeIsERC165 = (bytecode: string): boolean => bytecodeIsERC(ERC165_METHODS, bytecode); -export const bytecodeIsIGovernor = (bytecode: string): boolean => bytecodeIsERC(GOVERNOR_METHODS, bytecode); -export const bytecodeIsGnosisSafe = (bytecode: string): boolean => bytecodeIsERC(SAFE_METHODS, bytecode); - -export const normalizeBlock = (block: StdObj): RawBlock => { - // console.log('block', block); - - let str = JSON.stringify(block); - - // replace all EVM addresses with lowercased versions - str = str.replace(/("0x[A-z0-9]{40}")/g, (v) => v.toLowerCase()); - - return JSON.parse(str) as RawBlock; -}; - -export function decodeEVMAddress(addressString: string): string { - if (!addressString) return ''; - - const buf = Buffer.from(addressString.replace(/^0x/, ''), 'hex'); - if (!buf.slice(0, 12).equals(Buffer.alloc(12, 0))) { - return ''; - } - const address = '0x' + buf.toString('hex', 12, 32); // grab the last 20 bytes - return address.toLocaleLowerCase(); -} - -export const hexToString = (str: string) => { - const buf = Buffer.from(str, 'hex'); - return buf.toString('utf8'); -}; - -const VALID_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890.? '; - -export const countValidChars = (stringToCount: string) => { - let count = 0; - for (let i = 0; i < stringToCount.length; i++) { - if (VALID_CHARS.indexOf(stringToCount[i]) >= 0) { - count++; - } - } - return count; -}; - -export const convertToString = (value: any): string => { - // Check if the value is not null or undefined, and it has a toString() method. - if (value !== null && value !== undefined && typeof value?.toString === 'function') { - return value.toString(); - } else { - // Return an empty string if the value is not convertible to a string. - return ''; - } -}; - -export function splitStringIntoChunks(inputString: string, chunkSize: number): string[] { - const chunks: string[] = []; - for (let i = 0; i < inputString.length; i += chunkSize) { - chunks.push(inputString.slice(i, i + chunkSize)); - } - return chunks; -} - -export function convertBNToStringInTx(decodeResult: ethers.TransactionDescription): TransactionDescription { - let txDecode; - if (decodeResult) { - try { - txDecode = { - ...decodeResult, - value: decodeResult.value.toString(), - fragment: { - ...decodeResult.fragment, - gas: decodeResult.fragment.gas ? decodeResult.fragment.gas.toString() : null, - }, - args: decodeResult.args.map((arg) => convertToString(arg)), - }; - } catch (e) { - // ignore deferred ethers error - } - } - - return txDecode; -} - -export function objectToDotNotation(obj: Record, current?: string) { - if (!obj || typeof obj !== 'object') { - return obj; - } - - const newObj = {}; - - for (const key in obj) { - const val = obj[key]; - const newKey = current ? `${current}.${key}` : key; - if (val && typeof val === 'object') { - Object.assign(newObj, objectToDotNotation(val as Record, newKey)); - } else { - newObj[newKey] = val; - } - } - - return newObj; -} -/** - * Detect custom proxy and its implementation. - * @param address The Ethereum address to check. - * @param web3Provider The provider for web3 interactions. - * @returns The target address if found, otherwise an empty string. - */ -export async function detectCustomProxy(address: string, web3Provider: AsyncUtils['web3Provider']): Promise { - // Retrieve the bytecode of the given address - const code = await web3Provider.getCode(address); - const evm = new EVM(code); - const opcodes = evm.getOpcodes(); - - // Check if bytecode contains DELEGATECALL - const hasDelegateCall = opcodes.some((opcode) => opcode.name === 'DELEGATECALL'); - - // Retrieve potential proxy implementations - const implementations: string[] = await Promise.all( - Object.values(PROXY_IMPLEMENTATION_METHODS).map(async (method) => { - try { - return await web3Provider.send('eth_call', [ - { - to: address, - data: `0x${method}`, - }, - ]); - } catch (error) { - return ''; - } - }) - ); - - // Search for a valid implementation address - const target = - implementations - .map((implementation) => decodeEVMAddress(implementation)) - .find((implementation) => implementation && ethers.isAddress(implementation)) || ''; - - return hasDelegateCall && target ? target : ''; -} - -export const getTokenName = async (token): Promise => { - try { - return (await token.methods.name().call()) as string; - } catch (error) { - console.log(`Name method not implemented.`); - return ''; - } -}; - -export const getTokenSymbol = async (token): Promise => { - try { - return (await token.methods.symbol().call()) as string; - } catch (error) { - console.log('Symbol method not implemented.'); - return ''; - } -}; - -export const getTokenDecimals = async (token): Promise => { - try { - return (await token.methods.decimals().call()) as number; - } catch (error) { - console.log('Decimals method not implemented.'); - return 18; - } -}; diff --git a/src/transformers/types.ts b/src/transformers/types.ts deleted file mode 100644 index 4b051d5..0000000 --- a/src/transformers/types.ts +++ /dev/null @@ -1,380 +0,0 @@ -// import { ethers } from 'ethers'; -export type StdObj = Record; - -// INTERFACES - -export type Config = { - async: boolean; - chains?: string[]; - checkMethod?: string; - method: string; - outputModel: 'block' | 'transaction'; - outputSource: 'json'; - phaseName: string; - rateLimit?: number; // measured in requests per second - sourcePhase: string; -}; - - -// PAYLOAD TYPES - -export type AssetTransfer = { - asset?: string; // === 'contractAddress' - burn?: boolean; - from: string; - mint?: boolean; - to: string; - tokenId?: string; - value?: string; - type: 'erc20' | 'erc721' | 'erc1155' | 'eth'; -}; - -export type NetAssetTransfer = { - asset: string; - from?: string; - to?: string; - id: string; - tokenId?: string; - type: AssetTransfer['type']; - value: string; -}; - -export type NetAssetTransfers = Record; - -export type RawBlock = StdObj & { - chainId?: number; - number: number; - timestamp: number; - transactions: RawTransaction[]; -}; - -export type RawLog = StdObj & { - address: string; - data: string; - logIndex: number; - topics: string[]; - decode?: LogDescription; -}; - -export type RawReceipt = StdObj & { - logs: RawLog[]; -}; - -export type RawTransaction = StdObj & { - accessList?: StdObj[]; - blockNumber: number; - from: string; - hash: string; - input: string; - value: string; - receipt: RawReceipt; - to: string; - traces: RawTrace[]; - contracts?: Contract[]; - decode?: TransactionDescription; - context: TxContext; - assetTransfers: AssetTransfer[]; - netAssetTransfers: NetAssetTransfers; -}; - -export type RawTraceAction = StdObj & { - address: string; - balance?: string; - callType?: string; - from: string; - refundAddress?: string; - to?: string; - value?: string; - input?: string; -}; - -export type RawTraceResult = StdObj & { - address?: string; - code: string; - hash: string; - receipt: StdObj; - to: string; - traces: RawTrace[]; - transactionIndex: number; -}; - -export type RawTrace = StdObj & { - action: RawTraceAction; - blockNumber: number; - blockhash: string; - error?: string; - result: RawTraceResult; - subtraces: number; - traceAddress: number[]; - transactionHash: string; - transactionPosition: number; - type: string; - decode?: TransactionDescription; -}; - -export type SupportedInterfaces = Record; - -export type ContractMetadata = { - isUniswapV3: boolean; - isUniswapV2: boolean; - isUniswapV1: boolean; - uniswapPairs: string[]; - isPropHouseToken: boolean; - isPropHouseMetadata: boolean; - isPropHouseAuction: boolean; - isPropHouseTreasury: boolean; - isPropHouseGovernor: boolean; - isGenericGovernance: boolean; - isGnosisSafe: boolean; - - alchemy?: StdObj; - coingecko?: StdObj; - etherscan?: StdObj; - opensea?: StdObj; - simplehash?: StdObj; - tally?: TallyMetadata; - whatsAbiSelectors: string[]; - // whatsAbiAbi: ethers.InterfaceAbi; - isProxy: boolean; - implementationAddress?: string; - tokenMetadata?: TokenMetadata; -}; - -export type UniswapPair = { - address: string; - tokens: string[]; -}; - -export type Contract = { - chainId?: number; - deployer: string; - directDeployer: string; - address: string; - bytecode: string; - fingerprint: string; - gas: unknown; // TOOD - do we convert with bignumber here? - gasUsed: unknown; // TODO - do we convert with bignumber here? - blockNumber: number; - transactionHash: string; - type: 'create' | 'create2'; - metadata?: ContractMetadata; - supportedInterfaces?: SupportedInterfaces; - sigHash: string; - internalSigHashes: string[]; - transactionIndex: number; - traceIndex: number; - ethTransfer: boolean; - timestamp: number; - isoTimestamp: string; -}; - -export type TokenStandard = 'erc20' | 'erc721' | 'erc777' | 'erc1155' | ''; - -export type TokenMetadata = { - tokenStandard: TokenStandard; - name?: string; - symbol?: string; - decimals?: number; -}; - -/** ABI */ - -export type AbiType = 'function' | 'constructor' | 'event' | 'fallback' | 'receive'; -export type StateMutabilityType = 'pure' | 'view' | 'nonpayable' | 'payable'; - -export interface AbiItem { - anonymous?: boolean; - constant?: boolean; - inputs?: AbiInput[]; - name?: string; - outputs?: AbiOutput[]; - payable?: boolean; - stateMutability?: StateMutabilityType; - type: AbiType; - gas?: number; -} - -export interface AbiInput { - name: string; - type: string; - indexed?: boolean; - components?: AbiInput[]; - internalType?: string; -} - -export interface AbiOutput { - name: string; - type: string; - components?: AbiOutput[]; - internalType?: string; -} - -export type TransactionContract = { - hash: string; - contracts: Contract[]; -}; - -export type transactionAssetTransfers = { - hash: string; - assetTransfers: AssetTransfer[]; -}; - -export type InternalHashType = { - sigHash: string; - from: string; - to: string; -}; - -export type TransactionWithHash = { - hash: string; - sigHash: string; - internalSigHashes: InternalHashType[]; -}; - -export type TransactionDescription = { - fragment: { - name: string; - // type: ethers.FragmentType; - // inputs: ReadonlyArray; - // outputs: ReadonlyArray; - constant: boolean; - stateMutability: 'payable' | 'nonpayable' | 'view' | 'pure'; - payable: boolean; - gas: null | string; - }; - name: string; - args: string[]; - signature: string; - selector: string; - value: string; -}; - -export type LogDescription = { - fragment: { - name: string; - // type: ethers.FragmentType; - // inputs: ReadonlyArray; - anonymous: boolean; - }; - name: string; - signature: string; - args: string[]; - topic: string; -}; - -export type DecodeStatistics = { - totalLogs: number; - parsedLogs: number; - totalTraces: number; - parsedTraces: number; - isParsed: boolean; -}; - -export type TransactionDecode = { - hash: string; - decode?: TransactionDescription; - receipt?: RawReceipt; - traces?: RawTrace[]; -}; - -export type TransactionWithIDM = { - hash: string; - idm: boolean; -}; - -export type PropHouseDao = { - token: string; - metadata: string; - auction: string; - treasury: string; - governor: string; -}; - -export type TallyGovernorAPIResponse = { - data: { - governors: TallyMetadata[]; - }; -}; - -export type TallyMetadata = { - type: string; - name: string; - quorum: string; - timelockId: string; - parameters: { - quorumVotes: string; - proposalThreshold: string; - votingDelay: string; - votingPeriod: string; - quorumNumerator: string; - quorumDenominator: string; - }; - proposalStats: { - total: number; - active: number; - failed: number; - passed: number; - }; - tokens: [ - { - id: string; - type: string; - address: string; - name: string; - symbol: string; - supply: string; - lastBlock: number; - decimals: number; - } - ]; - slug: string; -}; - -export type AddressInteractedWith = { - hash: string; - addressInteractedWith: { - address: string; - interactedWith: string; - }; -}; - -export type AddressesPartiedWith = { - hash: string; - addressesPartiedWith: { - address: string; - interactedWith: string; - }[]; -}; - -export type Neighbor = { - hash: string; - neighbor: { - address: string; - neighbor: string; - }; -}; - -export type TransactionWithContext = { - hash: string; - context: TxContext; -}; - -export type TxContextValueType = { - type: string; - value: string; -}; - -export type TxContext = { - type: string; -}; - -export type TransactionDecodeGnosisSafe = { - hash: string; - decodeGnosis?: GnosisSafeDecode; -}; - -export type GnosisSafeDecode = { - target: string; - data: string; - decode: TransactionDescription; -}; diff --git a/src/types/assetTransfer.ts b/src/types/assetTransfer.ts index cc56fe9..effdecd 100644 --- a/src/types/assetTransfer.ts +++ b/src/types/assetTransfer.ts @@ -1,12 +1,12 @@ -import {AssetType} from "./shared" +import { AssetType } from './shared'; export type AssetTransfer = { - asset?: string; // === 'contractAddress' - burn?: boolean; - from: string; - mint?: boolean; - to: string; - tokenId?: string; - value?: string; - type: AssetType; -}; \ No newline at end of file + asset?: string; // === 'contractAddress' + burn?: boolean; + from: string; + mint?: boolean; + to: string; + tokenId?: string; + value?: string; + type: AssetType; +}; diff --git a/src/types/block.ts b/src/types/block.ts index 4322bb8..b108353 100644 --- a/src/types/block.ts +++ b/src/types/block.ts @@ -1,10 +1,9 @@ -import {StdObj} from "./shared" -import {RawTransaction} from "./transaction" +import { StdObj } from './shared'; +import { RawTransaction } from './transaction'; export type RawBlock = StdObj & { - chainId?: number; - number: number; - timestamp: number; - transactions: RawTransaction[]; - }; - \ No newline at end of file + chainId?: number; + number: number; + timestamp: number; + transactions: RawTransaction[]; +}; diff --git a/src/types/contract.ts b/src/types/contract.ts index 307c0b8..e416708 100644 --- a/src/types/contract.ts +++ b/src/types/contract.ts @@ -1,97 +1,95 @@ - -import {StdObj} from "./shared" +import { StdObj } from './shared'; export type Contract = { - chainId?: number; - deployer: string; - directDeployer: string; - address: string; - bytecode: string; - fingerprint: string; - gas: unknown; // TOOD - do we convert with bignumber here? - gasUsed: unknown; // TODO - do we convert with bignumber here? - blockNumber: number; - transactionHash: string; - type: 'create' | 'create2'; - metadata?: ContractMetadata; - supportedInterfaces?: SupportedInterfaces; - sigHash: string; - internalSigHashes: string[]; - transactionIndex: number; - traceIndex: number; - ethTransfer: boolean; - timestamp: number; - isoTimestamp: string; + chainId?: number; + deployer: string; + directDeployer: string; + address: string; + bytecode: string; + fingerprint: string; + gas: unknown; // TOOD - do we convert with bignumber here? + gasUsed: unknown; // TODO - do we convert with bignumber here? + blockNumber: number; + transactionHash: string; + type: 'create' | 'create2'; + metadata?: ContractMetadata; + supportedInterfaces?: SupportedInterfaces; + sigHash: string; + internalSigHashes: string[]; + transactionIndex: number; + traceIndex: number; + ethTransfer: boolean; + timestamp: number; + isoTimestamp: string; }; export type ContractMetadata = { - isUniswapV3: boolean; - isUniswapV2: boolean; - isUniswapV1: boolean; - uniswapPairs: string[]; - isPropHouseToken: boolean; - isPropHouseMetadata: boolean; - isPropHouseAuction: boolean; - isPropHouseTreasury: boolean; - isPropHouseGovernor: boolean; - isGenericGovernance: boolean; - isGnosisSafe: boolean; - - alchemy?: StdObj; - coingecko?: StdObj; - etherscan?: StdObj; - opensea?: StdObj; - simplehash?: StdObj; - tally?: TallyMetadata; - whatsAbiSelectors: string[]; - // whatsAbiAbi: ethers.InterfaceAbi; - isProxy: boolean; - implementationAddress?: string; - tokenMetadata?: TokenMetadata; + isUniswapV3: boolean; + isUniswapV2: boolean; + isUniswapV1: boolean; + uniswapPairs: string[]; + isPropHouseToken: boolean; + isPropHouseMetadata: boolean; + isPropHouseAuction: boolean; + isPropHouseTreasury: boolean; + isPropHouseGovernor: boolean; + isGenericGovernance: boolean; + isGnosisSafe: boolean; + + alchemy?: StdObj; + coingecko?: StdObj; + etherscan?: StdObj; + opensea?: StdObj; + simplehash?: StdObj; + tally?: TallyMetadata; + whatsAbiSelectors: string[]; + // whatsAbiAbi: ethers.InterfaceAbi; + isProxy: boolean; + implementationAddress?: string; + tokenMetadata?: TokenMetadata; }; export type SupportedInterfaces = Record; - export type TallyMetadata = { - type: string; - name: string; - quorum: string; - timelockId: string; - parameters: { - quorumVotes: string; - proposalThreshold: string; - votingDelay: string; - votingPeriod: string; - quorumNumerator: string; - quorumDenominator: string; - }; - proposalStats: { - total: number; - active: number; - failed: number; - passed: number; - }; - tokens: [ - { - id: string; - type: string; - address: string; - name: string; - symbol: string; - supply: string; - lastBlock: number; - decimals: number; - } - ]; - slug: string; + type: string; + name: string; + quorum: string; + timelockId: string; + parameters: { + quorumVotes: string; + proposalThreshold: string; + votingDelay: string; + votingPeriod: string; + quorumNumerator: string; + quorumDenominator: string; + }; + proposalStats: { + total: number; + active: number; + failed: number; + passed: number; + }; + tokens: [ + { + id: string; + type: string; + address: string; + name: string; + symbol: string; + supply: string; + lastBlock: number; + decimals: number; + }, + ]; + slug: string; }; export type TokenStandard = 'erc20' | 'erc721' | 'erc777' | 'erc1155' | ''; export type TokenMetadata = { - tokenStandard: TokenStandard; - name?: string; - symbol?: string; - decimals?: number; -}; \ No newline at end of file + tokenStandard: TokenStandard; + name?: string; + symbol?: string; + decimals?: number; +}; diff --git a/src/types/index.ts b/src/types/index.ts index df39353..5b2df5b 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,7 +1,7 @@ -export * from "./assetTransfer" -export * from "./block" -export * from "./contract" -export * from "./log" -export * from "./netAssetTransfer" -export * from "./shared" -export * from "./transaction" \ No newline at end of file +export * from './assetTransfer'; +export * from './block'; +export * from './contract'; +export * from './log'; +export * from './netAssetTransfer'; +export * from './shared'; +export * from './transaction'; diff --git a/src/types/log.ts b/src/types/log.ts index 00eafcf..563d3dd 100644 --- a/src/types/log.ts +++ b/src/types/log.ts @@ -1,26 +1,26 @@ -import {StdObj} from "./shared" +import { StdObj } from './shared'; export type LogDescription = { - fragment: { - name: string; - // type: ethers.FragmentType; - // inputs: ReadonlyArray; - anonymous: boolean; - }; + fragment: { name: string; - signature: string; - args: string[]; - topic: string; + // type: ethers.FragmentType; + // inputs: ReadonlyArray; + anonymous: boolean; + }; + name: string; + signature: string; + args: string[]; + topic: string; }; export type RawLog = StdObj & { - address: string; - data: string; - logIndex: number; - topics: string[]; - decode?: LogDescription; - }; + address: string; + data: string; + logIndex: number; + topics: string[]; + decode?: LogDescription; +}; export type RawReceipt = StdObj & { - logs: RawLog[]; -}; \ No newline at end of file + logs: RawLog[]; +}; diff --git a/src/types/netAssetTransfer.ts b/src/types/netAssetTransfer.ts index e09d4c6..9a434af 100644 --- a/src/types/netAssetTransfer.ts +++ b/src/types/netAssetTransfer.ts @@ -1,13 +1,16 @@ -import {AssetType} from "./shared" +import { AssetType } from './shared'; export type NetAssetTransfer = { - asset: string; - from?: string; - to?: string; - id: string; - tokenId?: string; - type: AssetType; - value: string; + asset: string; + from?: string; + to?: string; + id: string; + tokenId?: string; + type: AssetType; + value: string; }; -export type NetAssetTransfers = Record; +export type NetAssetTransfers = Record< + string, + { received: NetAssetTransfer[]; sent: NetAssetTransfer[] } +>; diff --git a/src/types/shared.ts b/src/types/shared.ts index f0a0f3a..7270bd7 100644 --- a/src/types/shared.ts +++ b/src/types/shared.ts @@ -1,3 +1,39 @@ export type StdObj = Record; export type AssetType = 'erc20' | 'erc721' | 'erc1155' | 'eth'; +/** ABI */ + +export type AbiType = + | 'function' + | 'constructor' + | 'event' + | 'fallback' + | 'receive'; +export type StateMutabilityType = 'pure' | 'view' | 'nonpayable' | 'payable'; + +export interface AbiItem { + anonymous?: boolean; + constant?: boolean; + inputs?: AbiInput[]; + name?: string; + outputs?: AbiOutput[]; + payable?: boolean; + stateMutability?: StateMutabilityType; + type: AbiType; + gas?: number; +} + +export interface AbiInput { + name: string; + type: string; + indexed?: boolean; + components?: AbiInput[]; + internalType?: string; +} + +export interface AbiOutput { + name: string; + type: string; + components?: AbiOutput[]; + internalType?: string; +} diff --git a/src/types/transaction.ts b/src/types/transaction.ts index 3bc4466..41ca3f5 100644 --- a/src/types/transaction.ts +++ b/src/types/transaction.ts @@ -1,79 +1,79 @@ -import {StdObj} from "./shared" -import {AssetTransfer} from "./assetTransfer" -import {NetAssetTransfers} from "./netAssetTransfer" -import {RawReceipt} from "./log" -import { Contract } from "./contract" +import { StdObj } from './shared'; +import { AssetTransfer } from './assetTransfer'; +import { NetAssetTransfers } from './netAssetTransfer'; +import { RawReceipt } from './log'; +import { Contract } from './contract'; export type RawTransaction = StdObj & { - accessList?: StdObj[]; - blockNumber: number; - from: string; - hash: string; - input: string; - value: string; - receipt: RawReceipt; - to: string; - traces: RawTrace[]; - contracts?: Contract[]; - decode?: TransactionDescription; - context: TxContext; - assetTransfers: AssetTransfer[]; - netAssetTransfers: NetAssetTransfers; + accessList?: StdObj[]; + blockNumber: number; + from: string; + hash: string; + input: string; + value: string; + receipt: RawReceipt; + to: string; + traces: RawTrace[]; + contracts?: Contract[]; + decode?: TransactionDescription; + context: TxContext; + assetTransfers: AssetTransfer[]; + netAssetTransfers: NetAssetTransfers; }; export type RawTraceAction = StdObj & { - address: string; - balance?: string; - callType?: string; - from: string; - refundAddress?: string; - to?: string; - value?: string; - input?: string; + address: string; + balance?: string; + callType?: string; + from: string; + refundAddress?: string; + to?: string; + value?: string; + input?: string; }; - + export type RawTraceResult = StdObj & { - address?: string; - code: string; - hash: string; - receipt: StdObj; - to: string; - traces: RawTrace[]; - transactionIndex: number; + address?: string; + code: string; + hash: string; + receipt: StdObj; + to: string; + traces: RawTrace[]; + transactionIndex: number; }; - + export type RawTrace = StdObj & { - action: RawTraceAction; - blockNumber: number; - blockhash: string; - error?: string; - result: RawTraceResult; - subtraces: number; - traceAddress: number[]; - transactionHash: string; - transactionPosition: number; - type: string; - decode?: TransactionDescription; + action: RawTraceAction; + blockNumber: number; + blockhash: string; + error?: string; + result: RawTraceResult; + subtraces: number; + traceAddress: number[]; + transactionHash: string; + transactionPosition: number; + type: string; + decode?: TransactionDescription; }; export type TransactionDescription = { - fragment: { - name: string; - // type: ethers.FragmentType; - // inputs: ReadonlyArray; - // outputs: ReadonlyArray; - constant: boolean; - stateMutability: 'payable' | 'nonpayable' | 'view' | 'pure'; - payable: boolean; - gas: null | string; - }; + fragment: { name: string; - args: string[]; - signature: string; - selector: string; - value: string; + // type: ethers.FragmentType; + // inputs: ReadonlyArray; + // outputs: ReadonlyArray; + constant: boolean; + stateMutability: 'payable' | 'nonpayable' | 'view' | 'pure'; + payable: boolean; + gas: null | string; + }; + name: string; + args: string[]; + signature: string; + selector: string; + value: string; }; export type TxContext = { - type: string; -}; \ No newline at end of file + type: string; +}; From e90ce936cfa8a2037147cb62146ff16af4482bbb Mon Sep 17 00:00:00 2001 From: ponyjackal Date: Fri, 26 Jan 2024 03:56:41 -0800 Subject: [PATCH 4/9] feat: update transactionParties --- package-lock.json | 74 ++++++++++++++++ package.json | 1 + src/helpers/utils.ts | 11 +++ src/transformers/_common/blockGasUsage.ts | 11 +-- src/transformers/_common/contractABI.ts | 31 ++++++- .../_common/transactionNetAssetTransfers.ts | 86 ++++++++++++------- .../_common/transactionParties.ts | 62 +++++++++---- .../_common/transactionProxyUpgrades.ts | 8 +- .../_common/transactionSigHash.ts | 6 +- .../_common/transactionTimestamp.ts | 2 +- src/types/assetTransfer.ts | 78 +++++++++++++++-- src/types/block.ts | 2 + src/types/contract.ts | 4 +- src/types/log.ts | 6 +- src/types/shared.ts | 50 ++++++++++- src/types/transaction.ts | 8 +- 16 files changed, 358 insertions(+), 82 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5f511b2..2f2e15d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.0.1", "license": "MIT", "dependencies": { + "@shazow/whatsabi": "^0.11.0", "commander": "^11.1.0", "dotenv": "^16.3.1", "handlebars": "^4.7.8", @@ -1373,6 +1374,17 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/@shazow/whatsabi": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@shazow/whatsabi/-/whatsabi-0.11.0.tgz", + "integrity": "sha512-dIjhgynJeqPLwSI179E37yFElq+IDyy6xBk9fthkhZp/NO6o2AvtJUq9hWotCBNX/ZQzh6ak7CmdHevwralW8w==", + "dependencies": { + "ethers": "^6.10.0" + }, + "peerDependencies": { + "@noble/hashes": "^1" + } + }, "node_modules/@sinclair/typebox": { "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", @@ -1764,6 +1776,11 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/aes-js": { + "version": "4.0.0-beta.5", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz", + "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==" + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -2715,6 +2732,63 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/ethers": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.10.0.tgz", + "integrity": "sha512-nMNwYHzs6V1FR3Y4cdfxSQmNgZsRj1RiTU25JwvnJLmyzw9z3SKxNc2XKDuiXXo/v9ds5Mp9m6HBabgYQQ26tA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/ethers-io/" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@adraffy/ens-normalize": "1.10.0", + "@noble/curves": "1.2.0", + "@noble/hashes": "1.3.2", + "@types/node": "18.15.13", + "aes-js": "4.0.0-beta.5", + "tslib": "2.4.0", + "ws": "8.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/ethers/node_modules/@types/node": { + "version": "18.15.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.13.tgz", + "integrity": "sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==" + }, + "node_modules/ethers/node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "node_modules/ethers/node_modules/ws": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", + "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", diff --git a/package.json b/package.json index 7fe5c5f..1ee73c5 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "testEnvironment": "node" }, "dependencies": { + "@shazow/whatsabi": "^0.11.0", "commander": "^11.1.0", "dotenv": "^16.3.1", "handlebars": "^4.7.8", diff --git a/src/helpers/utils.ts b/src/helpers/utils.ts index 27750f7..e76ea03 100644 --- a/src/helpers/utils.ts +++ b/src/helpers/utils.ts @@ -160,3 +160,14 @@ export const getTokenDecimals = async (token): Promise => { return 18; } }; + +export function decodeEVMAddress(addressString: string): string { + if (!addressString) return ''; + + const buf = Buffer.from(addressString.replace(/^0x/, ''), 'hex'); + if (!buf.slice(0, 12).equals(Buffer.alloc(12, 0))) { + return ''; + } + const address = '0x' + buf.toString('hex', 12, 32); // grab the last 20 bytes + return address.toLocaleLowerCase(); +} diff --git a/src/transformers/_common/blockGasUsage.ts b/src/transformers/_common/blockGasUsage.ts index e22a9f6..5fe0406 100644 --- a/src/transformers/_common/blockGasUsage.ts +++ b/src/transformers/_common/blockGasUsage.ts @@ -1,14 +1,11 @@ -import { toBigNumber } from '../helpers/utils'; -import type { RawBlock } from '../types'; +import type { RawBlock } from '../../types'; export function transform(block: RawBlock) { - const gasUsedPercentage = toBigNumber(block.gasUsed) - .multipliedBy(100) - .dividedBy(toBigNumber(block.gasLimit)) - .toString(); + const gasUsedPercentage = + (BigInt(block.gasUsed) * BigInt(100)) / BigInt(block.gasLimit); return { number: block.number, - gasUsedPercentage, + gasUsedPercentage: gasUsedPercentage.toString(), }; } diff --git a/src/transformers/_common/contractABI.ts b/src/transformers/_common/contractABI.ts index cddb9ee..2ece9c7 100644 --- a/src/transformers/_common/contractABI.ts +++ b/src/transformers/_common/contractABI.ts @@ -1,5 +1,5 @@ import { whatsabi } from '@shazow/whatsabi'; -import type { Contract, RawBlock, TransactionContract } from '../types'; +import type { Contract, RawBlock, TransactionContract } from '../../types'; export function transform(block: RawBlock): TransactionContract[] { const results: { hash: string; contracts: Contract[] }[] = []; @@ -12,14 +12,37 @@ export function transform(block: RawBlock): TransactionContract[] { const contracts = tx.contracts .map((txContract) => { try { + if (!txContract.metadata) { + txContract.metadata = { + isUniswapV3: false, + isUniswapV2: false, + isUniswapV1: false, + uniswapPairs: [], + isPropHouseToken: false, + isPropHouseMetadata: false, + isPropHouseAuction: false, + isPropHouseTreasury: false, + isPropHouseGovernor: false, + isGenericGovernance: false, + isGnosisSafe: false, + whatsAbiSelectors: [], + isProxy: false, + whatsAbiAbi: { + type: 'constructor', + }, + }; + } // Get just the callable selectors - txContract.metadata.whatsAbiSelectors = whatsabi.selectorsFromBytecode(txContract.bytecode); + txContract.metadata.whatsAbiSelectors = + whatsabi.selectorsFromBytecode(txContract.bytecode); // Get an ABI-like list of interfaces - txContract.metadata.whatsAbiAbi = whatsabi.abiFromBytecode(txContract.bytecode); + txContract.metadata.whatsAbiAbi = whatsabi.abiFromBytecode( + txContract.bytecode, + ); return txContract; } catch (e) { - return null; + return txContract; } }) .filter((v) => v); diff --git a/src/transformers/_common/transactionNetAssetTransfers.ts b/src/transformers/_common/transactionNetAssetTransfers.ts index 21fc77e..fc44ff7 100644 --- a/src/transformers/_common/transactionNetAssetTransfers.ts +++ b/src/transformers/_common/transactionNetAssetTransfers.ts @@ -1,6 +1,8 @@ -import BigNumber from 'bignumber.js'; -import type { RawBlock, NetAssetTransfer, NetAssetTransfers } from '../types'; -import { toBigNumber } from '../helpers/utils'; +import type { + RawBlock, + NetAssetTransfer, + NetAssetTransfers, +} from '../../types'; export function transform(block: RawBlock) { const results: { hash: string; netAssetTransfers: NetAssetTransfers }[] = []; @@ -12,7 +14,7 @@ export function transform(block: RawBlock) { } const assetsById: Record = {}; - const netAssetsByAddress: Record> = {}; + const netAssetsByAddress: Record> = {}; for (const txfer of assetTransfers) { if (txfer.from === txfer.to || !txfer.from || !txfer.to) { @@ -20,29 +22,41 @@ export function transform(block: RawBlock) { } let asset: NetAssetTransfer; - if (txfer.type === 'erc721' || txfer.type === 'erc1155') { - asset = { - asset: txfer.asset, - id: `${txfer.asset}-${txfer.tokenId}`, - tokenId: txfer.tokenId, - type: txfer.type, - value: txfer.value || '1', - }; - } else if (txfer.type === 'erc20') { - asset = { - asset: txfer.asset, - id: txfer.asset, - tokenId: txfer.tokenId, - type: txfer.type, - value: txfer.value, - }; - } else if (txfer.type === 'eth') { - asset = { - asset: 'eth', - id: 'eth', - type: txfer.type, - value: txfer.value, - }; + switch (txfer.type) { + case 'erc721': + asset = { + asset: txfer.asset, + id: `${txfer.asset}-${txfer.tokenId}`, + tokenId: txfer.tokenId, + type: txfer.type, + value: '1', + }; + break; + case 'erc1155': + asset = { + asset: txfer.asset, + id: `${txfer.asset}-${txfer.tokenId}`, + tokenId: txfer.tokenId, + type: txfer.type, + value: txfer.value, + }; + break; + case 'erc20': + asset = { + asset: txfer.asset, + id: `${txfer.asset}`, + type: txfer.type, + value: txfer.value, + }; + break; + case 'eth': + asset = { + asset: 'eth', + id: 'eth', + type: txfer.type, + value: txfer.value, + }; + break; } if (!asset.id || !asset.value || asset.value === '0') { @@ -63,8 +77,12 @@ export function transform(block: RawBlock) { } assetsById[asset.id] = asset; - netAssetsByAddress[txfer.from][asset.id] = netAssetsByAddress[txfer.from][asset.id].minus(asset.value); - netAssetsByAddress[txfer.to][asset.id] = netAssetsByAddress[txfer.to][asset.id].plus(asset.value); + netAssetsByAddress[txfer.from][asset.id] = netAssetsByAddress[txfer.from][ + asset.id + ].minus(asset.value); + netAssetsByAddress[txfer.to][asset.id] = netAssetsByAddress[txfer.to][ + asset.id + ].plus(asset.value); } const netAssetTransfers: NetAssetTransfers = {}; @@ -77,9 +95,15 @@ export function transform(block: RawBlock) { netAssetTransfers[address] = { received: [], sent: [] }; } if (value.lt(0)) { - netAssetTransfers[address].sent.push({ ...assetsById[id], value: value.multipliedBy(-1).toString() }); + netAssetTransfers[address].sent.push({ + ...assetsById[id], + value: value.multipliedBy(-1).toString(), + }); } else { - netAssetTransfers[address].received.push({ ...assetsById[id], value: value.toString() }); + netAssetTransfers[address].received.push({ + ...assetsById[id], + value: value.toString(), + }); } } } diff --git a/src/transformers/_common/transactionParties.ts b/src/transformers/_common/transactionParties.ts index 3be2d53..ea2541b 100644 --- a/src/transformers/_common/transactionParties.ts +++ b/src/transformers/_common/transactionParties.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/no-unsafe-call */ -import type { RawBlock } from '../types'; +import type { RawBlock } from '../../types'; type TransactionWithParties = { hash: string; @@ -16,9 +16,15 @@ export function transform(block: RawBlock): TransactionWithParties[] { parties = [...parties, tx.to.toLowerCase()]; } // address from input data - const inputAddresses = tx.decode?.fragment.inputs - .map((param, index) => (param.type === 'address' ? tx.decode?.args[index].toLowerCase() : '')) - .filter((address) => address !== ''); + const inputAddresses: string[] = tx.decode + ? tx.decode.fragment.inputs + .map((param, index) => + param.type === 'address' && tx.decode + ? tx.decode.args[index].toLowerCase() + : '', + ) + .filter((address) => address !== '') + : []; // addresses from traces const traceParties = tx.traces.map((trace) => { let result: string[] = []; @@ -29,14 +35,21 @@ export function transform(block: RawBlock): TransactionWithParties[] { result = [...result, trace.action.to.toLowerCase()]; } if (trace.type === 'suicide') { - result = [...result, trace.action.address.toLowerCase(), trace.action.refundAddress.toLowerCase()]; + result = [...result, trace.action.address.toLowerCase()]; + if (trace.action.refundAddress) { + result = [...result, trace.action.refundAddress.toLowerCase()]; + } } // grab event inputs params from decoded trace - const partiesFromTrace: string[] = trace.decode?.fragment.inputs - .map((param, index) => (param.type === 'address' ? trace.decode.args[index].toLowerCase() : '')) + const partiesFromTrace = trace.decode?.fragment.inputs + .map((param, index) => + param.type === 'address' && trace.decode + ? trace.decode.args[index].toLowerCase() + : '', + ) .filter((address) => address !== ''); - if (partiesFromTrace?.length > 0) { + if (partiesFromTrace && partiesFromTrace.length > 0) { result = [...result, ...partiesFromTrace]; } return result; @@ -45,11 +58,15 @@ export function transform(block: RawBlock): TransactionWithParties[] { const logParties = tx.receipt.logs.map((log) => { let result = [log.address.toLowerCase()]; // grab event inputs params from decoded log - const partiesFromLog: string[] = log.decode?.fragment.inputs - .map((param, index) => (param.type === 'address' ? log.decode.args[index].toLowerCase() : '')) + const partiesFromLog = log.decode?.fragment.inputs + .map((param, index) => + param.type === 'address' && log.decode + ? log.decode.args[index].toLowerCase() + : '', + ) .filter((address) => address !== ''); - if (partiesFromLog?.length > 0) { + if (partiesFromLog && partiesFromLog.length > 0) { result = [...result, ...partiesFromLog]; } return result; @@ -58,21 +75,30 @@ export function transform(block: RawBlock): TransactionWithParties[] { const nfts = tx.receipt.logs .filter( (log) => - (log.decode?.name === 'Transfer' || log.decode?.name === 'Approval') && - log.decode?.fragment.inputs[2]?.type === 'uint256' + (log.decode?.name === 'Transfer' || + log.decode?.name === 'Approval') && + log.decode?.fragment.inputs[2]?.type === 'uint256', ) .map((log) => `${log.address.toLowerCase()}-${log.decode?.args[2]}`); // contracts created - const contractsCreated: string[] = tx.contracts?.map((contract) => contract.address); - parties = [...parties, ...traceParties.flat(), ...logParties.flat(), ...nfts.flat()]; - if (inputAddresses?.length > 0) { + const contractsCreated = tx.contracts?.map((contract) => contract.address); + parties = [ + ...parties, + ...traceParties.flat(), + ...logParties.flat(), + ...nfts.flat(), + ]; + if (inputAddresses && inputAddresses.length > 0) { parties = [...parties, ...inputAddresses]; } - if (contractsCreated?.length > 0) { + if (contractsCreated && contractsCreated.length > 0) { parties = [...parties, ...contractsCreated]; } - return { hash: tx.hash, parties: [...new Set(parties)].filter((party) => party) }; + return { + hash: tx.hash, + parties: [...new Set(parties)].filter((party) => party), + }; }); return result; diff --git a/src/transformers/_common/transactionProxyUpgrades.ts b/src/transformers/_common/transactionProxyUpgrades.ts index 59e8bfa..2f2e6f6 100644 --- a/src/transformers/_common/transactionProxyUpgrades.ts +++ b/src/transformers/_common/transactionProxyUpgrades.ts @@ -1,6 +1,6 @@ -import type { RawBlock, RawTransaction } from '../types'; +import type { RawBlock, RawTransaction } from '../../types'; import { TRANSPARENT_UPGRADEABLE_PROXY_EVENTS } from '../../helpers/constants'; -import { decodeEVMAddress } from '../helpers/utils'; +import { decodeEVMAddress } from '../../helpers/utils'; type ProxyUpgrade = { hash: string; address: string; upgradedAddress: string }; @@ -9,7 +9,9 @@ function getProxyUpgrades(tx: RawTransaction): ProxyUpgrade[] { for (const log of tx.receipt.logs) { const [signature] = log.topics; // detect upgrade event - if (signature === TRANSPARENT_UPGRADEABLE_PROXY_EVENTS['Upgraded(address)']) { + if ( + signature === TRANSPARENT_UPGRADEABLE_PROXY_EVENTS['Upgraded(address)'] + ) { // store proxy upgrades const address = log.address.toLowerCase(); let upgradedAddress = ''; diff --git a/src/transformers/_common/transactionSigHash.ts b/src/transformers/_common/transactionSigHash.ts index ba7b6ad..1028eca 100644 --- a/src/transformers/_common/transactionSigHash.ts +++ b/src/transformers/_common/transactionSigHash.ts @@ -1,4 +1,8 @@ -import type { RawBlock, TransactionWithHash, InternalHashType } from '../types'; +import type { + RawBlock, + TransactionWithHash, + InternalHashType, +} from '../../types'; export function transform(block: RawBlock): TransactionWithHash[] { const result: TransactionWithHash[] = block.transactions.map((tx) => { diff --git a/src/transformers/_common/transactionTimestamp.ts b/src/transformers/_common/transactionTimestamp.ts index 11bfd90..93206bf 100644 --- a/src/transformers/_common/transactionTimestamp.ts +++ b/src/transformers/_common/transactionTimestamp.ts @@ -1,4 +1,4 @@ -import type { RawBlock } from '../types'; +import type { RawBlock } from '../../types'; export function transform(block: RawBlock) { const isoTimestamp = new Date(block.timestamp * 1000).toISOString(); diff --git a/src/types/assetTransfer.ts b/src/types/assetTransfer.ts index effdecd..8c5ae33 100644 --- a/src/types/assetTransfer.ts +++ b/src/types/assetTransfer.ts @@ -1,12 +1,76 @@ import { AssetType } from './shared'; -export type AssetTransfer = { - asset?: string; // === 'contractAddress' - burn?: boolean; +export type ETHAsset = { + id: string; + type: AssetType.ETH; + value: string; +}; + +export interface ERC20Asset { + id: string; + asset: string; + type: AssetType.ERC20; + value: string; +} + +export interface ERC721Asset { + asset: string; + id: string; + type: AssetType.ERC721; + tokenId: string; +} + +export interface ERC1155Asset { + asset: string; + id: string; + type: AssetType.ERC1155; + value: string; + tokenId: string; +} + +export type Asset = ETHAsset | ERC20Asset | ERC721Asset | ERC1155Asset; + +export interface NetAssetTransfers { + [address: string]: { + received: Asset[]; + sent: Asset[]; + }; +} + +export type ETHAssetTransfer = { + type: AssetType.ETH; + value: string; from: string; - mint?: boolean; to: string; - tokenId?: string; - value?: string; - type: AssetType; }; + +export interface ERC20AssetTransfer { + asset: string; + type: AssetType.ERC20; + value: string; + from: string; + to: string; +} + +export interface ERC721AssetTransfer { + asset: string; + type: AssetType.ERC721; + tokenId: string; + from: string; + to: string; +} + +export interface ERC1155AssetTransfer { + asset: string; + type: AssetType.ERC1155; + value: string; + tokenId: string; + from: string; + to: string; +} + +export type AssetTransfer = + | ETHAssetTransfer + | ERC20AssetTransfer + | ERC721AssetTransfer + | ERC1155AssetTransfer; diff --git a/src/types/block.ts b/src/types/block.ts index b108353..63fbbd3 100644 --- a/src/types/block.ts +++ b/src/types/block.ts @@ -6,4 +6,6 @@ export type RawBlock = StdObj & { number: number; timestamp: number; transactions: RawTransaction[]; + gasUsed: string; + gasLimit: string; }; diff --git a/src/types/contract.ts b/src/types/contract.ts index e416708..3f0dd18 100644 --- a/src/types/contract.ts +++ b/src/types/contract.ts @@ -1,4 +1,4 @@ -import { StdObj } from './shared'; +import { StdObj, AbiItem } from './shared'; export type Contract = { chainId?: number; @@ -43,7 +43,7 @@ export type ContractMetadata = { simplehash?: StdObj; tally?: TallyMetadata; whatsAbiSelectors: string[]; - // whatsAbiAbi: ethers.InterfaceAbi; + whatsAbiAbi: AbiItem; isProxy: boolean; implementationAddress?: string; tokenMetadata?: TokenMetadata; diff --git a/src/types/log.ts b/src/types/log.ts index 563d3dd..2639949 100644 --- a/src/types/log.ts +++ b/src/types/log.ts @@ -1,10 +1,10 @@ -import { StdObj } from './shared'; +import { StdObj, FragmentType, ParamType } from './shared'; export type LogDescription = { fragment: { name: string; - // type: ethers.FragmentType; - // inputs: ReadonlyArray; + type: FragmentType; + inputs: ReadonlyArray; anonymous: boolean; }; name: string; diff --git a/src/types/shared.ts b/src/types/shared.ts index 7270bd7..4cfd56e 100644 --- a/src/types/shared.ts +++ b/src/types/shared.ts @@ -1,6 +1,14 @@ +import { Contract } from './contract'; +import { AssetTransfer } from './assetTransfer'; + export type StdObj = Record; -export type AssetType = 'erc20' | 'erc721' | 'erc1155' | 'eth'; +export enum AssetType { + ETH = 'eth', + ERC20 = 'erc20', + ERC721 = 'erc721', + ERC1155 = 'erc1155', +} /** ABI */ export type AbiType = @@ -37,3 +45,43 @@ export interface AbiOutput { components?: AbiOutput[]; internalType?: string; } + +export type TransactionContract = { + hash: string; + contracts: Contract[]; +}; + +export type transactionAssetTransfers = { + hash: string; + assetTransfers: AssetTransfer[]; +}; + +export type InternalHashType = { + sigHash: string; + from: string; + to?: string; +}; + +export type TransactionWithHash = { + hash: string; + sigHash: string; + internalSigHashes: InternalHashType[]; +}; + +export type FragmentType = + | 'constructor' + | 'error' + | 'event' + | 'fallback' + | 'function' + | 'struct'; + +export type ParamType = { + name: string; + type: string; + baseType: string; + indexed: null | boolean; + components: null | ReadonlyArray; + arrayLength: null | number; + arrayChildren: null | ParamType; +}; diff --git a/src/types/transaction.ts b/src/types/transaction.ts index 41ca3f5..9f252db 100644 --- a/src/types/transaction.ts +++ b/src/types/transaction.ts @@ -1,4 +1,4 @@ -import { StdObj } from './shared'; +import { StdObj, FragmentType, ParamType } from './shared'; import { AssetTransfer } from './assetTransfer'; import { NetAssetTransfers } from './netAssetTransfer'; import { RawReceipt } from './log'; @@ -59,9 +59,9 @@ export type RawTrace = StdObj & { export type TransactionDescription = { fragment: { name: string; - // type: ethers.FragmentType; - // inputs: ReadonlyArray; - // outputs: ReadonlyArray; + type: FragmentType; + inputs: ReadonlyArray; + outputs: ReadonlyArray; constant: boolean; stateMutability: 'payable' | 'nonpayable' | 'view' | 'pure'; payable: boolean; From 5e2ea88dd323f9d267a9a9f971a0d58db981096f Mon Sep 17 00:00:00 2001 From: ponyjackal Date: Fri, 26 Jan 2024 06:02:31 -0800 Subject: [PATCH 5/9] feat: update common transformations --- src/transformers/_common/contractABI.ts | 5 +- .../_common/contractERC1155Detection.ts | 4 +- .../_common/contractERC20Detection.ts | 4 +- .../_common/contractERC721Detection.ts | 4 +- .../_common/contractERC777Detection.ts | 4 +- .../_common/contractGnosisSafeDetection.ts | 22 +-- .../_common/contractGovernanceDetection.ts | 22 +-- .../_common/contractSelfDestructed.ts | 28 ++-- src/transformers/_common/contractTimestamp.ts | 4 +- .../_common/transactionAssetTransfers.ts | 90 +++++++----- .../_common/transactionContractsCreated.ts | 24 ++- .../_common/transactionDelegateCalls.ts | 6 +- .../transactionDerivativesNeighbors.ts | 21 ++- src/transformers/_common/transactionErrors.ts | 2 +- .../_common/transactionNetAssetTransfers.ts | 82 +++++++---- src/transformers/ethereum/blockEthPrice.ts | 139 ++++++++++++++---- src/types/abi.ts | 24 +++ src/types/{assetTransfer.ts => asset.ts} | 0 src/types/contract.ts | 9 +- src/types/index.ts | 5 +- src/types/neighbor.ts | 7 + src/types/netAssetTransfer.ts | 16 -- src/types/shared.ts | 2 +- src/types/transaction.ts | 3 +- 24 files changed, 354 insertions(+), 173 deletions(-) create mode 100644 src/types/abi.ts rename src/types/{assetTransfer.ts => asset.ts} (100%) create mode 100644 src/types/neighbor.ts delete mode 100644 src/types/netAssetTransfer.ts diff --git a/src/transformers/_common/contractABI.ts b/src/transformers/_common/contractABI.ts index 2ece9c7..0a35065 100644 --- a/src/transformers/_common/contractABI.ts +++ b/src/transformers/_common/contractABI.ts @@ -27,9 +27,8 @@ export function transform(block: RawBlock): TransactionContract[] { isGnosisSafe: false, whatsAbiSelectors: [], isProxy: false, - whatsAbiAbi: { - type: 'constructor', - }, + whatsAbiAbi: [], + tokenMetadata: { tokenStandard: '' }, }; } // Get just the callable selectors diff --git a/src/transformers/_common/contractERC1155Detection.ts b/src/transformers/_common/contractERC1155Detection.ts index a416c8f..ec37837 100644 --- a/src/transformers/_common/contractERC1155Detection.ts +++ b/src/transformers/_common/contractERC1155Detection.ts @@ -1,5 +1,5 @@ -import type { Contract, RawBlock, TransactionContract } from '../types'; -import { bytecodeIsERC1155 } from '../helpers/utils'; +import type { Contract, RawBlock, TransactionContract } from '../../types'; +import { bytecodeIsERC1155 } from '../../helpers/utils'; export function transform(block: RawBlock): TransactionContract[] { const results: { hash: string; contracts: Contract[] }[] = []; diff --git a/src/transformers/_common/contractERC20Detection.ts b/src/transformers/_common/contractERC20Detection.ts index 86a08d8..2c73239 100644 --- a/src/transformers/_common/contractERC20Detection.ts +++ b/src/transformers/_common/contractERC20Detection.ts @@ -1,5 +1,5 @@ -import type { Contract, RawBlock, TransactionContract } from '../types'; -import { bytecodeIsERC20 } from '../helpers/utils'; +import type { Contract, RawBlock, TransactionContract } from '../../types'; +import { bytecodeIsERC20 } from '../../helpers/utils'; export function transform(block: RawBlock): TransactionContract[] { const results: { hash: string; contracts: Contract[] }[] = []; diff --git a/src/transformers/_common/contractERC721Detection.ts b/src/transformers/_common/contractERC721Detection.ts index 6011301..85ae4fa 100644 --- a/src/transformers/_common/contractERC721Detection.ts +++ b/src/transformers/_common/contractERC721Detection.ts @@ -1,5 +1,5 @@ -import type { Contract, RawBlock, TransactionContract } from '../types'; -import { bytecodeIsERC721 } from '../helpers/utils'; +import type { Contract, RawBlock, TransactionContract } from '../../types'; +import { bytecodeIsERC721 } from '../../helpers/utils'; export function transform(block: RawBlock): TransactionContract[] { const results: { hash: string; contracts: Contract[] }[] = []; diff --git a/src/transformers/_common/contractERC777Detection.ts b/src/transformers/_common/contractERC777Detection.ts index dc4ba9b..c6bf320 100644 --- a/src/transformers/_common/contractERC777Detection.ts +++ b/src/transformers/_common/contractERC777Detection.ts @@ -1,5 +1,5 @@ -import type { Contract, RawBlock, TransactionContract } from '../types'; -import { bytecodeIsERC777 } from '../helpers/utils'; +import type { Contract, RawBlock, TransactionContract } from '../../types'; +import { bytecodeIsERC777 } from '../../helpers/utils'; export function transform(block: RawBlock): TransactionContract[] { const results: { hash: string; contracts: Contract[] }[] = []; diff --git a/src/transformers/_common/contractGnosisSafeDetection.ts b/src/transformers/_common/contractGnosisSafeDetection.ts index baebb22..7a328c0 100644 --- a/src/transformers/_common/contractGnosisSafeDetection.ts +++ b/src/transformers/_common/contractGnosisSafeDetection.ts @@ -1,18 +1,20 @@ -import type { RawBlock, Contract, TransactionContract } from '../types'; -import { bytecodeIsGnosisSafe } from '../helpers/utils'; +import type { RawBlock, Contract, TransactionContract } from '../../types'; +import { bytecodeIsGnosisSafe } from '../../helpers/utils'; export function transform(block: RawBlock): TransactionContract[] { const result: TransactionContract[] = block.transactions - .filter((tx) => tx.contracts?.length > 0) + .filter((tx) => tx.contracts && tx.contracts.length > 0) .map((tx) => { - const contracts: Contract[] = tx.contracts.map((txContract) => { - const contract: Contract = { ...txContract }; - if (bytecodeIsGnosisSafe(txContract.bytecode)) { - contract.metadata.isGnosisSafe = true; - } + const contracts: Contract[] = tx.contracts + ? tx.contracts.map((txContract) => { + const contract: Contract = { ...txContract }; + if (bytecodeIsGnosisSafe(txContract.bytecode)) { + contract.metadata.isGnosisSafe = true; + } - return contract; - }); + return contract; + }) + : []; return { hash: tx.hash, contracts }; }); diff --git a/src/transformers/_common/contractGovernanceDetection.ts b/src/transformers/_common/contractGovernanceDetection.ts index 38d1889..d8ed0c0 100644 --- a/src/transformers/_common/contractGovernanceDetection.ts +++ b/src/transformers/_common/contractGovernanceDetection.ts @@ -1,18 +1,20 @@ -import type { RawBlock, Contract, TransactionContract } from '../types'; -import { bytecodeIsIGovernor } from '../helpers/utils'; +import type { RawBlock, Contract, TransactionContract } from '../../types'; +import { bytecodeIsIGovernor } from '../../helpers/utils'; export function transform(block: RawBlock): TransactionContract[] { const result: TransactionContract[] = block.transactions - .filter((tx) => tx.contracts?.length > 0) + .filter((tx) => tx.contracts && tx.contracts.length > 0) .map((tx) => { - const contracts: Contract[] = tx.contracts.map((txContract) => { - const contract: Contract = { ...txContract }; - if (bytecodeIsIGovernor(txContract.bytecode)) { - contract.metadata.isGenericGovernance = true; - } + const contracts: Contract[] = tx.contracts + ? tx.contracts.map((txContract) => { + const contract: Contract = { ...txContract }; + if (bytecodeIsIGovernor(txContract.bytecode)) { + contract.metadata.isGenericGovernance = true; + } - return contract; - }); + return contract; + }) + : []; return { hash: tx.hash, contracts }; }); diff --git a/src/transformers/_common/contractSelfDestructed.ts b/src/transformers/_common/contractSelfDestructed.ts index fd349b8..48e7130 100644 --- a/src/transformers/_common/contractSelfDestructed.ts +++ b/src/transformers/_common/contractSelfDestructed.ts @@ -1,16 +1,22 @@ -import { toBigNumber } from '../helpers/utils'; -import type { RawBlock } from '../types'; +import type { RawBlock, Contract } from '../../types'; -type ContractSelfDestructed = { address: string; refundAddress: string; balance: string }; +type ContractSelfDestructed = { + address: string; + refundAddress: string; + balance: string; +}; + +type ResultType = { + contractsCreated: Contract[]; + contractSelfDestructed: ContractSelfDestructed[]; + hash: string; +}; export function transform(block: RawBlock) { - const results: { - contractSelfDestructed: ContractSelfDestructed[]; - hash: string; - }[] = []; + const results: ResultType[] = []; for (const tx of block.transactions) { - const result = { + const result: ResultType = { contractsCreated: [], contractSelfDestructed: [], hash: tx.hash, @@ -22,8 +28,10 @@ export function transform(block: RawBlock) { if (trace.type === 'suicide' && trace.action) { result.contractSelfDestructed.push({ address: trace.action.address, - balance: toBigNumber(trace.action.balance).toString(), - refundAddress: trace.action.refundAddress, + balance: trace.action.balance + ? BigInt(trace.action.balance).toString() + : '0', + refundAddress: trace.action.refundAddress ?? '', }); } } diff --git a/src/transformers/_common/contractTimestamp.ts b/src/transformers/_common/contractTimestamp.ts index 0320ad2..d3deb96 100644 --- a/src/transformers/_common/contractTimestamp.ts +++ b/src/transformers/_common/contractTimestamp.ts @@ -1,10 +1,12 @@ -import type { RawBlock, TransactionContract } from '../types'; +import type { RawBlock, TransactionContract } from '../../types'; export function transform(block: RawBlock): TransactionContract[] { const isoTimestamp = new Date(block.timestamp * 1000).toISOString(); const result: TransactionContract[] = []; for (const tx of block.transactions) { + if (!tx.contracts) continue; + const contracts = tx.contracts.map((txContract) => { txContract.timestamp = block.timestamp; txContract.isoTimestamp = isoTimestamp; diff --git a/src/transformers/_common/transactionAssetTransfers.ts b/src/transformers/_common/transactionAssetTransfers.ts index 788007e..f1160f2 100644 --- a/src/transformers/_common/transactionAssetTransfers.ts +++ b/src/transformers/_common/transactionAssetTransfers.ts @@ -1,9 +1,12 @@ -import BigNumber from 'bignumber.js'; -import Web3 from 'web3'; - -import { decodeEVMAddress, toBigNumber } from '../helpers/utils'; -import type { AssetTransfer, RawBlock, RawTransaction } from '../types'; +import { decodeEVMAddress } from '../../helpers/utils'; +import { + AssetType, + type AssetTransfer, + type RawBlock, + type RawTransaction, +} from '../../types'; import { KNOWN_ADDRESSES } from '../../helpers/constants'; +import { decodeAbiParameters, Hex } from 'viem'; // 1. pull out token transfers from logs // 2. pull out ETH transfers from traces (this covers tx.value transfers) @@ -17,22 +20,22 @@ const TRANSFER_SIGNATURES = { ERC721: '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', // event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value) - ERC1155_SINGLE: '0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62', + ERC1155_SINGLE: + '0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62', // event TransferBatch(address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values) - ERC1155_BATCH: '0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb', + ERC1155_BATCH: + '0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb', // event Deposit(address indexed dst, uint wad) - WETH_DEPOSIT_ERC20: '0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c', + WETH_DEPOSIT_ERC20: + '0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c', // event Withdrawal(address indexed src, uint wad) - WETH_WITHDRAW_ERC20: '0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65', + WETH_WITHDRAW_ERC20: + '0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65', }; -// @NOTE: we do *not* need access to an RPC here -// we just need an instance of Web3 in order to decode some log params -const web3 = new Web3(); - function getTokenTransfers(tx: RawTransaction) { const txAssetTransfers: AssetTransfer[] = []; @@ -49,29 +52,29 @@ function getTokenTransfers(tx: RawTransaction) { asset: log.address, from: decodeEVMAddress(log.topics[1]), to: decodeEVMAddress(log.topics[2]), - tokenId: toBigNumber(log.topics[3]).toString(), - type: 'erc721', + tokenId: BigInt(log.topics[3]).toString(), + type: AssetType.ERC721, }); } else { txAssetTransfers.push({ asset: log.address, from: decodeEVMAddress(log.topics[1]), to: decodeEVMAddress(log.topics[2]), - value: toBigNumber(log.data).toString(), - type: 'erc20', + value: BigInt(log.data).toString(), + type: AssetType.ERC20, }); } continue; } case TRANSFER_SIGNATURES.ERC1155_SINGLE: { - const { tokenId, value } = web3.eth.abi.decodeParameters( + const [tokenId, value] = decodeAbiParameters( [ { name: 'tokenId', type: 'uint256' }, { name: 'value', type: 'uint256' }, ], - log.data - ) as { tokenId: BigNumber; value: BigNumber }; + log.data as Hex, + ); txAssetTransfers.push({ asset: log.address, @@ -79,19 +82,19 @@ function getTokenTransfers(tx: RawTransaction) { to: decodeEVMAddress(log.topics[3]), tokenId: tokenId.toString(), value: value.toString(), - type: 'erc1155', + type: AssetType.ERC1155, }); continue; } case TRANSFER_SIGNATURES.ERC1155_BATCH: { - const { tokenIds, values } = web3.eth.abi.decodeParameters( + const [tokenIds, values] = decodeAbiParameters( [ { name: 'tokenIds', type: 'uint256[]' }, { name: 'values', type: 'uint256[]' }, ], - log.data - ) as { tokenIds: BigNumber[]; values: BigNumber[] }; + log.data as Hex, + ); for (let tokenIdx = 0; tokenIdx < tokenIds.length; tokenIdx += 1) { txAssetTransfers.push({ @@ -100,7 +103,7 @@ function getTokenTransfers(tx: RawTransaction) { to: decodeEVMAddress(log.topics[3]), tokenId: tokenIds[tokenIdx].toString(), value: values[tokenIdx].toString(), - type: 'erc1155', + type: AssetType.ERC1155, }); } continue; @@ -115,8 +118,8 @@ function getTokenTransfers(tx: RawTransaction) { asset: log.address, from: KNOWN_ADDRESSES.NULL, to: decodeEVMAddress(log.topics[1]), - value: toBigNumber(log.data).toString(), - type: 'erc20', + value: BigInt(log.data).toString(), + type: AssetType.ERC20, }); continue; } @@ -130,8 +133,8 @@ function getTokenTransfers(tx: RawTransaction) { asset: log.address, from: decodeEVMAddress(log.topics[1]), to: KNOWN_ADDRESSES.NULL, - value: toBigNumber(log.data).toString(), - type: 'erc20', + value: BigInt(log.data).toString(), + type: AssetType.ERC20, }); continue; } @@ -159,10 +162,12 @@ export function transform(block: RawBlock) { // then group by contract const tokenTransfersByContract: Record = {}; for (const transfer of tokenTransfers) { - if (!tokenTransfersByContract[transfer.asset]) { - tokenTransfersByContract[transfer.asset] = []; + if (transfer.type !== AssetType.ETH) { + if (!tokenTransfersByContract[transfer.asset]) { + tokenTransfersByContract[transfer.asset] = []; + } + tokenTransfersByContract[transfer.asset].push(transfer); } - tokenTransfersByContract[transfer.asset].push(transfer); } // now prepare a final set of *all* asset transfers (including ETH) @@ -173,21 +178,28 @@ export function transform(block: RawBlock) { // check for ETH transfers if (trace.action.callType !== 'delegatecall') { // track contract suicides - if (trace.type === 'suicide' && trace.action.balance && trace.action.balance !== '0x0') { + if ( + trace.type === 'suicide' && + trace.action.balance && + trace.action.balance !== '0x0' + ) { assetTransfers.push({ from: trace.action.address, - to: trace.action.refundAddress, - type: 'eth', - value: toBigNumber(trace.action.balance).toString(), + to: trace.action.refundAddress ?? '', + type: AssetType.ETH, + value: BigInt(trace.action.balance).toString(), }); } // otherwise track ETH transfers else if (trace.action.value && trace.action.value !== '0x0') { assetTransfers.push({ from: trace.action.from, - to: trace.type === 'create' ? trace.result.address : trace.action.to, - type: 'eth', - value: toBigNumber(trace.action.value).toString(), + to: + trace.type === 'create' + ? trace.result.address ?? '' + : trace.action.to ?? '', + type: AssetType.ETH, + value: BigInt(trace.action.value).toString(), }); } } diff --git a/src/transformers/_common/transactionContractsCreated.ts b/src/transformers/_common/transactionContractsCreated.ts index 8d13ceb..f8f8b9c 100644 --- a/src/transformers/_common/transactionContractsCreated.ts +++ b/src/transformers/_common/transactionContractsCreated.ts @@ -1,14 +1,15 @@ import { keccak256 } from 'web3-utils'; -import type { RawBlock, Contract } from '../types'; +import type { RawBlock, Contract } from '../../types'; +type ResultType = { + contracts: Contract[]; + hash: string; +}; export function transform(block: RawBlock) { - const results: { - contracts: Contract[]; - hash: string; - }[] = []; + const results: ResultType[] = []; for (const tx of block.transactions) { - const result = { + const result: ResultType = { contracts: [], hash: tx.hash, }; @@ -16,16 +17,23 @@ export function transform(block: RawBlock) { for (let i = 0; i < tx.traces.length; i += 1) { const trace = tx.traces[i]; - if ((trace.type === 'create' || trace.type == 'create2') && trace.result) { + if ( + (trace.type === 'create' || trace.type == 'create2') && + trace.result + ) { // Basic Create Contract Details const isoTimestamp = new Date(block.timestamp * 1000).toISOString(); + if (!trace.result.address) { + continue; + } const contract: Contract = { deployer: tx.from, directDeployer: trace.action.from, address: trace.result.address, bytecode: trace.result.code, - fingerprint: trace.result.code !== '0x0' ? keccak256(trace.result.code) : '', // TODO - need a way to avoid validation errors + fingerprint: + trace.result.code !== '0x0' ? keccak256(trace.result.code) : '', // TODO - need a way to avoid validation errors gas: trace.action.gas, // TOOD - do we convert with bignumber here? gasUsed: trace.result.gasUsed, // TODO - do we convert with bignumber here? blockNumber: block.number, diff --git a/src/transformers/_common/transactionDelegateCalls.ts b/src/transformers/_common/transactionDelegateCalls.ts index 1dd4e35..84e99f6 100644 --- a/src/transformers/_common/transactionDelegateCalls.ts +++ b/src/transformers/_common/transactionDelegateCalls.ts @@ -1,10 +1,12 @@ -import type { RawBlock, RawTrace } from '../types'; +import type { RawBlock, RawTrace } from '../../types'; export function transform(block: RawBlock) { const results: { hash: string; delegateCalls: RawTrace[] }[] = []; for (const tx of block.transactions) { - const delegateCalls = tx.traces.filter((t) => t.action.callType === 'delegatecall'); + const delegateCalls = tx.traces.filter( + (t) => t.action.callType === 'delegatecall', + ); if (delegateCalls.length > 0) { results.push({ hash: tx.hash, diff --git a/src/transformers/_common/transactionDerivativesNeighbors.ts b/src/transformers/_common/transactionDerivativesNeighbors.ts index f53cf6a..3d9dc06 100644 --- a/src/transformers/_common/transactionDerivativesNeighbors.ts +++ b/src/transformers/_common/transactionDerivativesNeighbors.ts @@ -1,4 +1,4 @@ -import type { RawBlock, Neighbor } from '../types'; +import type { RawBlock, Neighbor } from '../../types'; export function transform(block: RawBlock): Neighbor[] { const result: Neighbor[] = []; @@ -6,13 +6,24 @@ export function transform(block: RawBlock): Neighbor[] { const tx = block.transactions[i]; if (tx.assetTransfers) { const fromAddresses: Set = new Set( - (tx.assetTransfers as { from: string }[]).map((assetTransfer) => assetTransfer.from) + (tx.assetTransfers as { from: string }[]).map( + (assetTransfer) => assetTransfer.from, + ), ); const toAddresses: Set = new Set( - (tx.assetTransfers as { to: string }[]).map((assetTransfer) => assetTransfer.to) + (tx.assetTransfers as { to: string }[]).map( + (assetTransfer) => assetTransfer.to, + ), ); - if (fromAddresses.size === 1 && fromAddresses.has(tx.from) && toAddresses.size === 1) { - result.push({ hash: tx.hash, neighbor: { address: tx.from, neighbor: [...toAddresses][0] } }); + if ( + fromAddresses.size === 1 && + fromAddresses.has(tx.from) && + toAddresses.size === 1 + ) { + result.push({ + hash: tx.hash, + neighbor: { address: tx.from, neighbor: [...toAddresses][0] }, + }); } } } diff --git a/src/transformers/_common/transactionErrors.ts b/src/transformers/_common/transactionErrors.ts index 93b9791..2f7fcd0 100644 --- a/src/transformers/_common/transactionErrors.ts +++ b/src/transformers/_common/transactionErrors.ts @@ -1,4 +1,4 @@ -import type { RawBlock } from '../types'; +import type { RawBlock } from '../../types'; export function transform(block: RawBlock) { const allTxErrors: { hash: string; errors: string[] }[] = []; diff --git a/src/transformers/_common/transactionNetAssetTransfers.ts b/src/transformers/_common/transactionNetAssetTransfers.ts index fc44ff7..1a1d531 100644 --- a/src/transformers/_common/transactionNetAssetTransfers.ts +++ b/src/transformers/_common/transactionNetAssetTransfers.ts @@ -1,7 +1,11 @@ -import type { - RawBlock, - NetAssetTransfer, - NetAssetTransfers, +import { + type RawBlock, + type NetAssetTransfers, + type Asset, + AssetType, + ERC1155Asset, + ERC20Asset, + ETHAsset, } from '../../types'; export function transform(block: RawBlock) { @@ -13,7 +17,7 @@ export function transform(block: RawBlock) { continue; } - const assetsById: Record = {}; + const assetsById: Record = {}; const netAssetsByAddress: Record> = {}; for (const txfer of assetTransfers) { @@ -21,7 +25,8 @@ export function transform(block: RawBlock) { continue; } - let asset: NetAssetTransfer; + let asset: Asset | undefined = undefined; + let assetValue = BigInt(0); switch (txfer.type) { case 'erc721': asset = { @@ -29,8 +34,8 @@ export function transform(block: RawBlock) { id: `${txfer.asset}-${txfer.tokenId}`, tokenId: txfer.tokenId, type: txfer.type, - value: '1', }; + assetValue = BigInt(1); break; case 'erc1155': asset = { @@ -40,6 +45,7 @@ export function transform(block: RawBlock) { type: txfer.type, value: txfer.value, }; + assetValue = BigInt(txfer.value); break; case 'erc20': asset = { @@ -48,18 +54,19 @@ export function transform(block: RawBlock) { type: txfer.type, value: txfer.value, }; + assetValue = BigInt(txfer.value); break; case 'eth': asset = { - asset: 'eth', id: 'eth', type: txfer.type, value: txfer.value, }; + assetValue = BigInt(txfer.value); break; } - if (!asset.id || !asset.value || asset.value === '0') { + if (!asset?.id) { continue; } @@ -70,40 +77,63 @@ export function transform(block: RawBlock) { netAssetsByAddress[txfer.to] = {}; } if (!netAssetsByAddress[txfer.from][asset.id]) { - netAssetsByAddress[txfer.from][asset.id] = toBigNumber(0); + netAssetsByAddress[txfer.from][asset.id] = BigInt(0); } if (!netAssetsByAddress[txfer.to][asset.id]) { - netAssetsByAddress[txfer.to][asset.id] = toBigNumber(0); + netAssetsByAddress[txfer.to][asset.id] = BigInt(0); } assetsById[asset.id] = asset; - netAssetsByAddress[txfer.from][asset.id] = netAssetsByAddress[txfer.from][ - asset.id - ].minus(asset.value); - netAssetsByAddress[txfer.to][asset.id] = netAssetsByAddress[txfer.to][ - asset.id - ].plus(asset.value); + netAssetsByAddress[txfer.from][asset.id] = + netAssetsByAddress[txfer.from][asset.id] - BigInt(assetValue); + netAssetsByAddress[txfer.to][asset.id] = + netAssetsByAddress[txfer.to][asset.id] + BigInt(assetValue); } const netAssetTransfers: NetAssetTransfers = {}; for (const [address, assets] of Object.entries(netAssetsByAddress)) { for (const [id, value] of Object.entries(assets)) { - if (value.eq(0)) { - continue; - } if (!netAssetTransfers[address]) { netAssetTransfers[address] = { received: [], sent: [] }; } - if (value.lt(0)) { + + const type = assetsById[id].type; + if (type === AssetType.ERC721) { netAssetTransfers[address].sent.push({ ...assetsById[id], - value: value.multipliedBy(-1).toString(), }); } else { - netAssetTransfers[address].received.push({ - ...assetsById[id], - value: value.toString(), - }); + if (value === BigInt(0)) { + continue; + } + + let asset: Asset | undefined = undefined; + switch (assetsById[id].type) { + case AssetType.ERC1155: + asset = assetsById[id] as ERC1155Asset; + asset.value = + value > BigInt(0) + ? value.toString() + : (value * BigInt(-1)).toString(); + netAssetTransfers[address].received.push(asset); + break; + case AssetType.ERC20: + asset = assetsById[id] as ERC20Asset; + asset.value = + value > BigInt(0) + ? value.toString() + : (value * BigInt(-1)).toString(); + netAssetTransfers[address].received.push(asset); + break; + case AssetType.ETH: + asset = assetsById[id] as ETHAsset; + asset.value = + value > BigInt(0) + ? value.toString() + : (value * BigInt(-1)).toString(); + netAssetTransfers[address].received.push(asset); + break; + } } } } diff --git a/src/transformers/ethereum/blockEthPrice.ts b/src/transformers/ethereum/blockEthPrice.ts index f43a303..de93374 100644 --- a/src/transformers/ethereum/blockEthPrice.ts +++ b/src/transformers/ethereum/blockEthPrice.ts @@ -33,15 +33,26 @@ const uniSwapV3ETHPools = new Set([ ]); export function transform(block: RawBlock) { - const result: { number: number; price?: number; priceSource?: 'ETHERSCAN' | 'UNISWAP' } = { number: block.number }; + const result: { + number: number; + price?: number; + priceSource?: 'ETHERSCAN' | 'UNISWAP'; + } = { number: block.number }; const date = new Date(block.timestamp * 1000); const swaps: { price: BigNumber; volume: BigNumber }[] = []; // if we're pre UniSwap usage (~ February 2019), then use Etherscan prices if (block.number < 7207017) { // only track the price for the block right at midnight - if (date.getUTCHours() === 0 && date.getUTCMinutes() === 0 && date.getUTCSeconds() < 30) { - result.price = etherscanPriceByDay[`${date.getUTCFullYear()}-${date.getUTCMonth() + 1}-${date.getUTCDate()}`]; + if ( + date.getUTCHours() === 0 && + date.getUTCMinutes() === 0 && + date.getUTCSeconds() < 30 + ) { + result.price = + etherscanPriceByDay[ + `${date.getUTCFullYear()}-${date.getUTCMonth() + 1}-${date.getUTCDate()}` + ]; result.priceSource = 'ETHERSCAN'; } } @@ -52,7 +63,8 @@ export function transform(block: RawBlock) { for (const log of tx.receipt.logs) { if ( log.address === uniSwapV1USDC && - log.topics[0] === '0x06239653922ac7bea6aa2b19dc486b9361821d37712eb796adfd38d81de278ca' + log.topics[0] === + '0x06239653922ac7bea6aa2b19dc486b9361821d37712eb796adfd38d81de278ca' ) { const usd = toBigNumber(log.topics[3]).div(USD_DECIMALS); if (usd.gte(MIN_USD_AMOUNT_TO_CONSIDER)) { @@ -73,7 +85,8 @@ export function transform(block: RawBlock) { // check V2 swap logs if ( uniSwapV2ETHPools.has(log.address) && - log.topics[0] === '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822' && + log.topics[0] === + '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822' && log.topics.length === 3 ) { const params = decodeEvent( @@ -81,19 +94,49 @@ export function transform(block: RawBlock) { { anonymous: false, inputs: [ - { indexed: true, internalType: 'address', name: 'sender', type: 'address' }, - { indexed: false, internalType: 'uint256', name: 'amount0In', type: 'uint256' }, - { indexed: false, internalType: 'uint256', name: 'amount1In', type: 'uint256' }, - { indexed: false, internalType: 'uint256', name: 'amount0Out', type: 'uint256' }, - { indexed: false, internalType: 'uint256', name: 'amount1Out', type: 'uint256' }, - { indexed: true, internalType: 'address', name: 'to', type: 'address' }, + { + indexed: true, + internalType: 'address', + name: 'sender', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'amount0In', + type: 'uint256', + }, + { + indexed: false, + internalType: 'uint256', + name: 'amount1In', + type: 'uint256', + }, + { + indexed: false, + internalType: 'uint256', + name: 'amount0Out', + type: 'uint256', + }, + { + indexed: false, + internalType: 'uint256', + name: 'amount1Out', + type: 'uint256', + }, + { + indexed: true, + internalType: 'address', + name: 'to', + type: 'address', + }, ], name: 'Swap', type: 'event', }, ], log.topics, - log.data + log.data, ); // first 4 data params are possible amounts, only 2 are used @@ -103,7 +146,8 @@ export function transform(block: RawBlock) { // and check V3 swap logs else if ( uniSwapV3ETHPools.has(log.address) && - log.topics[0] === '0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67' && + log.topics[0] === + '0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67' && log.topics.length === 3 ) { const params = decodeEvent( @@ -111,20 +155,55 @@ export function transform(block: RawBlock) { { anonymous: false, inputs: [ - { indexed: true, internalType: 'address', name: 'sender', type: 'address' }, - { indexed: true, internalType: 'address', name: 'recipient', type: 'address' }, - { indexed: false, internalType: 'int256', name: 'amount0', type: 'int256' }, - { indexed: false, internalType: 'int256', name: 'amount1', type: 'int256' }, - { indexed: false, internalType: 'uint160', name: 'sqrtPriceX96', type: 'uint160' }, - { indexed: false, internalType: 'uint128', name: 'liquidity', type: 'uint128' }, - { indexed: false, internalType: 'int24', name: 'tick', type: 'int24' }, + { + indexed: true, + internalType: 'address', + name: 'sender', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'recipient', + type: 'address', + }, + { + indexed: false, + internalType: 'int256', + name: 'amount0', + type: 'int256', + }, + { + indexed: false, + internalType: 'int256', + name: 'amount1', + type: 'int256', + }, + { + indexed: false, + internalType: 'uint160', + name: 'sqrtPriceX96', + type: 'uint160', + }, + { + indexed: false, + internalType: 'uint128', + name: 'liquidity', + type: 'uint128', + }, + { + indexed: false, + internalType: 'int24', + name: 'tick', + type: 'int24', + }, ], name: 'Swap', type: 'event', }, ], log.topics, - log.data + log.data, ); // first 2 data params are possible amounts, one is always negative @@ -133,13 +212,18 @@ export function transform(block: RawBlock) { if (amounts.length >= 2) { // because ETH has 3x the decimals, it will always be the larger number prior to normalizing - let [usd, eth] = amounts.filter((a) => a.gt(0)).sort((a, b) => (a.gt(b) ? 1 : -1)); + let [usd, eth] = amounts + .filter((a) => a.gt(0)) + .sort((a, b) => (a.gt(b) ? 1 : -1)); if (!usd || !eth) { continue; } usd = usd.div(USD_DECIMALS); - if (usd.gte(MIN_USD_AMOUNT_TO_CONSIDER) && usd.lte(MAX_USD_AMOUNT_TO_CONSIDER)) { + if ( + usd.gte(MIN_USD_AMOUNT_TO_CONSIDER) && + usd.lte(MAX_USD_AMOUNT_TO_CONSIDER) + ) { eth = eth.div(ETH_DECIMALS); swaps.push({ price: usd.dividedBy(eth), volume: usd }); } @@ -150,8 +234,13 @@ export function transform(block: RawBlock) { // compute a quick Volume Weight Average Price (VWAP) for the block if (swaps.length) { - const totalVolume = swaps.reduce((a, b) => a.plus(b.volume), toBigNumber(0)); - const price = swaps.reduce((a, b) => a.plus(b.price.multipliedBy(b.volume)), toBigNumber(0)).div(totalVolume); + const totalVolume = swaps.reduce( + (a, b) => a.plus(b.volume), + toBigNumber(0), + ); + const price = swaps + .reduce((a, b) => a.plus(b.price.multipliedBy(b.volume)), toBigNumber(0)) + .div(totalVolume); result.price = price.decimalPlaces(2).toNumber(); result.priceSource = 'UNISWAP'; } diff --git a/src/types/abi.ts b/src/types/abi.ts new file mode 100644 index 0000000..4bad9f9 --- /dev/null +++ b/src/types/abi.ts @@ -0,0 +1,24 @@ +export type StateMutability = 'nonpayable' | 'payable' | 'view' | 'pure'; + +export type ABIFunction = { + type: 'function'; // TODO: constructor, receive, fallback + selector: string; + name?: string; + outputs?: { type: string; length?: number; name: string }[]; + inputs?: { type: string; name: string }[]; + sig?: string; + sigAlts?: string[]; + payable?: boolean; + stateMutability?: StateMutability; +}; + +export type ABIEvent = { + type: 'event'; + hash: string; + name?: string; + sig?: string; + sigAlts?: string[]; + // TODO: ... +}; + +export type ABI = (ABIFunction | ABIEvent)[]; diff --git a/src/types/assetTransfer.ts b/src/types/asset.ts similarity index 100% rename from src/types/assetTransfer.ts rename to src/types/asset.ts diff --git a/src/types/contract.ts b/src/types/contract.ts index 3f0dd18..18a75b0 100644 --- a/src/types/contract.ts +++ b/src/types/contract.ts @@ -1,4 +1,5 @@ -import { StdObj, AbiItem } from './shared'; +import { StdObj } from './shared'; +import { ABI } from './abi'; export type Contract = { chainId?: number; @@ -12,7 +13,7 @@ export type Contract = { blockNumber: number; transactionHash: string; type: 'create' | 'create2'; - metadata?: ContractMetadata; + metadata: ContractMetadata; supportedInterfaces?: SupportedInterfaces; sigHash: string; internalSigHashes: string[]; @@ -43,10 +44,10 @@ export type ContractMetadata = { simplehash?: StdObj; tally?: TallyMetadata; whatsAbiSelectors: string[]; - whatsAbiAbi: AbiItem; + whatsAbiAbi: ABI; isProxy: boolean; implementationAddress?: string; - tokenMetadata?: TokenMetadata; + tokenMetadata: TokenMetadata; }; export type SupportedInterfaces = Record; diff --git a/src/types/index.ts b/src/types/index.ts index 5b2df5b..a6a26bf 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,7 +1,8 @@ -export * from './assetTransfer'; +export * from './asset'; export * from './block'; export * from './contract'; export * from './log'; -export * from './netAssetTransfer'; export * from './shared'; export * from './transaction'; +export * from './neighbor'; +export * from './abi'; diff --git a/src/types/neighbor.ts b/src/types/neighbor.ts new file mode 100644 index 0000000..bde2bdf --- /dev/null +++ b/src/types/neighbor.ts @@ -0,0 +1,7 @@ +export type Neighbor = { + hash: string; + neighbor: { + address: string; + neighbor: string; + }; +}; diff --git a/src/types/netAssetTransfer.ts b/src/types/netAssetTransfer.ts deleted file mode 100644 index 9a434af..0000000 --- a/src/types/netAssetTransfer.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { AssetType } from './shared'; - -export type NetAssetTransfer = { - asset: string; - from?: string; - to?: string; - id: string; - tokenId?: string; - type: AssetType; - value: string; -}; - -export type NetAssetTransfers = Record< - string, - { received: NetAssetTransfer[]; sent: NetAssetTransfer[] } ->; diff --git a/src/types/shared.ts b/src/types/shared.ts index 4cfd56e..cd2b3d2 100644 --- a/src/types/shared.ts +++ b/src/types/shared.ts @@ -1,5 +1,5 @@ import { Contract } from './contract'; -import { AssetTransfer } from './assetTransfer'; +import { AssetTransfer } from './asset'; export type StdObj = Record; diff --git a/src/types/transaction.ts b/src/types/transaction.ts index 9f252db..6f18298 100644 --- a/src/types/transaction.ts +++ b/src/types/transaction.ts @@ -1,6 +1,5 @@ import { StdObj, FragmentType, ParamType } from './shared'; -import { AssetTransfer } from './assetTransfer'; -import { NetAssetTransfers } from './netAssetTransfer'; +import { AssetTransfer, NetAssetTransfers } from './asset'; import { RawReceipt } from './log'; import { Contract } from './contract'; From fa0683bdc6c3c2941ed64a8ff59034eca11ae776 Mon Sep 17 00:00:00 2001 From: ponyjackal Date: Fri, 26 Jan 2024 08:40:28 -0800 Subject: [PATCH 6/9] feat: update ethereum transformations --- src/helpers/constants.ts | 53 +++- src/transformers/_common/blockGasUsage.ts | 11 - src/transformers/_common/contractABI.ts | 55 ---- .../_common/contractERC1155Detection.ts | 23 -- .../_common/contractERC20Detection.ts | 23 -- .../_common/contractERC721Detection.ts | 23 -- .../_common/contractERC777Detection.ts | 23 -- .../_common/contractGnosisSafeDetection.ts | 23 -- .../_common/contractGovernanceDetection.ts | 23 -- .../_common/contractSelfDestructed.ts | 45 ---- src/transformers/_common/contractTimestamp.ts | 21 -- .../_common/transactionProxyUpgrades.ts | 44 --- src/transformers/ethereum/blockEthPrice.ts | 253 ------------------ src/transformers/ethereum/blockFork.ts | 27 -- .../ethereum/contractPropHouseDetection.ts | 82 ------ .../ethereum/contractUniswapDetection.ts | 112 -------- .../transactionAssetTransfersOldNFTs.ts | 106 +++++--- src/transformers/ethereum/transactionFees.ts | 21 +- src/transformers/ethereum/transactionForks.ts | 6 +- src/types/block.ts | 1 + src/types/contract.ts | 8 + src/types/log.ts | 7 + 22 files changed, 142 insertions(+), 848 deletions(-) delete mode 100644 src/transformers/_common/blockGasUsage.ts delete mode 100644 src/transformers/_common/contractABI.ts delete mode 100644 src/transformers/_common/contractERC1155Detection.ts delete mode 100644 src/transformers/_common/contractERC20Detection.ts delete mode 100644 src/transformers/_common/contractERC721Detection.ts delete mode 100644 src/transformers/_common/contractERC777Detection.ts delete mode 100644 src/transformers/_common/contractGnosisSafeDetection.ts delete mode 100644 src/transformers/_common/contractGovernanceDetection.ts delete mode 100644 src/transformers/_common/contractSelfDestructed.ts delete mode 100644 src/transformers/_common/contractTimestamp.ts delete mode 100644 src/transformers/_common/transactionProxyUpgrades.ts delete mode 100644 src/transformers/ethereum/blockEthPrice.ts delete mode 100644 src/transformers/ethereum/blockFork.ts delete mode 100644 src/transformers/ethereum/contractPropHouseDetection.ts delete mode 100644 src/transformers/ethereum/contractUniswapDetection.ts diff --git a/src/helpers/constants.ts b/src/helpers/constants.ts index 7b28f81..43f056b 100644 --- a/src/helpers/constants.ts +++ b/src/helpers/constants.ts @@ -416,10 +416,55 @@ export const OLD_NFT_ADDRESSES = [ '0x323a3e1693e7a0959f65972f3bf2dfcb93239dfe', // Digital Art Chain '0x552d72f86f04098a4eaeda6d7b665ac12f846ad2', // Dark Winds ]; -export const ERC721_TRANSFER_EVENT_1 = - 'event Transfer(address indexed,address indexed,uint256)'; -export const ERC721_TRANSFER_EVENT_2 = - 'event Transfer(address,address,uint256)'; +export const ERC721_TRANSFER_EVENT_1 = [ + { + anonymous: false, + inputs: [ + { + indexed: true, + name: 'from', + type: 'address', + }, + { + indexed: true, + name: 'to', + type: 'address', + }, + { + indexed: false, + name: 'value', + type: 'uint256', + }, + ], + name: 'Transfer', + type: 'event', + }, +] as const; + +export const ERC721_TRANSFER_EVENT_2 = [ + { + anonymous: false, + inputs: [ + { + indexed: false, + name: 'from', + type: 'address', + }, + { + indexed: false, + name: 'to', + type: 'address', + }, + { + indexed: false, + name: 'value', + type: 'uint256', + }, + ], + name: 'Transfer', + type: 'event', + }, +] as const; export const PROXY_IMPLEMENTATION_METHOD_SIGNATURES = [ 'implementation()', diff --git a/src/transformers/_common/blockGasUsage.ts b/src/transformers/_common/blockGasUsage.ts deleted file mode 100644 index 5fe0406..0000000 --- a/src/transformers/_common/blockGasUsage.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { RawBlock } from '../../types'; - -export function transform(block: RawBlock) { - const gasUsedPercentage = - (BigInt(block.gasUsed) * BigInt(100)) / BigInt(block.gasLimit); - - return { - number: block.number, - gasUsedPercentage: gasUsedPercentage.toString(), - }; -} diff --git a/src/transformers/_common/contractABI.ts b/src/transformers/_common/contractABI.ts deleted file mode 100644 index 0a35065..0000000 --- a/src/transformers/_common/contractABI.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { whatsabi } from '@shazow/whatsabi'; -import type { Contract, RawBlock, TransactionContract } from '../../types'; - -export function transform(block: RawBlock): TransactionContract[] { - const results: { hash: string; contracts: Contract[] }[] = []; - - for (const tx of block.transactions) { - if (!tx.contracts) { - continue; - } - - const contracts = tx.contracts - .map((txContract) => { - try { - if (!txContract.metadata) { - txContract.metadata = { - isUniswapV3: false, - isUniswapV2: false, - isUniswapV1: false, - uniswapPairs: [], - isPropHouseToken: false, - isPropHouseMetadata: false, - isPropHouseAuction: false, - isPropHouseTreasury: false, - isPropHouseGovernor: false, - isGenericGovernance: false, - isGnosisSafe: false, - whatsAbiSelectors: [], - isProxy: false, - whatsAbiAbi: [], - tokenMetadata: { tokenStandard: '' }, - }; - } - // Get just the callable selectors - txContract.metadata.whatsAbiSelectors = - whatsabi.selectorsFromBytecode(txContract.bytecode); - // Get an ABI-like list of interfaces - txContract.metadata.whatsAbiAbi = whatsabi.abiFromBytecode( - txContract.bytecode, - ); - - return txContract; - } catch (e) { - return txContract; - } - }) - .filter((v) => v); - - if (contracts.length) { - results.push({ hash: tx.hash, contracts }); - } - } - - return results; -} diff --git a/src/transformers/_common/contractERC1155Detection.ts b/src/transformers/_common/contractERC1155Detection.ts deleted file mode 100644 index ec37837..0000000 --- a/src/transformers/_common/contractERC1155Detection.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { Contract, RawBlock, TransactionContract } from '../../types'; -import { bytecodeIsERC1155 } from '../../helpers/utils'; - -export function transform(block: RawBlock): TransactionContract[] { - const results: { hash: string; contracts: Contract[] }[] = []; - - for (const tx of block.transactions) { - if (!tx.contracts) { - continue; - } - - const contracts = tx.contracts.map((txContract) => { - if (bytecodeIsERC1155(txContract.bytecode)) { - txContract.metadata.tokenMetadata.tokenStandard = 'erc1155'; - } - return txContract; - }); - - results.push({ hash: tx.hash, contracts }); - } - - return results; -} diff --git a/src/transformers/_common/contractERC20Detection.ts b/src/transformers/_common/contractERC20Detection.ts deleted file mode 100644 index 2c73239..0000000 --- a/src/transformers/_common/contractERC20Detection.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { Contract, RawBlock, TransactionContract } from '../../types'; -import { bytecodeIsERC20 } from '../../helpers/utils'; - -export function transform(block: RawBlock): TransactionContract[] { - const results: { hash: string; contracts: Contract[] }[] = []; - - for (const tx of block.transactions) { - if (!tx.contracts) { - continue; - } - - const contracts = tx.contracts.map((txContract) => { - if (bytecodeIsERC20(txContract.bytecode)) { - txContract.metadata.tokenMetadata.tokenStandard = 'erc20'; - } - return txContract; - }); - - results.push({ hash: tx.hash, contracts }); - } - - return results; -} diff --git a/src/transformers/_common/contractERC721Detection.ts b/src/transformers/_common/contractERC721Detection.ts deleted file mode 100644 index 85ae4fa..0000000 --- a/src/transformers/_common/contractERC721Detection.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { Contract, RawBlock, TransactionContract } from '../../types'; -import { bytecodeIsERC721 } from '../../helpers/utils'; - -export function transform(block: RawBlock): TransactionContract[] { - const results: { hash: string; contracts: Contract[] }[] = []; - - for (const tx of block.transactions) { - if (!tx.contracts) { - continue; - } - - const contracts = tx.contracts.map((txContract) => { - if (bytecodeIsERC721(txContract.bytecode)) { - txContract.metadata.tokenMetadata.tokenStandard = 'erc721'; - } - return txContract; - }); - - results.push({ hash: tx.hash, contracts }); - } - - return results; -} diff --git a/src/transformers/_common/contractERC777Detection.ts b/src/transformers/_common/contractERC777Detection.ts deleted file mode 100644 index c6bf320..0000000 --- a/src/transformers/_common/contractERC777Detection.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { Contract, RawBlock, TransactionContract } from '../../types'; -import { bytecodeIsERC777 } from '../../helpers/utils'; - -export function transform(block: RawBlock): TransactionContract[] { - const results: { hash: string; contracts: Contract[] }[] = []; - - for (const tx of block.transactions) { - if (!tx.contracts) { - continue; - } - - const contracts = tx.contracts.map((txContract) => { - if (bytecodeIsERC777(txContract.bytecode)) { - txContract.metadata.tokenMetadata.tokenStandard = 'erc777'; - } - return txContract; - }); - - results.push({ hash: tx.hash, contracts }); - } - - return results; -} diff --git a/src/transformers/_common/contractGnosisSafeDetection.ts b/src/transformers/_common/contractGnosisSafeDetection.ts deleted file mode 100644 index 7a328c0..0000000 --- a/src/transformers/_common/contractGnosisSafeDetection.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { RawBlock, Contract, TransactionContract } from '../../types'; -import { bytecodeIsGnosisSafe } from '../../helpers/utils'; - -export function transform(block: RawBlock): TransactionContract[] { - const result: TransactionContract[] = block.transactions - .filter((tx) => tx.contracts && tx.contracts.length > 0) - .map((tx) => { - const contracts: Contract[] = tx.contracts - ? tx.contracts.map((txContract) => { - const contract: Contract = { ...txContract }; - if (bytecodeIsGnosisSafe(txContract.bytecode)) { - contract.metadata.isGnosisSafe = true; - } - - return contract; - }) - : []; - - return { hash: tx.hash, contracts }; - }); - - return result; -} diff --git a/src/transformers/_common/contractGovernanceDetection.ts b/src/transformers/_common/contractGovernanceDetection.ts deleted file mode 100644 index d8ed0c0..0000000 --- a/src/transformers/_common/contractGovernanceDetection.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { RawBlock, Contract, TransactionContract } from '../../types'; -import { bytecodeIsIGovernor } from '../../helpers/utils'; - -export function transform(block: RawBlock): TransactionContract[] { - const result: TransactionContract[] = block.transactions - .filter((tx) => tx.contracts && tx.contracts.length > 0) - .map((tx) => { - const contracts: Contract[] = tx.contracts - ? tx.contracts.map((txContract) => { - const contract: Contract = { ...txContract }; - if (bytecodeIsIGovernor(txContract.bytecode)) { - contract.metadata.isGenericGovernance = true; - } - - return contract; - }) - : []; - - return { hash: tx.hash, contracts }; - }); - - return result; -} diff --git a/src/transformers/_common/contractSelfDestructed.ts b/src/transformers/_common/contractSelfDestructed.ts deleted file mode 100644 index 48e7130..0000000 --- a/src/transformers/_common/contractSelfDestructed.ts +++ /dev/null @@ -1,45 +0,0 @@ -import type { RawBlock, Contract } from '../../types'; - -type ContractSelfDestructed = { - address: string; - refundAddress: string; - balance: string; -}; - -type ResultType = { - contractsCreated: Contract[]; - contractSelfDestructed: ContractSelfDestructed[]; - hash: string; -}; - -export function transform(block: RawBlock) { - const results: ResultType[] = []; - - for (const tx of block.transactions) { - const result: ResultType = { - contractsCreated: [], - contractSelfDestructed: [], - hash: tx.hash, - }; - - for (let i = 0; i < tx.traces.length; i += 1) { - const trace = tx.traces[i]; - - if (trace.type === 'suicide' && trace.action) { - result.contractSelfDestructed.push({ - address: trace.action.address, - balance: trace.action.balance - ? BigInt(trace.action.balance).toString() - : '0', - refundAddress: trace.action.refundAddress ?? '', - }); - } - } - - if (result.contractSelfDestructed.length > 0) { - results.push(result); - } - } - - return results; -} diff --git a/src/transformers/_common/contractTimestamp.ts b/src/transformers/_common/contractTimestamp.ts deleted file mode 100644 index d3deb96..0000000 --- a/src/transformers/_common/contractTimestamp.ts +++ /dev/null @@ -1,21 +0,0 @@ -import type { RawBlock, TransactionContract } from '../../types'; - -export function transform(block: RawBlock): TransactionContract[] { - const isoTimestamp = new Date(block.timestamp * 1000).toISOString(); - const result: TransactionContract[] = []; - - for (const tx of block.transactions) { - if (!tx.contracts) continue; - - const contracts = tx.contracts.map((txContract) => { - txContract.timestamp = block.timestamp; - txContract.isoTimestamp = isoTimestamp; - - return txContract; - }); - - result.push({ hash: tx.hash, contracts }); - } - - return result; -} diff --git a/src/transformers/_common/transactionProxyUpgrades.ts b/src/transformers/_common/transactionProxyUpgrades.ts deleted file mode 100644 index 2f2e6f6..0000000 --- a/src/transformers/_common/transactionProxyUpgrades.ts +++ /dev/null @@ -1,44 +0,0 @@ -import type { RawBlock, RawTransaction } from '../../types'; -import { TRANSPARENT_UPGRADEABLE_PROXY_EVENTS } from '../../helpers/constants'; -import { decodeEVMAddress } from '../../helpers/utils'; - -type ProxyUpgrade = { hash: string; address: string; upgradedAddress: string }; - -function getProxyUpgrades(tx: RawTransaction): ProxyUpgrade[] { - const proxyUpgrades: ProxyUpgrade[] = []; - for (const log of tx.receipt.logs) { - const [signature] = log.topics; - // detect upgrade event - if ( - signature === TRANSPARENT_UPGRADEABLE_PROXY_EVENTS['Upgraded(address)'] - ) { - // store proxy upgrades - const address = log.address.toLowerCase(); - let upgradedAddress = ''; - // check if its beacon proxy - if (log.data === '0x') { - upgradedAddress = decodeEVMAddress(log.topics[1]); - } else { - upgradedAddress = decodeEVMAddress(log.data); - } - proxyUpgrades.push({ - hash: tx.hash, - address, - upgradedAddress, - }); - } - } - - return proxyUpgrades; -} - -export function transform(block: RawBlock): ProxyUpgrade[] { - let results: ProxyUpgrade[] = []; - - for (const tx of block.transactions) { - const proxyUpgrades = getProxyUpgrades(tx); - results = [...results, ...proxyUpgrades]; - } - - return results; -} diff --git a/src/transformers/ethereum/blockEthPrice.ts b/src/transformers/ethereum/blockEthPrice.ts deleted file mode 100644 index de93374..0000000 --- a/src/transformers/ethereum/blockEthPrice.ts +++ /dev/null @@ -1,253 +0,0 @@ -import BigNumber from 'bignumber.js'; - -import etherscanPrices from '../helpers/etherscan_prices.json'; -import { toBigNumber } from '../helpers/utils'; -import { RawBlock } from '../types'; -import { decodeEvent } from '../helpers/sigMapper'; - -const ETH_DECIMALS = Math.pow(10, 18); -const USD_DECIMALS = Math.pow(10, 6); - -// put some rough safe guards around removing huge price swings -const MIN_USD_AMOUNT_TO_CONSIDER = 100; -const MAX_USD_AMOUNT_TO_CONSIDER = 10000; - -const etherscanPriceByDay: Record = {}; -for (const { UTCDate, value } of etherscanPrices.result) { - etherscanPriceByDay[UTCDate] = parseFloat(value); -} - -// define the Uniswap pools we want to use -const uniSwapV1USDC = '0x97dec872013f6b5fb443861090ad931542878126'; -const uniSwapV2ETHPools = new Set([ - '0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc', // V2: USDC - '0x0d4a11d5eeaac28ec3f61d100daf4d40471f1852', // V2: USDT -]); -const uniSwapV3ETHPools = new Set([ - '0x7bea39867e4169dbe237d55c8242a8f2fcdcc387', // V3: USDC 1 - '0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8', // V3: USDC 2 - '0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640', // V3: USDC 3 - '0x4e68ccd3e89f51c3074ca5072bbac773960dfa36', // V3: USDT 1 - '0xc5af84701f98fa483ece78af83f11b6c38aca71d', // V3: USDT 2 - '0x11b815efb8f581194ae79006d24e0d814b7697f6', // V3: USDT 3 -]); - -export function transform(block: RawBlock) { - const result: { - number: number; - price?: number; - priceSource?: 'ETHERSCAN' | 'UNISWAP'; - } = { number: block.number }; - const date = new Date(block.timestamp * 1000); - const swaps: { price: BigNumber; volume: BigNumber }[] = []; - - // if we're pre UniSwap usage (~ February 2019), then use Etherscan prices - if (block.number < 7207017) { - // only track the price for the block right at midnight - if ( - date.getUTCHours() === 0 && - date.getUTCMinutes() === 0 && - date.getUTCSeconds() < 30 - ) { - result.price = - etherscanPriceByDay[ - `${date.getUTCFullYear()}-${date.getUTCMonth() + 1}-${date.getUTCDate()}` - ]; - result.priceSource = 'ETHERSCAN'; - } - } - - // for the next year, look at adding liquidity to the original USDC Uniswap "pool" - else if (block.number < 10093190) { - for (const tx of block.transactions) { - for (const log of tx.receipt.logs) { - if ( - log.address === uniSwapV1USDC && - log.topics[0] === - '0x06239653922ac7bea6aa2b19dc486b9361821d37712eb796adfd38d81de278ca' - ) { - const usd = toBigNumber(log.topics[3]).div(USD_DECIMALS); - if (usd.gte(MIN_USD_AMOUNT_TO_CONSIDER)) { - const eth = toBigNumber(log.topics[2]).div(ETH_DECIMALS); - swaps.push({ price: usd.dividedBy(eth), volume: usd }); - } - } - } - } - } - - // and after May 2020, look to swaps on USDC and USDT Uniswap Pools - else { - for (const tx of block.transactions) { - for (const log of tx.receipt.logs) { - let amounts: BigNumber[] = []; - - // check V2 swap logs - if ( - uniSwapV2ETHPools.has(log.address) && - log.topics[0] === - '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822' && - log.topics.length === 3 - ) { - const params = decodeEvent( - [ - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'address', - name: 'sender', - type: 'address', - }, - { - indexed: false, - internalType: 'uint256', - name: 'amount0In', - type: 'uint256', - }, - { - indexed: false, - internalType: 'uint256', - name: 'amount1In', - type: 'uint256', - }, - { - indexed: false, - internalType: 'uint256', - name: 'amount0Out', - type: 'uint256', - }, - { - indexed: false, - internalType: 'uint256', - name: 'amount1Out', - type: 'uint256', - }, - { - indexed: true, - internalType: 'address', - name: 'to', - type: 'address', - }, - ], - name: 'Swap', - type: 'event', - }, - ], - log.topics, - log.data, - ); - - // first 4 data params are possible amounts, only 2 are used - amounts = params.args.slice(1, 5).map((v) => toBigNumber(v)); - } - - // and check V3 swap logs - else if ( - uniSwapV3ETHPools.has(log.address) && - log.topics[0] === - '0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67' && - log.topics.length === 3 - ) { - const params = decodeEvent( - [ - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'address', - name: 'sender', - type: 'address', - }, - { - indexed: true, - internalType: 'address', - name: 'recipient', - type: 'address', - }, - { - indexed: false, - internalType: 'int256', - name: 'amount0', - type: 'int256', - }, - { - indexed: false, - internalType: 'int256', - name: 'amount1', - type: 'int256', - }, - { - indexed: false, - internalType: 'uint160', - name: 'sqrtPriceX96', - type: 'uint160', - }, - { - indexed: false, - internalType: 'uint128', - name: 'liquidity', - type: 'uint128', - }, - { - indexed: false, - internalType: 'int24', - name: 'tick', - type: 'int24', - }, - ], - name: 'Swap', - type: 'event', - }, - ], - log.topics, - log.data, - ); - - // first 2 data params are possible amounts, one is always negative - amounts = params.args.slice(2, 4).map((v) => toBigNumber(v).abs()); - } - - if (amounts.length >= 2) { - // because ETH has 3x the decimals, it will always be the larger number prior to normalizing - let [usd, eth] = amounts - .filter((a) => a.gt(0)) - .sort((a, b) => (a.gt(b) ? 1 : -1)); - if (!usd || !eth) { - continue; - } - - usd = usd.div(USD_DECIMALS); - if ( - usd.gte(MIN_USD_AMOUNT_TO_CONSIDER) && - usd.lte(MAX_USD_AMOUNT_TO_CONSIDER) - ) { - eth = eth.div(ETH_DECIMALS); - swaps.push({ price: usd.dividedBy(eth), volume: usd }); - } - } - } - } - } - - // compute a quick Volume Weight Average Price (VWAP) for the block - if (swaps.length) { - const totalVolume = swaps.reduce( - (a, b) => a.plus(b.volume), - toBigNumber(0), - ); - const price = swaps - .reduce((a, b) => a.plus(b.price.multipliedBy(b.volume)), toBigNumber(0)) - .div(totalVolume); - result.price = price.decimalPlaces(2).toNumber(); - result.priceSource = 'UNISWAP'; - } - - if (!result.price) { - delete result.price; - delete result.priceSource; - } - return result; -} diff --git a/src/transformers/ethereum/blockFork.ts b/src/transformers/ethereum/blockFork.ts deleted file mode 100644 index e046407..0000000 --- a/src/transformers/ethereum/blockFork.ts +++ /dev/null @@ -1,27 +0,0 @@ -import type { RawBlock } from '../types'; -import { FORKS } from '../../helpers/constants'; - -export function transform(block: RawBlock) { - let fork: string; - - for (const [forkName, forkNumber] of Object.entries(FORKS)) { - if (block.number >= forkNumber) { - fork = forkName; - } - } - - let minerReward: number; - if (block.number < FORKS.byzantium) { - minerReward = 5; - } else if (block.number < FORKS.constantinople) { - minerReward = 3; - } else { - minerReward = 2; - } - - return { - number: block.number, - fork, - minerReward, - }; -} diff --git a/src/transformers/ethereum/contractPropHouseDetection.ts b/src/transformers/ethereum/contractPropHouseDetection.ts deleted file mode 100644 index 0065713..0000000 --- a/src/transformers/ethereum/contractPropHouseDetection.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { ethers } from 'ethers'; -import type { RawBlock, TransactionContract, PropHouseDao } from '../types'; -import { - PROP_HOUSE_PROXY_CONTRACT, - PROP_HOUSE_DAO_DEPLOYED_EVENT_HASH, - PROP_HOUSE_DAO_DEPLOYED_EVENT, -} from '../../helpers/constants'; - -export function transform(block: RawBlock): TransactionContract[] { - const result: TransactionContract[] = block.transactions - .filter((tx) => tx.contracts?.length > 0) - .map((tx) => { - const propHouseDaos: PropHouseDao[] = tx.receipt.logs - .filter( - (log) => - log.topics[0] === PROP_HOUSE_DAO_DEPLOYED_EVENT_HASH && - log.address.toLowerCase() === PROP_HOUSE_PROXY_CONTRACT.toLowerCase() - ) - .map((log) => { - // decode log - try { - const iface = new ethers.Interface([PROP_HOUSE_DAO_DEPLOYED_EVENT]); - const logDescriptor = iface.parseLog({ - topics: log.topics, - data: log.data, - }); - // get governor address from decoded log - const token = logDescriptor.args[0] as string; - const metadata = logDescriptor.args[1] as string; - const auction = logDescriptor.args[2] as string; - const treasury = logDescriptor.args[3] as string; - const governor = logDescriptor.args[4] as string; - - return { - token: token.toLowerCase(), - metadata: metadata.toLowerCase(), - auction: auction.toLowerCase(), - treasury: treasury.toLowerCase(), - governor: governor.toLowerCase(), - }; - } catch (e) { - return null; - } - }) - .filter((v) => v); - - const propHouseTokens = propHouseDaos.map((dao) => dao.token); - const propHouseMetadatas = propHouseDaos.map((dao) => dao.metadata); - const propHouseAuctions = propHouseDaos.map((dao) => dao.auction); - const propHouseTreasuries = propHouseDaos.map((dao) => dao.treasury); - const propHouseGovernors = propHouseDaos.map((dao) => dao.governor); - - // check contracts - const contracts = tx.contracts.map((contract) => { - // check if contract is PropHouse token address - if (propHouseTokens.includes(contract.address)) { - contract.metadata.isPropHouseToken = true; - } - // check if contract is PropHouse metadata address - if (propHouseMetadatas.includes(contract.address)) { - contract.metadata.isPropHouseMetadata = true; - } - // check if contract is PropHouse auction address - if (propHouseAuctions.includes(contract.address)) { - contract.metadata.isPropHouseAuction = true; - } - // check if contract is PropHouse treasuries address - if (propHouseTreasuries.includes(contract.address)) { - contract.metadata.isPropHouseTreasury = true; - } - // check if contract is PropHouse governor address - if (propHouseGovernors.includes(contract.address)) { - contract.metadata.isPropHouseGovernor = true; - } - return contract; - }); - - return { hash: tx.hash, contracts }; - }); - - return result; -} diff --git a/src/transformers/ethereum/contractUniswapDetection.ts b/src/transformers/ethereum/contractUniswapDetection.ts deleted file mode 100644 index 0b07449..0000000 --- a/src/transformers/ethereum/contractUniswapDetection.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { ethers } from 'ethers'; -import type { RawBlock, TransactionContract, UniswapPair } from '../types'; -import { decodeEVMAddress } from '../helpers/utils'; -import { - UNISWAP_V3_FACTORY, - UNISWAP_V2_FACTORY, - UNISWAP_V1_FACTORY, - UNISWAP_V3_POOL_CREATED_EVENT, - UNISWAP_V2_PAIR_CREATED_EVENT, - UNISWAP_V1_NEW_EXCHANGE_EVENT_HASH, - UNISWAP_V2_PAIR_CREATED_EVENT_HASH, - UNISWAP_V3_POOL_CREATED_EVENT_HASH, -} from '../../helpers/constants'; - -export function transform(block: RawBlock): TransactionContract[] { - const result: TransactionContract[] = block.transactions - .filter((tx) => tx.contracts?.length > 0) - .map((tx) => { - const uniswapV3Pools: UniswapPair[] = tx.receipt.logs - .filter((log) => log.topics[0] === UNISWAP_V3_POOL_CREATED_EVENT_HASH && log.address === UNISWAP_V3_FACTORY) - .map((log) => { - // decode log - try { - const iface = new ethers.Interface([UNISWAP_V3_POOL_CREATED_EVENT]); - const logDescriptor = iface.parseLog({ - topics: log.topics, - data: log.data, - }); - // get pool address from decoded log - const pool = logDescriptor.args[4] as string; - // get token addresses - const tokenA = decodeEVMAddress(log.topics[1]); - const tokenB = decodeEVMAddress(log.topics[2]); - - return { - address: pool.toLowerCase(), - tokens: [tokenA.toLowerCase(), tokenB.toLowerCase()], - }; - } catch (e) { - return null; - } - }) - .filter((v) => v); - - const uniswapV2Pairs: UniswapPair[] = tx.receipt.logs - .filter((log) => log.topics[0] === UNISWAP_V2_PAIR_CREATED_EVENT_HASH && log.address === UNISWAP_V2_FACTORY) - .map((log) => { - // decode log - try { - const iface = new ethers.Interface([UNISWAP_V2_PAIR_CREATED_EVENT]); - const logDescriptor = iface.parseLog({ - topics: log.topics, - data: log.data, - }); - // get pool address from decoded log - const pool = logDescriptor.args[2] as string; - // get token addresses - const tokenA = decodeEVMAddress(log.topics[1]); - const tokenB = decodeEVMAddress(log.topics[2]); - - return { - address: pool.toLowerCase(), - tokens: [tokenA.toLowerCase(), tokenB.toLowerCase()], - }; - } catch (e) { - return null; - } - }) - .filter((v) => v); - - const uniswapV1Exchanges: UniswapPair[] = tx.receipt.logs - .filter((log) => log.topics[0] === UNISWAP_V1_NEW_EXCHANGE_EVENT_HASH && log.address === UNISWAP_V1_FACTORY) - .map((log) => { - // go trough traces and tract create call - const exchangeCreateTrace = tx.traces.find((trace) => trace.type === 'create'); - const pool = exchangeCreateTrace.result.address; - // get token addresses - const tokenA = decodeEVMAddress(log.topics[1]); - const tokenB = decodeEVMAddress(log.topics[2]); - - return { - address: pool.toLowerCase(), - tokens: [tokenA.toLowerCase(), tokenB.toLowerCase()], - }; - }); - - // check contracts - const contracts = tx.contracts.map((contract) => { - const v3Pair = uniswapV3Pools.find((pair) => pair.address === contract.address); - const v2Pair = uniswapV2Pairs.find((pair) => pair.address === contract.address); - const v1Pair = uniswapV1Exchanges.find((pair) => pair.address === contract.address); - // check if contract is uniswap v3 pool - if (v3Pair) { - contract.metadata.isUniswapV3 = true; - contract.metadata.uniswapPairs = v3Pair.tokens; - } - if (v2Pair) { - contract.metadata.isUniswapV2 = true; - contract.metadata.uniswapPairs = v2Pair.tokens; - } - if (v1Pair) { - contract.metadata.isUniswapV1 = true; - contract.metadata.uniswapPairs = v1Pair.tokens; - } - return contract; - }); - - return { hash: tx.hash, contracts }; - }); - - return result; -} diff --git a/src/transformers/ethereum/transactionAssetTransfersOldNFTs.ts b/src/transformers/ethereum/transactionAssetTransfersOldNFTs.ts index 52dc8d9..2ba17f6 100644 --- a/src/transformers/ethereum/transactionAssetTransfersOldNFTs.ts +++ b/src/transformers/ethereum/transactionAssetTransfersOldNFTs.ts @@ -1,19 +1,27 @@ -import { decodeEVMAddress, toBigNumber } from '../helpers/utils'; -import type { AssetTransfer, RawBlock, RawTransaction, transactionAssetTransfers } from '../types'; +import { decodeEVMAddress } from '../../helpers/utils'; +import { + AssetType, + type AssetTransfer, + type EventLogTopics, + type RawBlock, + type RawTransaction, + type transactionAssetTransfers, +} from '../../types'; import { KNOWN_ADDRESSES, OLD_NFT_ADDRESSES, ERC721_TRANSFER_EVENT_1, ERC721_TRANSFER_EVENT_2, } from '../../helpers/constants'; -import { decodeEvent } from '../helpers/sigMapper'; +import { decodeEventLog, Hex } from 'viem'; const TRANSFER_SIGNATURES = { // event Transfer(address,address,uint256) ERC721: '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', // event PunkTransfer(address indexed from, address indexed to, uint256 punkIndex) - CRYPTO_PUNKS_ERC721: '0x05af636b70da6819000c49f85b21fa82081c632069bb626f30932034099107d8', + CRYPTO_PUNKS_ERC721: + '0x05af636b70da6819000c49f85b21fa82081c632069bb626f30932034099107d8', }; function updateTokenTransfers(tx: RawTransaction) { @@ -28,60 +36,66 @@ function updateTokenTransfers(tx: RawTransaction) { switch (signature) { // @NOTE: all of these cases are the same function signature - case TRANSFER_SIGNATURES.ERC721: { + case TRANSFER_SIGNATURES.ERC721: // for cryptopunks, we skip Transfer event and parse PunkTransfer - if (log.address === KNOWN_ADDRESSES.CryptoPunksNew || log.address === KNOWN_ADDRESSES.CryptoPunksOld) { - continue; + if ( + log.address === KNOWN_ADDRESSES.CryptoPunksNew || + log.address === KNOWN_ADDRESSES.CryptoPunksOld + ) { + break; } // check for old nfts - let logDescriptor = decodeEvent([ERC721_TRANSFER_EVENT_1], log.topics, log.data); + let logDescriptor = decodeEventLog({ + abi: ERC721_TRANSFER_EVENT_1, + data: log.data as Hex, + topics: log.topics as EventLogTopics, + }); if (!logDescriptor) { - logDescriptor = decodeEvent([ERC721_TRANSFER_EVENT_2], log.topics, log.data); - } - if (logDescriptor) { - oldNFTsTransfers.push({ - asset: log.address, - from: logDescriptor.args[0] as string, - to: logDescriptor.args[1] as string, - tokenId: logDescriptor.args[2] as string, - type: 'erc721', + logDescriptor = decodeEventLog({ + abi: ERC721_TRANSFER_EVENT_2, + data: log.data as Hex, + topics: log.topics as EventLogTopics, }); - } else { - // if there's a 4th topic (indexed parameter), then it's an ERC721 - if (log.topics.length === 4) { + if (logDescriptor) { oldNFTsTransfers.push({ asset: log.address, - from: decodeEVMAddress(log.topics[1]), - to: decodeEVMAddress(log.topics[2]), - tokenId: toBigNumber(log.topics[3]).toString(), - type: 'erc721', + from: logDescriptor.args[0] as string, + to: logDescriptor.args[1] as string, + tokenId: logDescriptor.args[2] as string, + type: AssetType.ERC721, }); } else { - oldNFTsTransfers.push({ - asset: log.address, - from: decodeEVMAddress(log.topics[1]), - to: decodeEVMAddress(log.topics[2]), - value: toBigNumber(log.data).toString(), - type: 'erc721', - }); + // if there's a 4th topic (indexed parameter), then it's an ERC721 + if (log.topics.length === 4) { + oldNFTsTransfers.push({ + asset: log.address, + from: decodeEVMAddress(log.topics[1]), + to: decodeEVMAddress(log.topics[2]), + tokenId: BigInt(log.topics[3]).toString(), + type: AssetType.ERC721, + }); + } else { + oldNFTsTransfers.push({ + asset: log.address, + from: decodeEVMAddress(log.topics[1]), + to: decodeEVMAddress(log.topics[2]), + tokenId: BigInt(log.data).toString(), + type: AssetType.ERC721, + }); + } } } - - continue; - } - - case TRANSFER_SIGNATURES.CRYPTO_PUNKS_ERC721: { + break; + case TRANSFER_SIGNATURES.CRYPTO_PUNKS_ERC721: oldNFTsTransfers.push({ asset: log.address, from: decodeEVMAddress(log.topics[1]), to: decodeEVMAddress(log.topics[2]), - tokenId: toBigNumber(log.data).toString(), - type: 'erc721', + tokenId: BigInt(log.data).toString(), + type: AssetType.ERC721, }); - continue; - } - + break; default: break; } @@ -89,7 +103,9 @@ function updateTokenTransfers(tx: RawTransaction) { // filter old asset transfers from previous asset transfers const nonOldAssetTransfers = tx.assetTransfers.filter( - (assetTransfer) => !OLD_NFT_ADDRESSES.includes(assetTransfer.asset) + (assetTransfer) => + assetTransfer.type !== AssetType.ETH && + !OLD_NFT_ADDRESSES.includes(assetTransfer.asset), ); const assetTransfers = [...nonOldAssetTransfers, ...oldNFTsTransfers]; @@ -99,8 +115,10 @@ function updateTokenTransfers(tx: RawTransaction) { export function transform(block: RawBlock) { const results: transactionAssetTransfers[] = block.transactions.map((tx) => { let assetTransfers = tx.assetTransfers; - const hasOldNFTTransfer = tx.assetTransfers?.some((assetTransfer) => - OLD_NFT_ADDRESSES.includes(assetTransfer.asset) + const hasOldNFTTransfer = tx.assetTransfers?.some( + (assetTransfer) => + assetTransfer.type !== AssetType.ETH && + OLD_NFT_ADDRESSES.includes(assetTransfer.asset), ); if (hasOldNFTTransfer) { assetTransfers = updateTokenTransfers(tx); diff --git a/src/transformers/ethereum/transactionFees.ts b/src/transformers/ethereum/transactionFees.ts index 1a2801d..9c5c43a 100644 --- a/src/transformers/ethereum/transactionFees.ts +++ b/src/transformers/ethereum/transactionFees.ts @@ -1,14 +1,13 @@ -import type { RawBlock, RawTransaction } from '../types'; -import { toBigNumber } from '../helpers/utils'; +import type { RawBlock, RawTransaction } from '../../types'; import { FORKS } from '../../helpers/constants'; export function transform(block: RawBlock) { const newTxs: Partial[] = []; for (const tx of block.transactions) { - const transactionFee = toBigNumber(tx.receipt.gasUsed) - .multipliedBy(toBigNumber(tx.receipt.effectiveGasPrice)) - .toString(); + const transactionFee = ( + BigInt(tx.receipt.gasUsed) * BigInt(tx.receipt.effectiveGasPrice) + ).toString(); let burntFees = '0'; let minerFees = transactionFee; @@ -20,11 +19,13 @@ export function transform(block: RawBlock) { * including respective base fees and tips." */ if (tx.type === 2 && block.number >= FORKS.london) { - burntFees = toBigNumber(block.baseFeePerGas).multipliedBy(toBigNumber(tx.receipt.gasUsed)).toString(); - minerFees = toBigNumber(tx.receipt.effectiveGasPrice) - .minus(toBigNumber(block.baseFeePerGas)) - .multipliedBy(toBigNumber(tx.receipt.gasUsed)) - .toString(); + burntFees = ( + BigInt(block.baseFeePerGas) * BigInt(tx.receipt.gasUsed) + ).toString(); + minerFees = ( + (BigInt(tx.receipt.effectiveGasPrice) - BigInt(block.baseFeePerGas)) * + BigInt(tx.receipt.gasUsed) + ).toString(); } newTxs.push({ diff --git a/src/transformers/ethereum/transactionForks.ts b/src/transformers/ethereum/transactionForks.ts index 3b5ac38..688af6d 100644 --- a/src/transformers/ethereum/transactionForks.ts +++ b/src/transformers/ethereum/transactionForks.ts @@ -1,4 +1,4 @@ -import type { RawBlock } from '../types'; +import type { RawBlock } from '../../types'; import { FORKS } from '../../helpers/constants'; export function transform(block: RawBlock) { @@ -10,5 +10,7 @@ export function transform(block: RawBlock) { } } - return block.transactions?.slice().map((tx) => ({ hash: tx.hash, fork })) || []; + return ( + block.transactions?.slice().map((tx) => ({ hash: tx.hash, fork })) || [] + ); } diff --git a/src/types/block.ts b/src/types/block.ts index 63fbbd3..62feb6f 100644 --- a/src/types/block.ts +++ b/src/types/block.ts @@ -8,4 +8,5 @@ export type RawBlock = StdObj & { transactions: RawTransaction[]; gasUsed: string; gasLimit: string; + baseFeePerGas: number | string; }; diff --git a/src/types/contract.ts b/src/types/contract.ts index 18a75b0..a255d54 100644 --- a/src/types/contract.ts +++ b/src/types/contract.ts @@ -94,3 +94,11 @@ export type TokenMetadata = { symbol?: string; decimals?: number; }; + +export type PropHouseDao = { + token: string; + metadata: string; + auction: string; + treasury: string; + governor: string; +}; diff --git a/src/types/log.ts b/src/types/log.ts index 2639949..8a99e7b 100644 --- a/src/types/log.ts +++ b/src/types/log.ts @@ -23,4 +23,11 @@ export type RawLog = StdObj & { export type RawReceipt = StdObj & { logs: RawLog[]; + gasUsed: number | string; + effectiveGasPrice: number | string; }; + +export type EventLogTopics = [ + signature: `0x${string}`, + ...args: `0x${string}`[], +]; From 48c1908c49fbacb7246f5531bb968e22a1a18607 Mon Sep 17 00:00:00 2001 From: ponyjackal Date: Mon, 29 Jan 2024 04:04:09 -0800 Subject: [PATCH 7/9] feat: use BigInt L2 fee logic --- src/transformers/ethereum/transactionFees.ts | 45 +++++++++----------- src/types/log.ts | 3 ++ src/types/transaction.ts | 1 + 3 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/transformers/ethereum/transactionFees.ts b/src/transformers/ethereum/transactionFees.ts index 9c5c43a..b05dbc2 100644 --- a/src/transformers/ethereum/transactionFees.ts +++ b/src/transformers/ethereum/transactionFees.ts @@ -1,39 +1,34 @@ import type { RawBlock, RawTransaction } from '../../types'; -import { FORKS } from '../../helpers/constants'; export function transform(block: RawBlock) { const newTxs: Partial[] = []; for (const tx of block.transactions) { - const transactionFee = ( - BigInt(tx.receipt.gasUsed) * BigInt(tx.receipt.effectiveGasPrice) - ).toString(); - - let burntFees = '0'; - let minerFees = transactionFee; - - /*** - * Legacy tx after EIP1559 https://legacy.ethgasstation.info/blog/eip-1559/ - * "EIP-1559 will still be able to facilitate legacy style transactions. - * When these transactions come in their gas prices are simply converted into fee caps, - * including respective base fees and tips." - */ - if (tx.type === 2 && block.number >= FORKS.london) { - burntFees = ( - BigInt(block.baseFeePerGas) * BigInt(tx.receipt.gasUsed) - ).toString(); - minerFees = ( - (BigInt(tx.receipt.effectiveGasPrice) - BigInt(block.baseFeePerGas)) * - BigInt(tx.receipt.gasUsed) - ).toString(); + let totalL2FeeWei = BigInt(0); + if (tx.gasPrice) { + const l2GasPrice = BigInt(tx.gasPrice); + const l2GasUsed = BigInt(tx.receipt?.gasUsed ?? 0); + + const tenToTheEighteenth = BigInt('1000000000000000000'); + + const l1FeeContribution = !tx.receipt?.l1GasUsed + ? BigInt(0) + : (BigInt(tx.receipt?.l1GasPrice ?? 0) * + BigInt(tx.receipt.l1GasUsed) * + BigInt( + parseFloat(tx.receipt?.l1FeeScalar ?? '0') * Math.pow(10, 18), + )) / + tenToTheEighteenth; + + const l2FeeContribution = l2GasPrice * l2GasUsed; + + totalL2FeeWei = l2FeeContribution + l1FeeContribution; } newTxs.push({ hash: tx.hash, baseFeePerGas: block.baseFeePerGas, - burntFees, - minerFees, - transactionFee, + transactionFee: totalL2FeeWei.toString(), }); } diff --git a/src/types/log.ts b/src/types/log.ts index 8a99e7b..bc0e854 100644 --- a/src/types/log.ts +++ b/src/types/log.ts @@ -25,6 +25,9 @@ export type RawReceipt = StdObj & { logs: RawLog[]; gasUsed: number | string; effectiveGasPrice: number | string; + l1GasPrice?: string; + l1GasUsed?: string; + l1FeeScalar?: string; }; export type EventLogTopics = [ diff --git a/src/types/transaction.ts b/src/types/transaction.ts index 6f18298..8744703 100644 --- a/src/types/transaction.ts +++ b/src/types/transaction.ts @@ -11,6 +11,7 @@ export type RawTransaction = StdObj & { input: string; value: string; receipt: RawReceipt; + gasPrice: string; to: string; traces: RawTrace[]; contracts?: Contract[]; From fc69a1478bc7e148be2299ade8caca3f753f254b Mon Sep 17 00:00:00 2001 From: ponyjackal Date: Tue, 30 Jan 2024 09:23:47 -0800 Subject: [PATCH 8/9] feat: remove whatsabi package --- package-lock.json | 74 ----------------------------------------------- package.json | 1 - 2 files changed, 75 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2f2e15d..5f511b2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,6 @@ "version": "0.0.1", "license": "MIT", "dependencies": { - "@shazow/whatsabi": "^0.11.0", "commander": "^11.1.0", "dotenv": "^16.3.1", "handlebars": "^4.7.8", @@ -1374,17 +1373,6 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/@shazow/whatsabi": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@shazow/whatsabi/-/whatsabi-0.11.0.tgz", - "integrity": "sha512-dIjhgynJeqPLwSI179E37yFElq+IDyy6xBk9fthkhZp/NO6o2AvtJUq9hWotCBNX/ZQzh6ak7CmdHevwralW8w==", - "dependencies": { - "ethers": "^6.10.0" - }, - "peerDependencies": { - "@noble/hashes": "^1" - } - }, "node_modules/@sinclair/typebox": { "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", @@ -1776,11 +1764,6 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/aes-js": { - "version": "4.0.0-beta.5", - "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz", - "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==" - }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -2732,63 +2715,6 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/ethers": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.10.0.tgz", - "integrity": "sha512-nMNwYHzs6V1FR3Y4cdfxSQmNgZsRj1RiTU25JwvnJLmyzw9z3SKxNc2XKDuiXXo/v9ds5Mp9m6HBabgYQQ26tA==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/ethers-io/" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@adraffy/ens-normalize": "1.10.0", - "@noble/curves": "1.2.0", - "@noble/hashes": "1.3.2", - "@types/node": "18.15.13", - "aes-js": "4.0.0-beta.5", - "tslib": "2.4.0", - "ws": "8.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/ethers/node_modules/@types/node": { - "version": "18.15.13", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.13.tgz", - "integrity": "sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==" - }, - "node_modules/ethers/node_modules/tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" - }, - "node_modules/ethers/node_modules/ws": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", - "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, "node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", diff --git a/package.json b/package.json index 1ee73c5..7fe5c5f 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,6 @@ "testEnvironment": "node" }, "dependencies": { - "@shazow/whatsabi": "^0.11.0", "commander": "^11.1.0", "dotenv": "^16.3.1", "handlebars": "^4.7.8", From 7152161e88a2f770f785dc3896d1e7e553f7046c Mon Sep 17 00:00:00 2001 From: ponyjackal Date: Tue, 30 Jan 2024 15:57:28 -0800 Subject: [PATCH 9/9] feat: add basic unit test --- src/transformer.spec.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/transformer.spec.ts b/src/transformer.spec.ts index e69de29..2a7e614 100644 --- a/src/transformer.spec.ts +++ b/src/transformer.spec.ts @@ -0,0 +1,5 @@ +describe('transform', () => { + it('should transform the input correctly', () => { + expect(true).toEqual(true); + }); +});