diff --git a/CHANGELOG.md b/CHANGELOG.md index 6623c519f..d02d36d06 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +- [#2104](https://github.com/NibiruChain/nibiru/pull/2074) - chore: update chain IDs + ### Nibiru EVM - [#2119](https://github.com/NibiruChain/nibiru/pull/2119) - fix(evm): Guarantee @@ -90,7 +92,9 @@ needed to include double quotes around the hexadecimal string. - [#2176](https://github.com/NibiruChain/nibiru/pull/2176) - tests(evm): add dirty state tests from code4rena audit - [#2180](https://github.com/NibiruChain/nibiru/pull/2180) - fix(evm): apply gas consumption across the entire EVM codebase at `CallContractWithInput` - [#2183](https://github.com/NibiruChain/nibiru/pull/2183) - fix(evm): bank keeper extension gas meter type -- +- [#2184](https://github.com/NibiruChain/nibiru/pull/2184) - test(evm): e2e tests configuration enhancements +- [#2187](https://github.com/NibiruChain/nibiru/pull/2187) - fix(evm): fix eip55 address encoding + #### Nibiru EVM | Before Audit 2 - 2024-12-06 The codebase went through a third-party [Code4rena diff --git a/app/appconst/appconst.go b/app/appconst/appconst.go index cbf5d8909..25c10dafc 100644 --- a/app/appconst/appconst.go +++ b/app/appconst/appconst.go @@ -53,39 +53,39 @@ func RuntimeVersion() string { // EIP 155 Chain IDs exported for tests. const ( - ETH_CHAIN_ID_MAINNET int64 = 7200 + ETH_CHAIN_ID_MAINNET int64 = 6900 - ETH_CHAIN_ID_TESTNET_1 int64 = 7210 - ETH_CHAIN_ID_TESTNET_2 int64 = 7211 - ETH_CHAIN_ID_TESTNET_3 int64 = 7212 + ETH_CHAIN_ID_TESTNET_1 int64 = 6910 + ETH_CHAIN_ID_TESTNET_2 int64 = 6911 + ETH_CHAIN_ID_TESTNET_3 int64 = 6912 - ETH_CHAIN_ID_DEVNET_1 int64 = 7220 - ETH_CHAIN_ID_DEVNET_2 int64 = 7221 - ETH_CHAIN_ID_DEVNET_3 int64 = 7222 + ETH_CHAIN_ID_DEVNET_1 int64 = 6920 + ETH_CHAIN_ID_DEVNET_2 int64 = 6921 + ETH_CHAIN_ID_DEVNET_3 int64 = 6922 - ETH_CHAIN_ID_LOCALNET_0 int64 = 7230 - ETH_CHAIN_ID_LOCALNET_1 int64 = 7231 - ETH_CHAIN_ID_LOCALNET_2 int64 = 7232 - ETH_CHAIN_ID_LOCALNET_3 int64 = 7233 + ETH_CHAIN_ID_LOCALNET_0 int64 = 6930 + ETH_CHAIN_ID_LOCALNET_1 int64 = 6931 + ETH_CHAIN_ID_LOCALNET_2 int64 = 6932 + ETH_CHAIN_ID_LOCALNET_3 int64 = 6933 - ETH_CHAIN_ID_DEFAULT int64 = 7230 + ETH_CHAIN_ID_DEFAULT int64 = 6930 ) var knownEthChainIDMap = map[string]int64{ - "cataclysm-1": 7200, + "cataclysm-1": 6900, - "nibiru-testnet-1": 7210, - "nibiru-testnet-2": 7211, - "nibiru-testnet-3": 7212, + "nibiru-testnet-1": 6910, + "nibiru-testnet-2": 6911, + "nibiru-testnet-3": 6912, - "nibiru-devnet-1": 7220, - "nibiru-devnet-2": 7221, - "nibiru-devnet-3": 7222, + "nibiru-devnet-1": 6920, + "nibiru-devnet-2": 6921, + "nibiru-devnet-3": 6922, - "nibiru-localnet-0": 7230, - "nibiru-localnet-1": 7231, - "nibiru-localnet-2": 7232, - "nibiru-localnet-3": 7233, + "nibiru-localnet-0": 6930, + "nibiru-localnet-1": 6931, + "nibiru-localnet-2": 6932, + "nibiru-localnet-3": 6933, } // GetEthChainID: Maps the given chain ID from the block's `sdk.Context` to an diff --git a/eth/eip55.go b/eth/eip55.go index 36f781d24..2c801bbea 100644 --- a/eth/eip55.go +++ b/eth/eip55.go @@ -36,7 +36,7 @@ func NewEIP55AddrFromStr(input string) (EIP55Addr, error) { // Marshal implements the gogo proto custom type interface. // Ref: https://github.com/cosmos/gogoproto/blob/v1.5.0/custom_types.md func (h EIP55Addr) Marshal() ([]byte, error) { - return []byte(h.Address.Hex()), nil + return h.Bytes(), nil } // MarshalJSON returns the [EIP55Addr] as JSON bytes. @@ -51,18 +51,15 @@ func (h EIP55Addr) MarshalJSON() ([]byte, error) { // Implements the gogo proto custom type interface. // Ref: https://github.com/cosmos/gogoproto/blob/v1.5.0/custom_types.md func (h *EIP55Addr) MarshalTo(data []byte) (n int, err error) { - copy(data, []byte(h.Address.Hex())) + copy(data, h.Bytes()) return h.Size(), nil } // Unmarshal implements the gogo proto custom type interface. // Ref: https://github.com/cosmos/gogoproto/blob/v1.5.0/custom_types.md func (h *EIP55Addr) Unmarshal(data []byte) error { - addr, err := NewEIP55AddrFromStr(string(data)) - if err != nil { - return err - } - *h = addr + addr := gethcommon.BytesToAddress(data) + *h = EIP55Addr{Address: addr} return nil } @@ -71,9 +68,7 @@ func (h *EIP55Addr) Unmarshal(data []byte) error { func (h *EIP55Addr) UnmarshalJSON(bz []byte) error { var addrStr string if err := json.Unmarshal(bz, &addrStr); err != nil { - return fmt.Errorf( - "EIP55AddrError: UnmarhsalJSON had invalid input %s: %w", bz, err, - ) + return err } addr, err := NewEIP55AddrFromStr(addrStr) if err != nil { @@ -86,5 +81,5 @@ func (h *EIP55Addr) UnmarshalJSON(bz []byte) error { // Size implements the gogo proto custom type interface. // Ref: https://github.com/cosmos/gogoproto/blob/v1.5.0/custom_types.md func (h EIP55Addr) Size() int { - return len([]byte(h.Address.Hex())) + return len(h.Bytes()) } diff --git a/eth/eip55_test.go b/eth/eip55_test.go index a2970e5e2..af56344a4 100644 --- a/eth/eip55_test.go +++ b/eth/eip55_test.go @@ -1,9 +1,9 @@ package eth_test import ( + "encoding/json" "fmt" "strconv" - "strings" "testing" gethcommon "github.com/ethereum/go-ethereum/common" @@ -12,9 +12,9 @@ import ( "github.com/NibiruChain/nibiru/v2/eth" ) -// MustNewEIP55AddrFromStr is the same as [NewEIP55AddrFromStr], except it panics +// mustNewEIP55AddrFromStr is the same as [NewEIP55AddrFromStr], except it panics // when there's an error. -func MustNewEIP55AddrFromStr(input string) eth.EIP55Addr { +func mustNewEIP55AddrFromStr(input string) eth.EIP55Addr { addr, err := eth.NewEIP55AddrFromStr(input) if err != nil { panic(err) @@ -22,15 +22,9 @@ func MustNewEIP55AddrFromStr(input string) eth.EIP55Addr { return addr } -var threeValidAddrs []eth.EIP55Addr = []eth.EIP55Addr{ - MustNewEIP55AddrFromStr("0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"), - MustNewEIP55AddrFromStr("0xAe967917c465db8578ca9024c205720b1a3651A9"), - MustNewEIP55AddrFromStr("0x1111111111111111111112222222222223333323"), -} - func (s *EIP55AddrSuite) TestEquivalence() { expectedGethAddr := gethcommon.HexToAddress("0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed") - expectedEIP55Addr := MustNewEIP55AddrFromStr("0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed") + expectedEIP55Addr := mustNewEIP55AddrFromStr("0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed") equivalentAddrs := []string{ "0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed", @@ -110,54 +104,95 @@ func (s *EIP55AddrSuite) TestNewEIP55Addr() { } } -func (s *EIP55AddrSuite) TestProtobufEncoding() { +func (s *EIP55AddrSuite) TestJsonEncoding() { for tcIdx, tc := range []struct { input eth.EIP55Addr - expectedJson string + expectedJson json.RawMessage wantErr string }{ { - input: threeValidAddrs[0], - expectedJson: `"0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"`, + input: mustNewEIP55AddrFromStr("0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"), + expectedJson: []byte("\"0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed\""), }, { - input: threeValidAddrs[1], - expectedJson: `"0xAe967917c465db8578ca9024c205720b1a3651A9"`, + input: mustNewEIP55AddrFromStr("0xAe967917c465db8578ca9024c205720b1a3651A9"), + expectedJson: []byte("\"0xAe967917c465db8578ca9024c205720b1a3651A9\""), }, { - input: threeValidAddrs[2], - expectedJson: `"0x1111111111111111111112222222222223333323"`, + input: mustNewEIP55AddrFromStr("0x1111111111111111111112222222222223333323"), + expectedJson: []byte("\"0x1111111111111111111112222222222223333323\""), }, } { s.Run(strconv.Itoa(tcIdx), func() { - givenMut := tc.input - jsonBz, err := givenMut.MarshalJSON() - s.NoError(err) - s.Equal(tc.expectedJson, string(jsonBz)) + jsonBz, err := tc.input.MarshalJSON() + s.Require().NoError(err) + s.Require().EqualValues(tc.expectedJson, jsonBz) eip55Addr := new(eth.EIP55Addr) - s.NoError(eip55Addr.UnmarshalJSON(jsonBz)) - s.Equal(givenMut, tc.input, - "Given -> MarshalJSON -> UnmarshalJSON returns a different value than the given when it should be an identity operation (no-op). test case #%d", tcIdx) + s.Require().NoError(eip55Addr.UnmarshalJSON(jsonBz)) + s.Require().EqualValues(tc.input, *eip55Addr) + }) + } +} +func (s *EIP55AddrSuite) TestProtobufEncoding() { + for tcIdx, tc := range []struct { + input eth.EIP55Addr + expectedProtoBz []byte + wantErr string + }{ + { + input: mustNewEIP55AddrFromStr("0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"), + expectedProtoBz: []byte{90, 174, 182, 5, 63, 62, 148, 201, 185, 160, 159, 51, 102, 148, 53, 231, 239, 27, 234, 237}, + }, + { + input: mustNewEIP55AddrFromStr("0xAe967917c465db8578ca9024c205720b1a3651A9"), + expectedProtoBz: []byte{174, 150, 121, 23, 196, 101, 219, 133, 120, 202, 144, 36, 194, 5, 114, 11, 26, 54, 81, 169}, + }, + { + input: mustNewEIP55AddrFromStr("0x1111111111111111111112222222222223333323"), + expectedProtoBz: []byte{17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 34, 34, 34, 34, 34, 35, 51, 51, 35}, + }, + } { + s.Run(strconv.Itoa(tcIdx), func() { bz, err := tc.input.Marshal() - s.NoError(err) - s.Equal(strings.Trim(tc.expectedJson, `"`), string(bz), - "Marshaling to bytes gives different value than the test case specifies. test case #%d", tcIdx) + s.Require().NoError(err) + s.Require().EqualValues(tc.expectedProtoBz, bz) - err = eip55Addr.Unmarshal(bz) - s.NoError(err) - s.Equal(tc.input.Address, eip55Addr.Address, - "Given -> Marshal -> Unmarshal returns a different value than the given when it should be an identity operation (no-op). test case #%d", tcIdx) + eip55Addr := new(eth.EIP55Addr) + s.Require().NoError(eip55Addr.Unmarshal(bz)) + s.Require().Equal(tc.input.Address, eip55Addr.Address) + }) + } +} - s.Equal(len([]byte(tc.input.Hex())), tc.input.Size()) - s.Equal(len(tc.input.Hex()), tc.input.Size()) +func (s *EIP55AddrSuite) TestSize() { + for idx, tc := range []struct { + input eth.EIP55Addr + expectedSize int + wantErr string + }{ + { + input: mustNewEIP55AddrFromStr("0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"), + expectedSize: 20, + }, + { + input: mustNewEIP55AddrFromStr("0xAe967917c465db8578ca9024c205720b1a3651A9"), + expectedSize: 20, + }, + { + input: mustNewEIP55AddrFromStr("0x1111111111111111111112222222222223333323"), + expectedSize: 20, + }, + } { + s.Run(strconv.Itoa(idx), func() { + s.Require().EqualValues(tc.expectedSize, tc.input.Size()) }) } } // showcases how geth checks for valid hex addresses and treats invalid inputs -func (s *EIP55AddrSuite) TestIsEIP55Address() { +func (s *EIP55AddrSuite) TestHexAddress() { s.True(gethcommon.IsHexAddress("0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed")) s.True(gethcommon.IsHexAddress("0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAED")) s.False(gethcommon.IsHexAddress("0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed1234")) @@ -179,21 +214,20 @@ func TestEIP55AddrSuite(t *testing.T) { func (s *EIP55AddrSuite) TestStringEncoding() { addrHex := "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed" - addr := new(eth.EIP55Addr) - err := addr.Unmarshal([]byte(addrHex)) - s.NoError(err) - s.Equal(addrHex, addr.Address.Hex()) + addr, err := eth.NewEIP55AddrFromStr(addrHex) + s.Require().NoError(err) + s.Require().Equal(addrHex, addr.Address.Hex()) - addrBytes, err := addr.Marshal() - s.NoError(err) - s.Equal(addrHex, string(addrBytes)) + addrBz, err := addr.Marshal() + s.Require().NoError(err) + s.Require().EqualValues(addr.Bytes(), addrBz) bz, err := addr.MarshalJSON() - s.NoError(err) - s.Equal(fmt.Sprintf(`"%s"`, addrHex), string(bz)) + s.Require().NoError(err) + s.Require().Equal(fmt.Sprintf(`"%s"`, addrHex), string(bz)) - addrb := new(eth.EIP55Addr) - err = addrb.UnmarshalJSON([]byte(fmt.Sprintf(`"%s"`, addrHex))) - s.NoError(err) - s.EqualValues(addrb, addr) + newAddr := new(eth.EIP55Addr) + err = newAddr.UnmarshalJSON(bz) + s.Require().NoError(err) + s.Require().EqualValues(addrHex, newAddr.Hex()) } diff --git a/evm-e2e/.env_sample b/evm-e2e/.env_sample index 98bebd6b2..f0492b948 100644 --- a/evm-e2e/.env_sample +++ b/evm-e2e/.env_sample @@ -1,2 +1,4 @@ JSON_RPC_ENDPOINT="http://127.0.0.1:8545" MNEMONIC="guard cream sadness conduct invite crumble clock pudding hole grit liar hotel maid produce squeeze return argue turtle know drive eight casino maze host" +TEST_TIMEOUT=15000 +TX_WAIT_TIMEOUT=5000 diff --git a/evm-e2e/test/contract_infinite_loop_gas.test.ts b/evm-e2e/test/contract_infinite_loop_gas.test.ts index 6508e0dce..ac1350811 100644 --- a/evm-e2e/test/contract_infinite_loop_gas.test.ts +++ b/evm-e2e/test/contract_infinite_loop_gas.test.ts @@ -1,21 +1,26 @@ import { describe, expect, it } from '@jest/globals'; import { toBigInt } from 'ethers'; import { deployContractInfiniteLoopGas } from './utils'; +import { TEST_TIMEOUT } from './setup'; describe('Infinite loop gas contract', () => { - it('should fail due to out of gas error', async () => { - const contract = await deployContractInfiniteLoopGas(); + it( + 'should fail due to out of gas error', + async () => { + const contract = await deployContractInfiniteLoopGas(); - expect(contract.counter()).resolves.toBe(toBigInt(0)); + await expect(contract.counter()).resolves.toBe(toBigInt(0)); - try { - const tx = await contract.forever({ gasLimit: 1e6 }); - await tx.wait(); - throw new Error('The transaction should have failed but did not.'); - } catch (error) { - expect(error.message).toContain('transaction execution reverted'); - } + try { + const tx = await contract.forever({ gasLimit: 1e6 }); + await tx.wait(); + throw new Error('The transaction should have failed but did not.'); + } catch (error) { + expect(error.message).toContain('transaction execution reverted'); + } - expect(contract.counter()).resolves.toBe(toBigInt(0)); - }, 20e3); + await expect(contract.counter()).resolves.toBe(toBigInt(0)); + }, + TEST_TIMEOUT, + ); }); diff --git a/evm-e2e/test/contract_send_nibi.test.ts b/evm-e2e/test/contract_send_nibi.test.ts index fa474b434..da322fba8 100644 --- a/evm-e2e/test/contract_send_nibi.test.ts +++ b/evm-e2e/test/contract_send_nibi.test.ts @@ -11,7 +11,7 @@ */ import { describe, expect, it } from '@jest/globals'; import { parseEther, toBigInt, Wallet } from 'ethers'; -import { account, provider } from './setup'; +import { account, provider, TEST_TIMEOUT, TX_WAIT_TIMEOUT } from './setup'; import { deployContractSendNibi } from './utils'; async function testSendNibi(method: 'sendViaTransfer' | 'sendViaSend' | 'sendViaCall', weiToSend: bigint) { @@ -23,7 +23,7 @@ async function testSendNibi(method: 'sendViaTransfer' | 'sendViaSend' | 'sendVia expect(recipientBalanceBefore).toEqual(BigInt(0)); const tx = await contract[method](recipient, { value: weiToSend }); - const receipt = await tx.wait(1, 5e3); + const receipt = await tx.wait(1, TX_WAIT_TIMEOUT); const tenPow12 = toBigInt(1e12); const txCostMicronibi = weiToSend / tenPow12 + receipt.gasUsed; @@ -52,14 +52,13 @@ async function testSendNibi(method: 'sendViaTransfer' | 'sendViaSend' | 'sendVia } describe('Send NIBI via smart contract', () => { - const TIMEOUT_MS = 20e3; it( 'method sendViaTransfer', async () => { const weiToSend: bigint = toBigInt(5e12) * toBigInt(1e6); await testSendNibi('sendViaTransfer', weiToSend); }, - TIMEOUT_MS, + TEST_TIMEOUT, ); it( @@ -68,7 +67,7 @@ describe('Send NIBI via smart contract', () => { const weiToSend: bigint = toBigInt(100e12) * toBigInt(1e6); await testSendNibi('sendViaSend', weiToSend); }, - TIMEOUT_MS, + TEST_TIMEOUT, ); it( @@ -77,6 +76,6 @@ describe('Send NIBI via smart contract', () => { const weiToSend: bigint = toBigInt(100e12) * toBigInt(1e6); await testSendNibi('sendViaCall', weiToSend); }, - TIMEOUT_MS, + TEST_TIMEOUT, ); }); diff --git a/evm-e2e/test/debug_queries.test.ts b/evm-e2e/test/debug_queries.test.ts index e58901c31..3c6468504 100644 --- a/evm-e2e/test/debug_queries.test.ts +++ b/evm-e2e/test/debug_queries.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it, beforeAll } from '@jest/globals'; import { TransactionReceipt, parseEther } from 'ethers'; -import { provider } from './setup'; +import { provider, TEST_TIMEOUT, TX_WAIT_TIMEOUT } from './setup'; import { alice, deployContractTestERC20, hexify } from './utils'; import { TestERC20__factory } from '../types'; @@ -18,14 +18,14 @@ describe('debug queries', () => { // Execute some contract TX const txResponse = await contract.transfer(alice, parseEther('0.01')); - await txResponse.wait(1, 5e3); + await txResponse.wait(1, TX_WAIT_TIMEOUT); const receipt: TransactionReceipt = await provider.getTransactionReceipt(txResponse.hash); txHash = txResponse.hash; txIndex = txResponse.index; blockNumber = receipt.blockNumber; blockHash = receipt.blockHash; - }, 20e3); + }, TEST_TIMEOUT); it('debug_traceBlockByNumber', async () => { const traceResult = await provider.send('debug_traceBlockByNumber', [ diff --git a/evm-e2e/test/erc20.test.ts b/evm-e2e/test/erc20.test.ts index 1405253ea..573f23d20 100644 --- a/evm-e2e/test/erc20.test.ts +++ b/evm-e2e/test/erc20.test.ts @@ -1,25 +1,29 @@ import { describe, expect, it } from '@jest/globals'; import { parseUnits, toBigInt, Wallet } from 'ethers'; -import { account } from './setup'; +import { account, TEST_TIMEOUT } from './setup'; import { deployContractTestERC20 } from './utils'; describe('ERC-20 contract tests', () => { - it('should send properly', async () => { - const contract = await deployContractTestERC20(); - expect(contract.getAddress()).resolves.toBeDefined(); + it( + 'should send properly', + async () => { + const contract = await deployContractTestERC20(); + expect(contract.getAddress()).resolves.toBeDefined(); - const ownerInitialBalance = parseUnits('1000000', 18); - const alice = Wallet.createRandom(); + const ownerInitialBalance = parseUnits('1000000', 18); + const alice = Wallet.createRandom(); - expect(contract.balanceOf(account)).resolves.toEqual(ownerInitialBalance); - expect(contract.balanceOf(alice)).resolves.toEqual(toBigInt(0)); + expect(contract.balanceOf(account)).resolves.toEqual(ownerInitialBalance); + expect(contract.balanceOf(alice)).resolves.toEqual(toBigInt(0)); - // send to alice - const amountToSend = parseUnits('1000', 18); // contract tokens - let tx = await contract.transfer(alice, amountToSend); - await tx.wait(); + // send to alice + const amountToSend = parseUnits('1000', 18); // contract tokens + let tx = await contract.transfer(alice, amountToSend); + await tx.wait(); - expect(contract.balanceOf(account)).resolves.toEqual(ownerInitialBalance - amountToSend); - expect(contract.balanceOf(alice)).resolves.toEqual(amountToSend); - }, 20e3); + expect(contract.balanceOf(account)).resolves.toEqual(ownerInitialBalance - amountToSend); + expect(contract.balanceOf(alice)).resolves.toEqual(amountToSend); + }, + TEST_TIMEOUT, + ); }); diff --git a/evm-e2e/test/eth_queries.test.ts b/evm-e2e/test/eth_queries.test.ts index 13bcb13a0..fc8ccac0b 100644 --- a/evm-e2e/test/eth_queries.test.ts +++ b/evm-e2e/test/eth_queries.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it, jest } from '@jest/globals'; -import { parseEther, keccak256, AbiCoder } from 'ethers'; -import { account, provider } from './setup'; +import { parseEther, keccak256, AbiCoder, ethers } from 'ethers'; +import { account, provider, TEST_TIMEOUT, TX_WAIT_TIMEOUT } from './setup'; import { INTRINSIC_TX_GAS, alice, @@ -8,14 +8,15 @@ import { deployContractSendNibi, hexify, sendTestNibi, + numberToHex, } from './utils'; describe('eth queries', () => { - jest.setTimeout(15e3); + jest.setTimeout(TEST_TIMEOUT); it('eth_accounts', async () => { const accounts = await provider.listAccounts(); - expect(accounts).not.toHaveLength(0); + expect(accounts).not.toBeNull(); }); it('eth_estimateGas', async () => { @@ -54,7 +55,7 @@ describe('eth queries', () => { }); it('eth_getBlockByNumber, eth_getBlockByHash', async () => { - const blockNumber = 1; + const blockNumber = 'latest'; const blockByNumber = await provider.send('eth_getBlockByNumber', [blockNumber, false]); expect(blockByNumber).toBeDefined(); expect(blockByNumber).toHaveProperty('hash'); @@ -66,14 +67,14 @@ describe('eth queries', () => { }); it('eth_getBlockTransactionCountByHash', async () => { - const blockNumber = 1; + const blockNumber = 'latest'; const block = await provider.send('eth_getBlockByNumber', [blockNumber, false]); const txCount = await provider.send('eth_getBlockTransactionCountByHash', [block.hash]); expect(parseInt(txCount)).toBeGreaterThanOrEqual(0); }); it('eth_getBlockTransactionCountByNumber', async () => { - const blockNumber = 1; + const blockNumber = 'latest'; const txCount = await provider.send('eth_getBlockTransactionCountByNumber', [blockNumber]); expect(parseInt(txCount)).toBeGreaterThanOrEqual(0); }); @@ -86,11 +87,12 @@ describe('eth queries', () => { }); it('eth_getFilterChanges', async () => { + const currentBlock = await provider.getBlockNumber(); // Deploy ERC-20 contract const contract = await deployContractTestERC20(); const contractAddr = await contract.getAddress(); const filter = { - fromBlock: '0x1', + fromBlock: numberToHex(currentBlock), address: contractAddr, }; // Create the filter for a contract @@ -99,7 +101,7 @@ describe('eth queries', () => { // Execute some contract TX const tx = await contract.transfer(alice, parseEther('0.01')); - await tx.wait(1, 5e3); + await tx.wait(1, TX_WAIT_TIMEOUT); await new Promise((resolve) => setTimeout(resolve, 3000)); // Assert logs @@ -114,16 +116,17 @@ describe('eth queries', () => { }); it('eth_getFilterLogs', async () => { + const currentBlock = await provider.getBlockNumber(); // Deploy ERC-20 contract const contract = await deployContractTestERC20(); const contractAddr = await contract.getAddress(); const filter = { - fromBlock: '0x1', + fromBlock: numberToHex(currentBlock), address: contractAddr, }; // Execute some contract TX const tx = await contract.transfer(alice, parseEther('0.01')); - await tx.wait(1, 5e3); + await tx.wait(1, TX_WAIT_TIMEOUT); await new Promise((resolve) => setTimeout(resolve, 3000)); // Create the filter for a contract @@ -139,16 +142,17 @@ describe('eth queries', () => { }); it('eth_getLogs', async () => { + const currentBlock = await provider.getBlockNumber(); // Deploy ERC-20 contract const contract = await deployContractTestERC20(); const contractAddr = await contract.getAddress(); const filter = { - fromBlock: '0x1', + fromBlock: numberToHex(currentBlock), address: contractAddr, }; // Execute some contract TX const tx = await contract.transfer(alice, parseEther('0.01')); - await tx.wait(1, 5e3); + await tx.wait(1, TX_WAIT_TIMEOUT); await new Promise((resolve) => setTimeout(resolve, 3000)); // Assert logs diff --git a/evm-e2e/test/native_transfer.test.ts b/evm-e2e/test/native_transfer.test.ts index 475ab270b..c6c0193f8 100644 --- a/evm-e2e/test/native_transfer.test.ts +++ b/evm-e2e/test/native_transfer.test.ts @@ -1,45 +1,49 @@ import { describe, expect, it } from '@jest/globals'; import { parseEther, toBigInt } from 'ethers'; -import { account, provider } from './setup'; +import { account, provider, TEST_TIMEOUT, TX_WAIT_TIMEOUT } from './setup'; import { alice } from './utils'; describe('native transfer', () => { - it('simple transfer, balance check', async () => { - const amountToSend = toBigInt(5e12) * toBigInt(1e6); // unibi - const senderBalanceBefore = await provider.getBalance(account); - const recipientBalanceBefore = await provider.getBalance(alice); - expect(senderBalanceBefore).toBeGreaterThan(0); - expect(recipientBalanceBefore).toEqual(BigInt(0)); + it( + 'simple transfer, balance check', + async () => { + const amountToSend = toBigInt(5e12) * toBigInt(1e6); // unibi + const senderBalanceBefore = await provider.getBalance(account); + const recipientBalanceBefore = await provider.getBalance(alice); + expect(senderBalanceBefore).toBeGreaterThan(0); + expect(recipientBalanceBefore).toEqual(BigInt(0)); - // Execute EVM transfer - const transaction = { - gasLimit: toBigInt(100e3), - to: alice, - value: amountToSend, - }; - const txResponse = await account.sendTransaction(transaction); - await txResponse.wait(1, 10e3); - expect(txResponse).toHaveProperty('blockHash'); + // Execute EVM transfer + const transaction = { + gasLimit: toBigInt(100e3), + to: alice, + value: amountToSend, + }; + const txResponse = await account.sendTransaction(transaction); + await txResponse.wait(1, TX_WAIT_TIMEOUT); + expect(txResponse).toHaveProperty('blockHash'); - const senderBalanceAfter = await provider.getBalance(account); - const recipientBalanceAfter = await provider.getBalance(alice); + const senderBalanceAfter = await provider.getBalance(account); + const recipientBalanceAfter = await provider.getBalance(alice); - // Assert balances with logging - const tenPow12 = toBigInt(1e12); - const gasUsed = transaction.gasLimit; - const txCostMicronibi = amountToSend / tenPow12 + gasUsed; - const txCostWei = txCostMicronibi * tenPow12; - const expectedSenderWei = senderBalanceBefore - txCostWei; - console.debug('DEBUG should send via transfer method %o:', { - senderBalanceBefore, - amountToSend, - expectedSenderWei, - senderBalanceAfter, - txResponse, - }); - expect(recipientBalanceAfter).toEqual(amountToSend); - const delta = senderBalanceAfter - expectedSenderWei; - const deltaFromExpectation = delta >= 0 ? delta : -delta; - expect(deltaFromExpectation).toBeLessThan(parseEther('0.1')); - }, 20e3); + // Assert balances with logging + const tenPow12 = toBigInt(1e12); + const gasUsed = transaction.gasLimit; + const txCostMicronibi = amountToSend / tenPow12 + gasUsed; + const txCostWei = txCostMicronibi * tenPow12; + const expectedSenderWei = senderBalanceBefore - txCostWei; + console.debug('DEBUG should send via transfer method %o:', { + senderBalanceBefore, + amountToSend, + expectedSenderWei, + senderBalanceAfter, + txResponse, + }); + expect(recipientBalanceAfter).toEqual(amountToSend); + const delta = senderBalanceAfter - expectedSenderWei; + const deltaFromExpectation = delta >= 0 ? delta : -delta; + expect(deltaFromExpectation).toBeLessThan(parseEther('0.1')); + }, + TEST_TIMEOUT, + ); }); diff --git a/evm-e2e/test/nibiru_oracle.test.ts b/evm-e2e/test/nibiru_oracle.test.ts index 28a5f05be..5695a60b7 100644 --- a/evm-e2e/test/nibiru_oracle.test.ts +++ b/evm-e2e/test/nibiru_oracle.test.ts @@ -1,40 +1,45 @@ import { expect, test } from '@jest/globals'; import { toBigInt } from 'ethers'; import { deployContractNibiruOracleChainLinkLike } from './utils'; +import { TEST_TIMEOUT } from './setup'; -test('NibiruOracleChainLinkLike implements ChainLink AggregatorV3Interface', async () => { - const { oraclePair, contract } = await deployContractNibiruOracleChainLinkLike(); +test( + 'NibiruOracleChainLinkLike implements ChainLink AggregatorV3Interface', + async () => { + const { oraclePair, contract } = await deployContractNibiruOracleChainLinkLike(); - const oracleAddr = await contract.getAddress(); - expect(oracleAddr).not.toBeFalsy(); + const oracleAddr = await contract.getAddress(); + expect(oracleAddr).not.toBeFalsy(); - const decimals = await contract.decimals(); - expect(decimals).toEqual(BigInt(8)); + const decimals = await contract.decimals(); + expect(decimals).toEqual(BigInt(8)); - const description = await contract.description(); - expect(description).toEqual(`Nibiru Oracle ChainLink-like price feed for ${oraclePair}`); + const description = await contract.description(); + expect(description).toEqual(`Nibiru Oracle ChainLink-like price feed for ${oraclePair}`); - const version = await contract.version(); - expect(version).toEqual(1n); + const version = await contract.version(); + expect(version).toEqual(1n); - // latestRoundData - const genesisEthUsdPrice = 2000n; - { - const { roundId, answer, startedAt, updatedAt, answeredInRound } = await contract.latestRoundData(); - expect(roundId).toEqual(0n); // price is from genesis block - expect(startedAt).toBeGreaterThan(1n); - expect(updatedAt).toBeGreaterThan(1n); - expect(answeredInRound).toEqual(420n); - expect(answer).toEqual(genesisEthUsdPrice * toBigInt(1e8)); - } + // latestRoundData + const genesisEthUsdPrice = 2000n; + { + const { roundId, answer, startedAt, updatedAt, answeredInRound } = await contract.latestRoundData(); + expect(roundId).toEqual(0n); // price is from genesis block + expect(startedAt).toBeGreaterThan(1n); + expect(updatedAt).toBeGreaterThan(1n); + expect(answeredInRound).toEqual(420n); + expect(answer).toEqual(genesisEthUsdPrice * toBigInt(1e8)); + } - // getRoundData - { - const { roundId, answer, startedAt, updatedAt, answeredInRound } = await contract.getRoundData(0n); - expect(roundId).toEqual(0n); // price is from genesis block - expect(startedAt).toBeGreaterThan(1n); - expect(updatedAt).toBeGreaterThan(1n); - expect(answeredInRound).toEqual(420n); - expect(answer).toEqual(genesisEthUsdPrice * toBigInt(1e8)); - } -}); + // getRoundData + { + const { roundId, answer, startedAt, updatedAt, answeredInRound } = await contract.getRoundData(0n); + expect(roundId).toEqual(0n); // price is from genesis block + expect(startedAt).toBeGreaterThan(1n); + expect(updatedAt).toBeGreaterThan(1n); + expect(answeredInRound).toEqual(420n); + expect(answer).toEqual(genesisEthUsdPrice * toBigInt(1e8)); + } + }, + TEST_TIMEOUT, +); diff --git a/evm-e2e/test/setup.ts b/evm-e2e/test/setup.ts index ec2fe24b7..09fdc0784 100644 --- a/evm-e2e/test/setup.ts +++ b/evm-e2e/test/setup.ts @@ -5,5 +5,7 @@ config(); const provider = new ethers.JsonRpcProvider(process.env.JSON_RPC_ENDPOINT); const account = Wallet.fromPhrase(process.env.MNEMONIC, provider); +const TEST_TIMEOUT = Number(process.env.TEST_TIMEOUT) || 15000; +const TX_WAIT_TIMEOUT = Number(process.env.TX_WAIT_TIMEOUT) || 5000; -export { account, provider }; +export { account, provider, TEST_TIMEOUT, TX_WAIT_TIMEOUT }; diff --git a/evm-e2e/test/tx_receipt.test.ts b/evm-e2e/test/tx_receipt.test.ts index 7a95cd995..c42f1bb41 100644 --- a/evm-e2e/test/tx_receipt.test.ts +++ b/evm-e2e/test/tx_receipt.test.ts @@ -1,11 +1,11 @@ import { describe, expect, it, jest } from '@jest/globals'; import { ethers, TransactionReceipt, Log } from 'ethers'; -import { account } from './setup'; -import { deployContractEventsEmitter, deployContractTransactionReverter, TENPOW12 } from './utils'; +import { account, TEST_TIMEOUT } from './setup'; +import { deployContractEventsEmitter } from './utils'; import { TestERC20__factory } from '../types'; describe('Transaction Receipt Tests', () => { - jest.setTimeout(15e3); + jest.setTimeout(TEST_TIMEOUT); let recipient = ethers.Wallet.createRandom().address; @@ -24,7 +24,7 @@ describe('Transaction Receipt Tests', () => { it('contract deployment receipt', async () => { const factory = new TestERC20__factory(account); - const deployTx = await factory.deploy({ maxFeePerGas: TENPOW12 }); + const deployTx = await factory.deploy(); const receipt = await deployTx.deploymentTransaction().wait(); assertBaseReceiptFields(receipt); diff --git a/evm-e2e/test/utils.ts b/evm-e2e/test/utils.ts index dbf8f4c1c..b6879d49a 100644 --- a/evm-e2e/test/utils.ts +++ b/evm-e2e/test/utils.ts @@ -1,4 +1,4 @@ -import { account } from './setup'; +import { account, provider, TX_WAIT_TIMEOUT } from './setup'; import { ContractTransactionResponse, parseEther, toBigInt, TransactionRequest, Wallet } from 'ethers'; import { InifiniteLoopGas__factory, @@ -16,28 +16,25 @@ export const hexify = (x: number): string => { return '0x' + x.toString(16); }; -/** 10 to the power of 12 */ -export const TENPOW12 = toBigInt(1e12); - export const INTRINSIC_TX_GAS: bigint = 21000n; export const deployContractTestERC20 = async () => { const factory = new TestERC20__factory(account); - const contract = await factory.deploy({ maxFeePerGas: TENPOW12 }); + const contract = await factory.deploy(); await contract.waitForDeployment(); return contract; }; export const deployContractSendNibi = async () => { const factory = new SendNibi__factory(account); - const contract = await factory.deploy({ maxFeePerGas: TENPOW12 }); + const contract = await factory.deploy(); await contract.waitForDeployment(); return contract; }; export const deployContractInfiniteLoopGas = async () => { const factory = new InifiniteLoopGas__factory(account); - const contract = await factory.deploy({ maxFeePerGas: TENPOW12 }); + const contract = await factory.deploy(); await contract.waitForDeployment(); return contract; }; @@ -61,10 +58,9 @@ export const sendTestNibi = async () => { gasLimit: toBigInt(100e3), to: alice, value: parseEther('0.01'), - maxFeePerGas: TENPOW12, }; const txResponse = await account.sendTransaction(transaction); - await txResponse.wait(1, 10e3); + await txResponse.wait(1, TX_WAIT_TIMEOUT); console.log(txResponse); return txResponse; }; @@ -81,3 +77,7 @@ export const deployContractNibiruOracleChainLinkLike = async (): Promise<{ await contract.waitForDeployment(); return { oraclePair, contract }; }; + +export const numberToHex = (num: Number) => { + return '0x' + num.toString(16); +};