UNPKG

@hyperlane-xyz/sdk

Version:

The official SDK for the Hyperlane Network

144 lines 7.14 kB
import chai, { expect } from 'chai'; import chaiAsPromised from 'chai-as-promised'; import { ethers } from 'ethers'; import hre from 'hardhat'; import { ERC20Test__factory } from '@hyperlane-xyz/core'; import { assert } from '@hyperlane-xyz/utils'; import { TestChainName } from '../../consts/testChains.js'; import { MultiProvider } from '../../providers/MultiProvider.js'; import { randomAddress, randomInt } from '../../test/testUtils.js'; import { getContractCreationBlockFromRpc, getLogsFromRpc } from './utils.js'; chai.use(chaiAsPromised); describe('RPC Utils', () => { let contractOwner; let tokenRecipient1; let tokenRecipient2; let providerChainTest1; let multiProvider; let testContract; let erc20Factory; let deploymentBlockNumber; const transferTopic = ethers.utils.id('Transfer(address,address,uint256)'); beforeEach(async () => { [contractOwner, tokenRecipient1, tokenRecipient2] = await hre.ethers.getSigners(); assert(contractOwner.provider, 'Expected provider to be defined on the signer'); // Initialize MultiProvider with test chain multiProvider = MultiProvider.createTestMultiProvider({ signer: contractOwner, provider: contractOwner.provider, }); providerChainTest1 = contractOwner.provider; // Get contract factory for ERC20Test erc20Factory = new ERC20Test__factory(contractOwner); }); async function deployTestErc20() { testContract = await erc20Factory.deploy('TestToken', 'TST', ethers.utils.parseEther('1000000'), 18); await testContract.deployed(); assert(testContract.deployTransaction.blockNumber, 'Expected the Contract deployment block number to be defined'); deploymentBlockNumber = testContract.deployTransaction.blockNumber; } async function mineRandomNumberOfBlocks() { const blocksToMine = randomInt(69, 420); for (let blockNum = 0; blockNum < blocksToMine; blockNum++) { await providerChainTest1.send('evm_mine', []); } } describe(getContractCreationBlockFromRpc.name, () => { it('should find the correct deployment block for a deployed contract', async () => { await mineRandomNumberOfBlocks(); await deployTestErc20(); await mineRandomNumberOfBlocks(); const foundBlock = await getContractCreationBlockFromRpc(TestChainName.test1, testContract.address, multiProvider); expect(foundBlock).to.equal(deploymentBlockNumber); const contractCode = await providerChainTest1.getCode(testContract.address); expect(contractCode).not.to.equal('0x'); }); it('should throw an error for non-existing contract address', async () => { const nonExistentAddress = randomAddress(); await expect(getContractCreationBlockFromRpc(TestChainName.test1, nonExistentAddress, multiProvider)).to.be.rejectedWith(`Address "${nonExistentAddress}" on chain "${TestChainName.test1}" is not a contract`); }); }); describe(getLogsFromRpc.name, () => { beforeEach(async () => { await deployTestErc20(); }); it('should retrieve logs for Transfer events emitted by the contract', async () => { // Emit some Transfer events const tx1 = await testContract.transfer(tokenRecipient1.address, ethers.utils.parseEther('100')); await tx1.wait(); const tx2 = await testContract.transfer(tokenRecipient2.address, ethers.utils.parseEther('200')); await tx2.wait(); const logs = await getLogsFromRpc({ chain: TestChainName.test1, contractAddress: testContract.address, multiProvider, fromBlock: deploymentBlockNumber, topic: transferTopic, }); // Should have 3 transfer events: 1 from constructor mint + 2 from transfers expect(logs).to.have.length(3); logs.forEach((log) => { expect(log.address).to.equal(testContract.address); expect(log.topics[0]).to.equal(transferTopic); }); }); it('should work when fromBlock and toBlock are provided', async () => { await mineRandomNumberOfBlocks(); const startBlock = await providerChainTest1.getBlockNumber(); // Emit event in first block const tx1 = await testContract.transfer(tokenRecipient1.address, ethers.utils.parseEther('100')); await tx1.wait(); const firstEventBlock = await providerChainTest1.getBlockNumber(); await mineRandomNumberOfBlocks(); // Emit event in later block const tx2 = await testContract.transfer(tokenRecipient1.address, ethers.utils.parseEther('200')); await tx2.wait(); // Query only the first event's block range const logs = await getLogsFromRpc({ chain: TestChainName.test1, contractAddress: testContract.address, multiProvider, fromBlock: startBlock, toBlock: firstEventBlock, topic: transferTopic, }); expect(logs).to.have.length(1); expect(logs[0].blockNumber).to.equal(firstEventBlock); }); it('should work when a custom range parameter is provided', async () => { const numberOfEventsToEmit = randomInt(1, 47); for (let i = 0; i < numberOfEventsToEmit; i++) { const tx = await testContract.mint(ethers.utils.parseEther(`${(i + 1) * 100}`)); await tx.wait(); } // +1 because of the transfer event emitted on contract deployment const expectedNumberOfEvents = numberOfEventsToEmit + 1; const logs = await getLogsFromRpc({ chain: TestChainName.test1, contractAddress: testContract.address, multiProvider, fromBlock: deploymentBlockNumber, topic: transferTopic, // Small range to test chunking range: 2, }); expect(logs).to.have.length(expectedNumberOfEvents); }); it('should return empty array when no logs match the criteria', async () => { // Emitting an event just to be sure that filtering works as expected const tx1 = await testContract.transfer(tokenRecipient1.address, ethers.utils.parseEther('100')); await tx1.wait(); const nonExistentTopic = ethers.utils.id('NonExistentEvent(uint256)'); const logs = await getLogsFromRpc({ chain: TestChainName.test1, contractAddress: testContract.address, multiProvider, fromBlock: deploymentBlockNumber, topic: nonExistentTopic, }); expect(logs).to.have.length(0); }); }); }); //# sourceMappingURL=utils.hardhat-test.js.map