"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 BitcoreClient = __importStar(require("@bitpay-labs/bitcore-client"));
const chai_1 = require("chai");
const crypto_wallet_core_1 = require("@bitpay-labs/crypto-wallet-core");
const sinon_1 = __importDefault(require("sinon"));
const config_1 = __importDefault(require("../../../src/config"));
const cache_1 = require("../../../src/models/cache");
const block_1 = require("../../../src/providers/chain-state/evm/models/block");
const p2p_1 = require("../../../src/providers/chain-state/evm/p2p/p2p");
const api_1 = require("../../../src/services/api");
const utils_1 = require("../../../src/utils");
const helpers_1 = require("../../helpers");
const integration_1 = require("../../helpers/integration");
describe('Polygon', function () {
    // eslint-disable-next-line @typescript-eslint/no-this-alias
    const suite = this;
    this.timeout(50000);
    const sandbox = sinon_1.default.createSandbox();
    const { StreamUtil } = BitcoreClient;
    const chain = 'MATIC';
    const network = 'regtest';
    let chainConfig;
    const name = 'PolygonWallet-Ci';
    const storageType = 'Level';
    const baseUrl = 'http://localhost:3000/api';
    const password = '';
    const phrase = 'glimpse mystery poverty onion muffin twist live kidney unhappy sort frame muffin';
    const accounts = { geth: '0xeC12CD1Ab86F83C1B26C5caa38126Bc4299b6CBa' };
    const privKeys = { geth: '0xf9ad2207e910cd649c9a32063dea3656380c32fa07d6bb9be853687ca585a015' };
    async function getWallet() {
        let wallet;
        try {
            wallet = await BitcoreClient.Wallet.loadWallet({ name, storageType });
            await wallet.register();
            await wallet.syncAddresses();
            return wallet;
        }
        catch (e) {
            console.log('Creating a new matic wallet');
            wallet = await BitcoreClient.Wallet.create({
                name,
                chain,
                network,
                baseUrl,
                password,
                phrase,
                storageType
            });
            await wallet.unlock(password);
            await wallet.nextAddressPair();
            await wallet.lock();
            return wallet;
        }
    }
    async function sendTransaction(from, to, amount, web3, wallet, nonce = 0) {
        if (!wallet) {
            wallet = await getWallet();
        }
        if (!nonce) {
            nonce = await web3.eth.getTransactionCount(accounts[from]);
        }
        const gasPrice = Number(await web3.eth.getGasPrice());
        const tx = await wallet.newTx({ recipients: [{ address: to, amount }], from: accounts[from], nonce, gasLimit: 21000, gasPrice });
        const signedTx = await wallet.signTx({ tx, signingKeys: [{ privKey: privKeys[from] }] });
        await web3.eth.sendSignedTransaction(signedTx);
    }
    before(async function () {
        chainConfig = config_1.default.chains[chain][network];
        await (0, integration_1.intBeforeHelper)();
        await (0, helpers_1.resetDatabase)();
        await api_1.Api.start();
        sandbox.stub(crypto_wallet_core_1.Transactions.get({ chain }), 'getChainId').returns(1337);
    });
    after(async () => {
        await api_1.Api.stop();
        await (0, integration_1.intAfterHelper)(suite);
        sandbox.restore();
    });
    it('should be able to create a wallet with an address', async () => {
        const wallet = await getWallet();
        const addresses = await wallet.getAddresses();
        (0, chai_1.expect)(addresses).to.exist;
        (0, chai_1.expect)(addresses.length).to.eq(1);
        (0, chai_1.expect)(addresses[0].toLowerCase()).to.equal('0xa4e131d8c33fc059e9d245489db03a4a61a2f32b');
    });
    it('should be able to get block events from geth', async () => {
        const { protocol, host, port } = chainConfig.providers[0];
        const getWeb3Stub = sinon_1.default.stub(p2p_1.EVMP2pWorker.prototype, 'getWeb3').resolves({ web3: new crypto_wallet_core_1.Web3(`${protocol}://${host}:${port}`) });
        const wallet = await getWallet();
        const addresses = await wallet.getAddresses();
        const worker = new p2p_1.EVMP2pWorker({ chain, network, chainConfig });
        await worker.setupListeners();
        await worker.connect();
        const sawBlock = new Promise(resolve => worker.events.on('block', resolve));
        const { web3 } = await worker.getWeb3();
        const nonce = Number(await web3.eth.getTransactionCount(accounts['geth']));
        // sending multiple tx to entice geth to mine a block because sometimes it doesn't mine even with automine enabled
        sendTransaction('geth', addresses[0], web3.utils.toWei('.01', 'ether'), web3, wallet, nonce),
            sendTransaction('geth', addresses[0], web3.utils.toWei('.01', 'ether'), web3, wallet, nonce + 1);
        await sawBlock;
        await worker.stop();
        getWeb3Stub.restore();
    });
    it('should be able to get the balance for the address', async () => {
        const wallet = await getWallet();
        const balance = await wallet.getBalance({ hex: true });
        (0, chai_1.expect)(Number(balance.confirmed)).to.be.gt(0);
        const key = 'getBalanceForAddress-MATIC-regtest-0xa4e131d8c33fc059e9d245489db03a4a61a2f32b';
        const cached = await cache_1.CacheStorage.collection.findOne({ key });
        (0, chai_1.expect)(cached).to.exist;
        (0, chai_1.expect)(cached.value).to.deep.eq(balance);
        await wallet.lock();
    });
    it('should update after a send', async () => {
        const wallet = await getWallet();
        const addresses = await wallet.getAddresses();
        const beforeBalance = await wallet.getBalance();
        const worker = new p2p_1.EVMP2pWorker({ chain, network, chainConfig });
        await worker.setupListeners();
        await worker.connect();
        const sawBlock = new Promise(resolve => worker.events.on('block', resolve));
        const { web3 } = await worker.getWeb3();
        await sendTransaction('geth', addresses[0], web3.utils.toWei('.01', 'ether'), web3, wallet);
        await sawBlock;
        await worker.stop();
        const afterBalance = await wallet.getBalance();
        (0, chai_1.expect)(afterBalance).to.not.deep.eq(beforeBalance);
        (0, chai_1.expect)(afterBalance.confirmed).to.be.gt(beforeBalance.confirmed);
        await wallet.lock();
    });
    it('should have receipts on tx history', async () => {
        const wallet = await getWallet();
        await new Promise(r => wallet
            .listTransactions({})
            .pipe(StreamUtil.jsonlBufferToObjectMode())
            .on('data', (tx) => {
            if (tx.height >= 0) {
                (0, chai_1.expect)(tx.receipt).to.exist;
                (0, chai_1.expect)(tx.receipt.gasUsed).to.exist;
                (0, chai_1.expect)(tx.receipt.gasUsed).to.be.lte(tx.gasLimit);
                (0, chai_1.expect)(tx.fee).to.eq(tx.gasPrice * tx.receipt.gasUsed);
            }
        })
            .on('finish', () => {
            r();
        }));
        await wallet.lock();
    });
    it.skip('should be able to save blocks to the database', async () => {
        const wallet = await getWallet();
        const addresses = await wallet.getAddresses();
        const worker = new p2p_1.EVMP2pWorker({ chain, network, chainConfig });
        const done = worker.syncDone();
        const sawBlock = new Promise(resolve => worker.events.on('block', resolve));
        await worker.start();
        await (0, utils_1.wait)(1000);
        const { web3 } = await worker.getWeb3();
        await sendTransaction('geth', addresses[0], web3.utils.toWei('.02', 'ether'), web3, wallet);
        await sawBlock;
        await done;
        await worker.stop();
        const dbBlocks = await block_1.EVMBlockStorage.collection.count({ chain, network });
        (0, chai_1.expect)(dbBlocks).to.be.gt(0);
        await wallet.lock();
    });
    it('should be able to handle reorgs');
    it('should be able to handle a failed getBlock');
    it('should be able to get tx events from parity');
    it('should be able to save transactions to the database');
});
//# sourceMappingURL=p2p.test.js.map