UNPKG

bitcore-node

Version:

A blockchain indexing node with extended capabilities using bitcore

402 lines 17.4 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const bson_1 = require("bson"); const chai_1 = require("chai"); const sinon = __importStar(require("sinon")); const stream_1 = require("stream"); const web3_1 = __importDefault(require("web3")); const cache_1 = require("../../../src/models/cache"); const wallet_1 = require("../../../src/models/wallet"); const walletAddress_1 = require("../../../src/models/walletAddress"); const csp_1 = require("../../../src/modules/matic/api/csp"); const block_1 = require("../../../src/providers/chain-state/evm/models/block"); const transaction_1 = require("../../../src/providers/chain-state/evm/models/transaction"); const integration_1 = require("../../helpers/integration"); describe('Polygon/MATIC API', function () { const chain = 'MATIC'; const network = 'regtest'; const suite = this; this.timeout(30000); before(integration_1.intBeforeHelper); after(async () => (0, integration_1.intAfterHelper)(suite)); it('should return undefined for garbage data', () => { const data = 'garbage'; const decoded = transaction_1.EVMTransactionStorage.abiDecode(data); (0, chai_1.expect)(decoded).to.be.undefined; }); it('should be able to classify ERC20 data', () => { const data = '0x095ea7b300000000000000000000000052de8d3febd3a06d3c627f59d56e6892b80dcf1200000000000000000000000000000000000000000000000000000000000f4240'; transaction_1.EVMTransactionStorage.abiDecode(data); const decoded = transaction_1.EVMTransactionStorage.abiDecode(data); (0, chai_1.expect)(decoded).to.exist; (0, chai_1.expect)(decoded.type).to.eq('ERC20'); }); it('should be able to classify ERC721 data', () => { const data = '0xa22cb465000000000000000000000000efc70a1b18c432bdc64b596838b4d138f6bc6cad0000000000000000000000000000000000000000000000000000000000000001'; const decoded = transaction_1.EVMTransactionStorage.abiDecode(data); (0, chai_1.expect)(decoded).to.exist; (0, chai_1.expect)(decoded.type).to.eq('ERC721'); }); it('should be able to classify Invoice data', () => { const data = '0xb6b4af0500000000000000000000000000000000000000000000000000000000000f4240000000000000000000000000000000000000000000000000000000033ec500800000000000000000000000000000000000000000000000000000016e00f7b3d3c72c929edaf203cfabf7a0513cb8cee277a84ec3fd56bcf3f396b6d665c8abe6c4432f916bacafc94982b45050513de2ee5544aa855d9b5b60e8c1c94e71ffca000000000000000000000000000000000000000000000000000000000000001cfd9150848849c7aff74939535afe5e56dcac5f2f553467ae0e9181d14c0e49c9799433220e288e282376b86aae1bc1d683af4708b38999d59b5d65ff29a85705000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'; const decoded = transaction_1.EVMTransactionStorage.abiDecode(data); (0, chai_1.expect)(decoded).to.exist; (0, chai_1.expect)(decoded.type).to.eq('INVOICE'); }); it('should handle multiple decodes', () => { const data = '0x095ea7b300000000000000000000000052de8d3febd3a06d3c627f59d56e6892b80dcf1200000000000000000000000000000000000000000000000000000000000f4240'; transaction_1.EVMTransactionStorage.abiDecode(data); const decoded = transaction_1.EVMTransactionStorage.abiDecode(data); (0, chai_1.expect)(decoded).to.exist; (0, chai_1.expect)(decoded.type).to.eq('ERC20'); const data2 = '0xa22cb465000000000000000000000000efc70a1b18c432bdc64b596838b4d138f6bc6cad0000000000000000000000000000000000000000000000000000000000000001'; transaction_1.EVMTransactionStorage.abiDecode(data); const decoded2 = transaction_1.EVMTransactionStorage.abiDecode(data2); (0, chai_1.expect)(decoded2).to.exist; (0, chai_1.expect)(decoded2.type).to.eq('ERC721'); }); it('should not crash when called with almost correct data', () => { const data = '0xa9059cbb0000000000000000000000000797350000000000000000000000000000000000000000000005150ac4c39a6f3f0000'; const decoded = transaction_1.EVMTransactionStorage.abiDecode(data); (0, chai_1.expect)(decoded).to.be.undefined; }); it('should be able to get the fees', async () => { const chain = 'MATIC'; const network = 'testnet'; let target = 1; while (target <= 4) { const cacheKey = `getFee-${chain}-${network}-${target}`; const fee = await csp_1.MATIC.getFee({ chain, network, target }); (0, chai_1.expect)(fee).to.exist; const cached = await cache_1.CacheStorage.getGlobal(cacheKey); (0, chai_1.expect)(fee).to.deep.eq(cached); target++; } }); it('should estimate fees by most recent transactions', async () => { const chain = 'MATIC'; const network = 'testnet'; const txs = new Array(4000).fill({}).map(_ => { return { chain, network, blockHeight: 1, gasPrice: 10 * 1e9 }; }); await cache_1.CacheStorage.collection.remove({}); await transaction_1.EVMTransactionStorage.collection.deleteMany({}); await transaction_1.EVMTransactionStorage.collection.insertMany(txs); const estimates = await Promise.all([1, 2, 3, 4].map(target => csp_1.MATIC.getFee({ network, target }))); for (const estimate of estimates) { (0, chai_1.expect)(estimate.feerate).to.be.gt(0); (0, chai_1.expect)(estimate.feerate).to.be.eq(10000000000); } }); it('should return cached fee for a minute', async () => { const chain = 'MATIC'; const network = 'testnet'; const txs = new Array(4000).fill({}).map(_ => { return { chain, network, blockHeight: 1, gasPrice: 10 * 1e9 }; }); await cache_1.CacheStorage.collection.remove({}); await transaction_1.EVMTransactionStorage.collection.deleteMany({}); await transaction_1.EVMTransactionStorage.collection.insertMany(txs); let estimates = await Promise.all([1, 2, 3, 4].map(target => csp_1.MATIC.getFee({ network, target }))); await transaction_1.EVMTransactionStorage.collection.deleteMany({}); estimates = await Promise.all([1, 2, 3, 4].map(target => csp_1.MATIC.getFee({ network, target }))); for (const estimate of estimates) { (0, chai_1.expect)(estimate.feerate).to.be.gt(0); (0, chai_1.expect)(estimate.feerate).to.be.eq(10000000000); } }); it('should be able to get address token balance', async () => { const sandbox = sinon.createSandbox(); const address = '0xb8fd14fb0e0848cb931c1e54a73486c4b968be3d'; const token = { name: 'Test Token', decimals: 10, symbol: 'TST' }; const tokenStub = { methods: { name: () => ({ call: sandbox.stub().resolves(token.name) }), decimals: () => ({ call: sandbox.stub().resolves(token.decimals) }), symbol: () => ({ call: sandbox.stub().resolves(token.symbol) }), balanceOf: () => ({ call: sandbox.stub().resolves(0) }) } }; sandbox.stub(csp_1.MATIC, 'erc20For').resolves(tokenStub); const balance = await csp_1.MATIC.getBalanceForAddress({ chain, network, address, args: { tokenAddress: address } }); (0, chai_1.expect)(balance).to.deep.eq({ confirmed: 0, unconfirmed: 0, balance: 0 }); sandbox.restore(); }); it('should be able to get address MATIC balance', async () => { const address = '0xb8fd14fb0e0848cb931c1e54a73486c4b968be3d'; const balance = await csp_1.MATIC.getBalanceForAddress({ chain, network, address, args: {} }); (0, chai_1.expect)(balance).to.deep.eq({ confirmed: 0, unconfirmed: 0, balance: 0 }); }); it('should stream MATIC transactions for address', async () => { const address = '0xb8fd14fb0e0848cb931c1e54a73486c4b968be3d'; const txCount = 100; const txs = new Array(txCount).fill({}).map(() => { return { chain, network, blockHeight: 1, gasPrice: 10 * 1e9, data: Buffer.from(''), from: address }; }); await transaction_1.EVMTransactionStorage.collection.deleteMany({}); await transaction_1.EVMTransactionStorage.collection.insertMany(txs); const res = new stream_1.Transform({ transform: (data, _, cb) => cb(null, data) }); res.type = () => res; const req = new stream_1.Transform({ transform: (_data, _, cb) => cb(null) }); await csp_1.MATIC.streamAddressTransactions({ chain, network, address, res, req, args: {} }); let counter = 0; await new Promise(r => { res .on('data', () => counter++) .on('end', r); }); const commaCount = txCount - 1; const bracketCount = 2; const expected = txCount + commaCount + bracketCount; (0, chai_1.expect)(counter).to.eq(expected); }); it('should stream MATIC transactions for block', async () => { const txCount = 100; const txs = new Array(txCount).fill({}).map(() => { return { chain, network, blockHeight: 1, gasPrice: 10 * 1e9, data: Buffer.from('') }; }); await transaction_1.EVMTransactionStorage.collection.deleteMany({}); await transaction_1.EVMTransactionStorage.collection.insertMany(txs); const res = new stream_1.Transform({ transform: (data, _, cb) => { cb(null, data); } }); res.type = () => res; const req = new stream_1.Transform({ transform: (_data, _, cb) => { cb(null); } }); await csp_1.MATIC.streamTransactions({ chain, network, res, req, args: { blockHeight: 1 } }); let counter = 0; await new Promise(r => { res .on('data', () => { counter++; }) .on('end', () => { r(); }); }); const commaCount = txCount - 1; const bracketCount = 2; const expected = txCount + commaCount + bracketCount; (0, chai_1.expect)(counter).to.eq(expected); }); it('should stream MATIC transactions for blockHash', async () => { const txCount = 100; const txs = new Array(txCount).fill({}).map(() => { return { chain, network, blockHash: '12345', gasPrice: 10 * 1e9, data: Buffer.from('') }; }); await transaction_1.EVMTransactionStorage.collection.deleteMany({}); await transaction_1.EVMTransactionStorage.collection.insertMany(txs); const res = new stream_1.Transform({ transform: (data, _, cb) => { cb(null, data); } }); res.type = () => res; const req = new stream_1.Transform({ transform: (_data, _, cb) => { cb(null); } }); await csp_1.MATIC.streamTransactions({ chain, network, res, req, args: { blockHash: '12345' } }); let counter = 0; await new Promise(r => { res .on('data', () => { counter++; }) .on('end', () => { r(); }); }); const commaCount = txCount - 1; const bracketCount = 2; const expected = txCount + commaCount + bracketCount; (0, chai_1.expect)(counter).to.eq(expected); }); describe('#streamWalletTransactions', () => { let sandbox = sinon.createSandbox(); let chain = 'MATIC'; let network = 'mainnet'; let address = '0x1Eee23160Db790ee48Fd39871A64b13e76Fc2C3C'; let wallet = { chain, network, pubKey: '', name: 'this-name', singleAddress: false, path: 'm/0/0' }; let web3 = new web3_1.default(); before(async () => { const res = await wallet_1.WalletStorage.collection.findOneAndUpdate({ name: wallet.name }, { $set: wallet }, { returnOriginal: false, upsert: true }); wallet = res.value; await walletAddress_1.WalletAddressStorage.collection.updateOne({ network, address }, { $set: { chain, network, wallet: wallet._id, processed: true, address } }, { upsert: true }); sandbox.stub(csp_1.MATIC, 'getWeb3').resolves({ web3 }); }); afterEach(async () => { await block_1.EVMBlockStorage.collection.deleteMany({}); await transaction_1.EVMTransactionStorage.collection.deleteMany({}); }); after(async () => { sandbox.restore(); }); it('should stream wallet\'s valid MATIC transactions', async () => await streamWalletTransactionsTest(chain, network)); it('should stream wallet\'s valid & invalid MATIC transactions', async () => await streamWalletTransactionsTest(chain, network, true)); }); }); const streamWalletTransactionsTest = async (chain, network, includeInvalidTxs = false) => { const sandbox = sinon.createSandbox(); // Constants const address = '0x7F17aF79AABC4A297A58D389ab5905fEd4Ec9502'; const objectId = bson_1.ObjectId.createFromHexString('60f9abed0e32086bf9903bb5'); const wallet = { _id: objectId, chain, network, name: 'Ganache', pubKey: '0x029ec2ebdebe6966259cf3c6f35c4f126b82fe072bf9d0e81dad375f1d6d2d9054', path: 'm/44\'/60\'/0\'/0/0', singleAddress: true }; const txCount = 100; // Valid Transactions const txs = new Array(txCount).fill({}).map(() => { return { chain, network, blockHeight: 1, gasPrice: 10 * 1e9, data: Buffer.from(''), from: address }; }); // Invalid Transactions for (let i = 0; i < txCount; i++) { txs.push({ ...txs[0], blockHeight: -3 }); } // Add wallet object ID to transactions for (const tx of txs) { tx.wallets = [objectId]; } // Stubs sandbox.stub(csp_1.MATIC, 'getWalletAddresses').resolves([address]); sandbox.stub(csp_1.MATIC, 'isP2p').returns(true); // Test await transaction_1.EVMTransactionStorage.collection.deleteMany({}); await transaction_1.EVMTransactionStorage.collection.insertMany(txs); let counter = 0; const req = new stream_1.Writable({ write: function (data, _, cb) { data && counter++; cb(); } }); const res = new stream_1.Writable({ write: function (data, _, cb) { data && counter++; cb(); } }); res.type = () => res; const err = await new Promise(r => { res .on('error', r) .on('finish', r); csp_1.MATIC.streamWalletTransactions({ chain, network, wallet, req, res, args: { includeInvalidTxs } }) .catch(e => r(e)); }); (0, chai_1.expect)(err).to.not.exist; (0, chai_1.expect)(counter).to.eq(includeInvalidTxs ? txCount * 2 : txCount); sandbox.restore(); }; //# sourceMappingURL=csp.spec.js.map