Skip to content

Commit

Permalink
Transaction to smart contract (#76)
Browse files Browse the repository at this point in the history
* add issmartcontract code

* check if recipient is smart contract when fetching tx

* add tests for changes

* remove duplicated doc

* dont request code if empty data

* fix typo

* fix condition
  • Loading branch information
estebanmino authored and MajorLift committed Oct 11, 2023
1 parent 304321a commit 7273d9c
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 5 deletions.
21 changes: 19 additions & 2 deletions src/TransactionController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,24 @@ const MOCK_FETCH_TX_HISTORY_DATA_OK = {
transactionIndex: '12',
txreceipt_status: '1',
value: '50000000000000000'
},
{
blockNumber: '4535105',
confirmations: '4',
contractAddress: '',
cumulativeGasUsed: '693910',
from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207',
gas: '335208',
gasPrice: '20000000000',
gasUsed: '21000',
hash: '0x342e9d73e10004af41d04973339fc7219dbadcbb5629730cfe65e9f9cb15ff91',
input: '0x',
isError: '0',
nonce: '1',
timeStamp: '1543596356',
transactionIndex: '13',
txreceipt_status: '1',
value: '50000000000000000'
}
],
status: '1'
Expand Down Expand Up @@ -373,7 +391,7 @@ describe('TransactionController', () => {

const from = '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207';
const latestBlock = await controller.fetchAll(from);
expect(controller.state.transactions.length).toBe(2);
expect(controller.state.transactions.length).toBe(3);
expect(latestBlock).toBe('4535101');
expect(controller.state.transactions[0].transaction.to).toBe(from);
});
Expand All @@ -387,7 +405,6 @@ describe('TransactionController', () => {
} as any;
controller.onComposed();
expect(controller.state.transactions.length).toBe(0);

const from = '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207';
const result = await controller.fetchAll(from);
expect(controller.state.transactions.length).toBe(0);
Expand Down
25 changes: 22 additions & 3 deletions src/TransactionController.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import { EventEmitter } from 'events';
import BaseController, { BaseConfig, BaseState } from './BaseController';
import NetworkController from './NetworkController';
import { BNToHex, fractionBN, hexToBN, normalizeTransaction, safelyExecute, validateTransaction } from './util';
import {
BNToHex,
fractionBN,
hexToBN,
normalizeTransaction,
safelyExecute,
validateTransaction,
isSmartContractCode
} from './util';

const EthQuery = require('eth-query');
const Transaction = require('ethereumjs-tx');
Expand Down Expand Up @@ -55,7 +63,7 @@ export interface Transaction {
* @property origin - Origin this transaction was sent from
* @property rawTransaction - Hex representation of the underlying transaction
* @property status - String status of this transaction
* @property time - Timestamp associated with this transaction
* @property toSmartContract - Whether transaction recipient is a smart contract
* @property transaction - Underlying Transaction object
* @property transactionHash - Hash of a successful transaction
* @property blockNumber - Number of the block where the transaction has been included
Expand All @@ -71,6 +79,7 @@ export interface TransactionMeta {
rawTransaction?: string;
status: string;
time: number;
toSmartContract?: boolean;
transaction: Transaction;
transactionHash?: string;
blockNumber?: string;
Expand Down Expand Up @@ -552,7 +561,7 @@ export class TransactionController extends BaseController<TransactionConfig, Tra
allTxs.sort((a, b) => (/* istanbul ignore next */ a.time < b.time ? -1 : 1));

let latestIncomingTxBlockNumber: string | undefined;
allTxs.forEach((tx) => {
allTxs.forEach(async (tx) => {
/* istanbul ignore next */
if (
tx.networkID === currentNetworkID &&
Expand All @@ -567,6 +576,16 @@ export class TransactionController extends BaseController<TransactionConfig, Tra
latestIncomingTxBlockNumber = tx.blockNumber;
}
}
/* istanbul ignore else */
if (tx.toSmartContract === undefined) {
// If not `to` is a contract deploy, if not `data` is send eth
if (tx.transaction.to || !tx.transaction.data || tx.transaction.data !== '0x') {
const code = await this.query('getCode', [tx.transaction.to]);
tx.toSmartContract = isSmartContractCode(code);
} else {
tx.toSmartContract = false;
}
}
});

this.update({ transactions: allTxs });
Expand Down
11 changes: 11 additions & 0 deletions src/util.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -362,5 +362,16 @@ describe('util', () => {
)
).not.toThrow();
});

it('should not throw if data is correct', () => {
const toSmartContract1 = util.isSmartContractCode('');
const toSmartContract2 = util.isSmartContractCode('0x');
const toSmartContract3 = util.isSmartContractCode('0x0');
const toSmartContract4 = util.isSmartContractCode('0x01234');
expect(toSmartContract1).toBe(false);
expect(toSmartContract2).toBe(false);
expect(toSmartContract3).toBe(false);
expect(toSmartContract4).toBe(true);
});
});
});
16 changes: 16 additions & 0 deletions src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -257,13 +257,29 @@ export function validateTypedSignMessageDataV3(messageData: TypedMessageParams,
}
}

/**
* Returns wether the given code corresponds to a smart contract
*
* @returns {string} - Corresponding code to review
*/
export function isSmartContractCode(code: string) {
/* istanbul ignore if */
if (!code) {
return false;
}
// Geth will return '0x', and ganache-core v2.2.1 will return '0x0'
const smartContractCode = code !== '0x' && code !== '0x0';
return smartContractCode;
}

export default {
BNToHex,
fractionBN,
getBuyURL,
handleFetch,
hexToBN,
hexToText,
isSmartContractCode,
normalizeTransaction,
safelyExecute,
validateTransaction,
Expand Down

0 comments on commit 7273d9c

Please sign in to comment.