@hyperlane-xyz/sdk
Version:
The official SDK for the Hyperlane Network
153 lines • 6.85 kB
JavaScript
import { expect } from 'chai';
import { errors as EthersError, Wallet, constants } from 'ethers';
import { ERC20__factory } from '@hyperlane-xyz/core';
import { randomAddress } from '../../test/testUtils.js';
import { HyperlaneSmartProvider, getSmartProviderErrorMessage, } from './SmartProvider.js';
const PK = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80';
const NETWORK = 31337;
const URL = 'http://127.0.0.1:8545';
describe('SmartProvider', async () => {
let signer;
let smartProvider;
let contractAddress;
before(async () => {
smartProvider = HyperlaneSmartProvider.fromRpcUrl(NETWORK, URL, {
maxRetries: 3,
});
signer = new Wallet(PK, smartProvider);
});
it('Sends transactions', async () => {
const transferTx = await signer.populateTransaction({
to: signer.address,
value: 1,
});
const signedTx = await signer.signTransaction(transferTx);
const response = await smartProvider.sendTransaction(signedTx);
expect(response.hash.substring(0, 2)).to.equal('0x');
expect(response.hash.length).to.equal(66);
});
it('Deploys contracts', async () => {
const factory = new ERC20__factory(signer);
const contract = await factory.deploy('fake', 'FAKE');
contractAddress = contract.address;
expect(contractAddress.substring(0, 2)).to.equal('0x');
expect(contractAddress.length).to.equal(42);
});
it('Handles multiple requests', async () => {
const [isHealthy, blockNum, block, balance, gasPrice, feeData, code, txCount, network, logs,] = await Promise.all([
smartProvider.isHealthy(),
smartProvider.getBlockNumber(),
smartProvider.getBlock(1),
smartProvider.getBalance(signer.address),
smartProvider.getGasPrice(),
smartProvider.getFeeData(),
smartProvider.getCode(contractAddress),
smartProvider.getTransactionCount(signer.address),
smartProvider.getNetwork(),
smartProvider.getLogs({
fromBlock: 0,
address: constants.AddressZero,
topics: [],
}),
]);
expect(isHealthy).to.be.true;
expect(blockNum).to.greaterThan(0);
expect(block.number).to.equal(1);
expect(balance.toBigInt() > 0).to.be.true;
expect(gasPrice.toBigInt() > 0).to.be.true;
expect(feeData.maxFeePerGas && feeData.maxFeePerGas.toBigInt() > 0).to.be
.true;
expect(code.length).to.greaterThan(10);
expect(txCount).to.be.greaterThan(0);
expect(network.chainId).to.equal(NETWORK);
expect(Array.isArray(logs)).to.be.true;
});
it('throws with invalid RPC', async () => {
const INVALID_URL = 'http://127.0.0.1:33331337';
const INVALID_NETWORK = 55555;
const smartProvider = HyperlaneSmartProvider.fromRpcUrl(INVALID_NETWORK, INVALID_URL);
const signer = new Wallet(PK, smartProvider);
try {
const factory = new ERC20__factory(signer);
await factory.deploy('fake', 'FAKE');
}
catch (e) {
expect(e.cause.code).to.equal('SERVER_ERROR');
expect(e.message).to.equal(getSmartProviderErrorMessage(EthersError.SERVER_ERROR));
}
});
it('throws with multiple invalid RPCs', async () => {
const INVALID_URL_1 = 'http://127.0.0.1:33331337';
const INVALID_URL_2 = 'http://127.0.0.1:23331337';
const INVALID_NETWORK = 55555;
const smartProvider = new HyperlaneSmartProvider(INVALID_NETWORK, [{ http: INVALID_URL_1 }, { http: INVALID_URL_2 }], []);
const signer = new Wallet(PK, smartProvider);
try {
const factory = new ERC20__factory(signer);
await factory.deploy('fake', 'FAKE');
}
catch (e) {
expect(e.cause.code).to.equal('SERVER_ERROR');
expect(e.message).to.equal(getSmartProviderErrorMessage(EthersError.SERVER_ERROR));
}
});
it('handles invalid and valid RPCs', async () => {
const INVALID_URL = 'http://127.0.0.1:33331337';
const smartProvider = new HyperlaneSmartProvider(NETWORK, [{ http: INVALID_URL }, { http: URL }], [], {
maxRetries: 3,
});
const signer = new Wallet(PK, smartProvider);
const factory = new ERC20__factory(signer);
const erc20 = await factory.deploy('fake', 'FAKE');
expect(erc20.address).to.not.be.empty;
});
it('returns the blockchain error reason: "ERC20: transfer to zero address"', async () => {
const smartProvider = HyperlaneSmartProvider.fromRpcUrl(NETWORK, URL, {
maxRetries: 1,
});
const signer = new Wallet(PK, smartProvider);
const factory = new ERC20__factory(signer);
const token = await factory.deploy('fake', 'FAKE');
try {
await token.transfer(constants.AddressZero, 1000000);
}
catch (e) {
expect(e.error.cause.code).to.equal(EthersError.UNPREDICTABLE_GAS_LIMIT);
expect(e.error.message).to.equal('execution reverted: ERC20: transfer to the zero address');
}
});
it('returns the blockchain error reason: "ERC20: transfer amount exceeds balance"', async () => {
const smartProvider = HyperlaneSmartProvider.fromRpcUrl(NETWORK, URL, {
maxRetries: 1,
});
const signer = new Wallet(PK, smartProvider);
const factory = new ERC20__factory(signer);
const token = await factory.deploy('fake', 'FAKE');
try {
await token.transfer(signer.address, 1000000);
}
catch (e) {
expect(e.error.cause.code).to.equal(EthersError.UNPREDICTABLE_GAS_LIMIT);
expect(e.error.message).to.equal('execution reverted: ERC20: transfer amount exceeds balance');
}
});
it('returns the blockchain error reason: "insufficient funds for intrinsic transaction cost"', async () => {
const smartProvider = HyperlaneSmartProvider.fromRpcUrl(NETWORK, URL, {
maxRetries: 1,
});
const signer = new Wallet(PK, smartProvider);
try {
const balance = await signer.getBalance();
// sendTransaction uses the Provider (SmartProvider in this case)
await signer.sendTransaction({
to: randomAddress(),
value: balance.add(1),
});
}
catch (e) {
expect(e.cause.code).to.equal(EthersError.INSUFFICIENT_FUNDS);
expect(e.message).to.equal('insufficient funds for intrinsic transaction cost');
}
});
});
//# sourceMappingURL=SmartProvider.foundry-test.js.map