From b292890b5d72ef95459619bab383cf71fd1d33ad Mon Sep 17 00:00:00 2001 From: Mykola Date: Mon, 12 Mar 2018 11:01:08 -0700 Subject: [PATCH] Contract creation (#216) * Add interface * Disable no-null-keyword Otherways alert when define object with key = null for the test https://web3js.readthedocs.io/en/1.0/web3-eth.html?highlight=block#id50 * Add seed data * Add test for extractTransactionData() * Don not save to = null for contract creation transaction Fixes https://github.com/TrustWallet/trust-ray/issues/95 * Add extra check --- src/common/CommonInterfaces.ts | 8 +++-- src/common/TransactionParser.ts | 16 +++++----- test/SeedData.ts | 52 +++++++++++++++++++++++++++++++++ test/TransactionParser.test.ts | 35 ++++++++++++++++++++++ tslint.json | 2 +- 5 files changed, 102 insertions(+), 11 deletions(-) create mode 100644 test/SeedData.ts create mode 100644 test/TransactionParser.test.ts diff --git a/src/common/CommonInterfaces.ts b/src/common/CommonInterfaces.ts index 719d7976..c37c68a6 100644 --- a/src/common/CommonInterfaces.ts +++ b/src/common/CommonInterfaces.ts @@ -32,7 +32,7 @@ export interface ITransactionReceipt { logs: any[] // TODO add log interface } -export interface ITransaction { +export interface ISavedTransaction { _id: string, addresses: string[], blockNumber: number, @@ -58,7 +58,7 @@ export interface ITransaction { blockHash: string | null, blockNumber: number, from: string, - gas: string, + gas: number, gasPrice: string, hash: string, input: string, @@ -71,6 +71,10 @@ export interface ITransaction { s?: string } +export interface IExtractedTransaction extends ITransaction { + _id: string +} + export interface IBlock { difficulty: string, extraData: string, diff --git a/src/common/TransactionParser.ts b/src/common/TransactionParser.ts index 7a0952bd..19ef440e 100644 --- a/src/common/TransactionParser.ts +++ b/src/common/TransactionParser.ts @@ -4,8 +4,7 @@ import { TransactionOperation } from "../models/TransactionOperationModel"; import { removeScientificNotationFromNumbString } from "./Utils"; import { Config } from "./Config"; import { Promise } from "bluebird"; -import { IDecodedLog, IContract, ITransaction } from "./CommonInterfaces"; - +import { IDecodedLog, IContract, ITransaction, IBlock, IExtractedTransaction, ISavedTransaction } from "./CommonInterfaces"; const erc20abi = require("./contracts/Erc20Abi"); const erc20ABIDecoder = require("abi-decoder"); erc20ABIDecoder.addABI(erc20abi); @@ -23,14 +22,14 @@ export class TransactionParser { return new Transaction(this.extractTransactionData(block, tx)); }); }); - const txIDs = extractedTransactions.map((tx: ITransaction) => tx._id); + const txIDs = extractedTransactions.map((tx: IExtractedTransaction) => tx._id); return this.fetchTransactionReceipts(txIDs).then((receipts: any) => { return this.mergeTransactionsAndReceipts(extractedTransactions, receipts); }).then((transactions: any) => { const bulkTransactions = Transaction.collection.initializeUnorderedBulkOp(); - transactions.forEach((transaction: ITransaction) => + transactions.forEach((transaction: IExtractedTransaction) => bulkTransactions.find({_id: transaction._id}).upsert().replaceOne(transaction) ); @@ -68,9 +67,10 @@ export class TransactionParser { return newTransaction; } - private extractTransactionData(block: any, transaction: any) { + extractTransactionData(block: IBlock, transaction: ITransaction) { const from = String(transaction.from).toLowerCase(); - const to = String(transaction.to).toLowerCase(); + const to: string = transaction.to === null ? "" : String(transaction.to).toLowerCase(); + const addresses: string[] = to ? [from, to] : [from]; return { _id: String(transaction.hash), @@ -84,13 +84,13 @@ export class TransactionParser { gasPrice: String(transaction.gasPrice), gasUsed: String(0), input: String(transaction.input), - addresses: [from, to] + addresses }; } // ========================== OPERATION PARSING ========================== // - public parseTransactionOperations(transactions: ITransaction[], contracts: IContract[]) { + public parseTransactionOperations(transactions: ISavedTransaction[], contracts: IContract[]) { if (!transactions || !contracts) return Promise.resolve(); return Promise.map(transactions, (transaction) => { diff --git a/test/SeedData.ts b/test/SeedData.ts new file mode 100644 index 00000000..fae19d6e --- /dev/null +++ b/test/SeedData.ts @@ -0,0 +1,52 @@ +// Contract creation trasaction +export const contractCreateTrx = { + blockHash: "0xcea93534febc780727c1404fba8ef420b728eab17f8ebdea38a1b7b79a941325", + blockNumber: 4925033, + from: "0xb42b20ddbEabdC2a288Be7FF847fF94fB48d2579", + gas: 500000, + gasPrice: "50000000000", + hash: "0x5051473cc1cf2b934fc13e7863bd44b19392eae25f619f3d6653c89e30a55b1a", + input: "0x6060604052341561000c57fe5b5b73209c4784ab1e8183cf58ca33cb740efbf3fc18ef600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555073b42b20ddbeabdc2a288be7ff847ff94fb48d2579600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b5b6104a0806100c86000396000f30060606040523615610055576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063661172761461014857806382c90ac01461017e578063b76ea962146101b4575b6101465b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163460405180905060006040518083038185876187965a03f1925050501561013d577f23919512b2162ddc59b67a65e3b03c419d4105366f7d4a632f5d3c3bee9b1cff600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a1610143565b60006000fd5b5b565b005b341561015057fe5b61017c600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610225565b005b341561018657fe5b6101b2600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506102c8565b005b610223600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509190505061036b565b005b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156102825760006000fd5b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b5b50565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156103255760006000fd5b80600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b5b50565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156103c85760006000fd5b8173ffffffffffffffffffffffffffffffffffffffff1634826040518082805190602001908083836000831461041d575b80518252602083111561041d576020820191506020810190506020830392506103f9565b505050905090810190601f1680156104495780820380516001836020036101000a031916815260200191505b5091505060006040518083038185876187965a03f192505050151561046e5760006000fd5b5b5b50505600a165627a7a7230582015dd8a30edc4d2b88e51c1e252cdc5a08cd0159c2d5d7b063fdaad85d6e813e40029", + nonce: 285675, + to: null, + transactionIndex: 27, + value: "0", +} + +// ETH transfer +export const ethTransferTrx = { + blockHash: "0x946b9020ea3a55980a08bb362fa98e883a8d3b63a3c3d67bcbbb0a0401edde84", + blockNumber: 4902828, + from: "0xdC2C39938b86Ce47d14cF2000Bbc0F3CCA9f09B3", + gas: 21000, + gasPrice: "110000000000", + hash: "0x3c9ece41403d76125352ffd941c8da4f2f379f258f3187987f7fdb28d5bb86db", + input: "0x", + nonce: 2, + to: "0xF08BDf21373A09aB7eDD7769A402D3a22826D317", + transactionIndex: 221, + value: "0", +} + +export const block = { difficulty: "1771245602758757", + extraData: "0xe4b883e5bda9e7a59ee4bb99e9b1bc", + gasLimit: 8000000, + gasUsed: 7982114, + hash: "0xdecf0e6886f0adeb4dca839a764d905add7830e703d4758773e7470cf3ee481b", + logsBloom: "0x00002021904001000a82020044000000000010000001000480032410112001680020010081000040801800000820008081010118010900101043020020200000000000418420000120106088a0000000020020000020100000010100000000011010042002400001005040a1000008000200020018144800062080750002220020108010402000000400040900011011001101001600081400001002000880000a0482002200000000000000b105840001000405000080008010501421084021c000840208060800021e000002004020a00020049208000010001040090028000010000104200000000000008901810010000004000000680208801400000090", + miner: "0x829BD824B016326A401d083B33D092293333A830", + mixHash: "0x53d51eb64e82632658c50a0ac02ba44ce78ff5ebe16311cde2df3b9d372b0564", + nonce: "0xee7660201fde3240", + number: 4748244, + parentHash: "0xcf6dd8d1ff207cd937e6b0e30a0d2ec462129d495c4edf5dcf7ee0d3567ae55b", + receiptsRoot: "0x712b97042663d98abed51210814d9fab7a08f92e7bf6b2902c6f123679a452e3", + sha3Uncles: "0x2d8f607dd5d66ee3003975eecb3e0fe2278ddb84b2a20beb6699eddb8d596c19", + size: 35246, + stateRoot: "0x0e397fa8b0ede6defebb5cbea187fb6a099a625e80101bc5dc3f0c659cfdbae4", + timestamp: 1513510292, + totalDifficulty: "1761498747834301809225", + transactions: [], + transactionsRoot: "0x5555292fb1f08aa06b65725117a88a00cde2dbfb73fd9939890a5bd6910f1fa4", + uncles: ["0x7904fd964c65e5e62cd894a947f7775eb8fdd90f46c4519ae8ee2af006e13dac"] +} + diff --git a/test/TransactionParser.test.ts b/test/TransactionParser.test.ts new file mode 100644 index 00000000..48f7618c --- /dev/null +++ b/test/TransactionParser.test.ts @@ -0,0 +1,35 @@ + +import { TransactionParser } from "../src/common/TransactionParser"; +import * as mocha from "mocha"; +import { block, contractCreateTrx, ethTransferTrx } from "./SeedData"; +import { should, expect } from "chai" + + +describe("Test TransactionParser", () => { + describe("Test extractTransactionData()", () => { + const extractTransactionData = new TransactionParser().extractTransactionData; + it("Should extract transaction data", () => { + const transaction = extractTransactionData(block, ethTransferTrx); + + transaction.should.to.have.property("_id").to.be.a("string"); + transaction.should.to.have.property("blockNumber").to.be.a("number"); + transaction.should.to.have.property("timeStamp").to.be.a("string"); + transaction.should.to.have.property("nonce").to.be.a("number"); + transaction.should.to.have.property("from").to.be.a("string"); + transaction.should.to.have.property("to").to.be.a("string"); + transaction.should.to.have.property("value").to.be.a("string"); + transaction.should.to.have.property("gas").to.be.a("string"); + transaction.should.to.have.property("gasPrice").to.be.a("string"); + transaction.should.to.have.property("gasUsed").to.be.a("string"); + transaction.should.to.have.property("input").to.be.a("string"); + transaction.should.to.have.property("addresses").to.be.a("array").to.have.lengthOf(2); + }) + + it("Should extract contract creation transaction correctly", () => { + const transaction = extractTransactionData(block, contractCreateTrx); + + expect(transaction.to).to.equal(""); + expect(transaction.addresses).to.have.lengthOf(1); + }) + }) +}) \ No newline at end of file diff --git a/tslint.json b/tslint.json index f32a6bf1..15410559 100644 --- a/tslint.json +++ b/tslint.json @@ -54,7 +54,7 @@ ], "no-internal-module": true, "no-trailing-whitespace": true, - "no-null-keyword": true, + "no-null-keyword": false, "prefer-const": true, "jsdoc-format": true }