From 17fef7f4a8270d16141e84d81304220634240aea Mon Sep 17 00:00:00 2001 From: Oleg Nikonychev Date: Thu, 30 May 2024 21:48:37 +0400 Subject: [PATCH 1/5] test(evm): more e2e test contracts for edge cases --- e2e/evm/README.md | 30 +++++-- e2e/evm/contracts/InfiniteLoopGas.sol | 17 ++++ .../contracts/InfiniteLoopGasCompiled.json | 31 +++++++ e2e/evm/contracts/ReceiveNibiCompiled.json | 32 +++++++ e2e/evm/contracts/SendNibiCompiled.json | 50 +++++++++++ e2e/evm/contracts/SendReceiveNibi.sol | 51 +++++++++++ e2e/evm/jest.config.js | 3 +- e2e/evm/test/basic_queries.test.js | 35 ++++++++ .../test/contract_infinite_loop_gas.test.js | 24 ++++++ e2e/evm/test/contract_send_nibi.test.js | 37 ++++++++ e2e/evm/test/erc20.test.js | 32 +++++++ e2e/evm/test/evm.test.js | 86 ------------------- e2e/evm/test/setup.js | 31 +++++++ 13 files changed, 364 insertions(+), 95 deletions(-) create mode 100644 e2e/evm/contracts/InfiniteLoopGas.sol create mode 100644 e2e/evm/contracts/InfiniteLoopGasCompiled.json create mode 100644 e2e/evm/contracts/ReceiveNibiCompiled.json create mode 100644 e2e/evm/contracts/SendNibiCompiled.json create mode 100644 e2e/evm/contracts/SendReceiveNibi.sol create mode 100644 e2e/evm/test/basic_queries.test.js create mode 100644 e2e/evm/test/contract_infinite_loop_gas.test.js create mode 100644 e2e/evm/test/contract_send_nibi.test.js create mode 100644 e2e/evm/test/erc20.test.js delete mode 100644 e2e/evm/test/evm.test.js create mode 100644 e2e/evm/test/setup.js diff --git a/e2e/evm/README.md b/e2e/evm/README.md index 4375ea399..b1db1199a 100644 --- a/e2e/evm/README.md +++ b/e2e/evm/README.md @@ -41,14 +41,28 @@ npm test > nibiru-evm-test@0.0.1 test > jest - PASS test/evm.test.js (13.163 s) - Ethereum JSON-RPC Interface Tests - ✓ Simple Transfer, balance check (4258 ms) - ✓ Smart Contract (8656 ms) - -Test Suites: 1 passed, 1 total -Tests: 2 passed, 2 total + PASS test/contract_infinite_loop_gas.test.js (8.617 s) + Infinite loop gas contract + ✓ should fail due to out of gas error (4152 ms) + + PASS test/contract_send_nibi.test.js (16.977 s) + Send NIBI from smart contract + ✓ send nibi via "sendViaTransfer" method (4244 ms) + ✓ send nibi via "sendViaSend" method (4239 ms) + ✓ send nibi via "sendViaCall" method (4259 ms) + + PASS test/erc20.test.js (8.845 s) + ERC-20 contract tests + ✓ send, balanceOf (8765 ms) + + PASS test/basic_queries.test.js + Basic Queries + ✓ Simple transfer, balance check (4224 ms) + +Test Suites: 4 passed, 4 total +Tests: 6 passed, 6 total Snapshots: 0 total -Time: 13.187 s, estimated 14 s +Time: 38.783 s, estimated 50 s Ran all test suites. + ``` diff --git a/e2e/evm/contracts/InfiniteLoopGas.sol b/e2e/evm/contracts/InfiniteLoopGas.sol new file mode 100644 index 000000000..beae47115 --- /dev/null +++ b/e2e/evm/contracts/InfiniteLoopGas.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +contract InifiniteLoopGas { + uint256 public counter = 0; + + // Using up all of the gas that you send causes your transaction to fail. + // State changes are undone. + // Gas spent are not refunded. + function forever() public { + // Here we run a loop until all of the gas are spent + // and the transaction fails + while (true) { + counter += 1; + } + } +} diff --git a/e2e/evm/contracts/InfiniteLoopGasCompiled.json b/e2e/evm/contracts/InfiniteLoopGasCompiled.json new file mode 100644 index 000000000..3868bd1d1 --- /dev/null +++ b/e2e/evm/contracts/InfiniteLoopGasCompiled.json @@ -0,0 +1,31 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "InifiniteLoopGas", + "sourceName": "contracts/InfiniteLoopGas.sol", + "abi": [ + { + "inputs": [], + "name": "counter", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "forever", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x60806040526000805534801561001457600080fd5b5061015e806100246000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806361bc221a1461003b5780639ff9a60314610059575b600080fd5b610043610063565b60405161005091906100aa565b60405180910390f35b610061610069565b005b60005481565b5b60011561008f57600160008082825461008391906100f4565b9250508190555061006a565b565b6000819050919050565b6100a481610091565b82525050565b60006020820190506100bf600083018461009b565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006100ff82610091565b915061010a83610091565b9250828201905080821115610122576101216100c5565b5b9291505056fea2646970667358221220946d430ff7d8c16c5401d4156ff1b5d75c112460fbba0fb343581bd3c86cfe1c64736f6c63430008180033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100365760003560e01c806361bc221a1461003b5780639ff9a60314610059575b600080fd5b610043610063565b60405161005091906100aa565b60405180910390f35b610061610069565b005b60005481565b5b60011561008f57600160008082825461008391906100f4565b9250508190555061006a565b565b6000819050919050565b6100a481610091565b82525050565b60006020820190506100bf600083018461009b565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006100ff82610091565b915061010a83610091565b9250828201905080821115610122576101216100c5565b5b9291505056fea2646970667358221220946d430ff7d8c16c5401d4156ff1b5d75c112460fbba0fb343581bd3c86cfe1c64736f6c63430008180033", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/e2e/evm/contracts/ReceiveNibiCompiled.json b/e2e/evm/contracts/ReceiveNibiCompiled.json new file mode 100644 index 000000000..979c40c63 --- /dev/null +++ b/e2e/evm/contracts/ReceiveNibiCompiled.json @@ -0,0 +1,32 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "ReceiveNibi", + "sourceName": "contracts/SendReceiveNibi.sol", + "abi": [ + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "inputs": [], + "name": "getBalance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ], + "bytecode": "0x608060405234801561001057600080fd5b5060bb8061001f6000396000f3fe608060405260043610601f5760003560e01c806312065fe0146027576025565b36602557005b005b348015603257600080fd5b506039604d565b60405160449190606c565b60405180910390f35b600047905090565b6000819050919050565b6066816055565b82525050565b6000602082019050607f6000830184605f565b9291505056fea2646970667358221220f4ee193ceac7d6ffbf8d62d675a1d21fed9c154b8e9407c7aba0f7301ef0db6b64736f6c63430008180033", + "deployedBytecode": "0x608060405260043610601f5760003560e01c806312065fe0146027576025565b36602557005b005b348015603257600080fd5b506039604d565b60405160449190606c565b60405180910390f35b600047905090565b6000819050919050565b6066816055565b82525050565b6000602082019050607f6000830184605f565b9291505056fea2646970667358221220f4ee193ceac7d6ffbf8d62d675a1d21fed9c154b8e9407c7aba0f7301ef0db6b64736f6c63430008180033", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/e2e/evm/contracts/SendNibiCompiled.json b/e2e/evm/contracts/SendNibiCompiled.json new file mode 100644 index 000000000..621e8db3e --- /dev/null +++ b/e2e/evm/contracts/SendNibiCompiled.json @@ -0,0 +1,50 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "SendNibi", + "sourceName": "contracts/SendReceiveNibi.sol", + "abi": [ + { + "inputs": [ + { + "internalType": "address payable", + "name": "_to", + "type": "address" + } + ], + "name": "sendViaCall", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address payable", + "name": "_to", + "type": "address" + } + ], + "name": "sendViaSend", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address payable", + "name": "_to", + "type": "address" + } + ], + "name": "sendViaTransfer", + "outputs": [], + "stateMutability": "payable", + "type": "function" + } + ], + "bytecode": "0x608060405234801561001057600080fd5b50610390806100206000396000f3fe6080604052600436106100345760003560e01c8063636e082b1461003957806374be480614610055578063830c29ae14610071575b600080fd5b610053600480360381019061004e919061026a565b61008d565b005b61006f600480360381019061006a919061026a565b6100d7565b005b61008b6004803603810190610086919061026a565b610154565b005b8073ffffffffffffffffffffffffffffffffffffffff166108fc349081150290604051600060405180830381858888f193505050501580156100d3573d6000803e3d6000fd5b5050565b60008173ffffffffffffffffffffffffffffffffffffffff166108fc349081150290604051600060405180830381858888f19350505050905080610150576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610147906102f4565b60405180910390fd5b5050565b6000808273ffffffffffffffffffffffffffffffffffffffff163460405161017b90610345565b60006040518083038185875af1925050503d80600081146101b8576040519150601f19603f3d011682016040523d82523d6000602084013e6101bd565b606091505b509150915081610202576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101f9906102f4565b60405180910390fd5b505050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006102378261020c565b9050919050565b6102478161022c565b811461025257600080fd5b50565b6000813590506102648161023e565b92915050565b6000602082840312156102805761027f610207565b5b600061028e84828501610255565b91505092915050565b600082825260208201905092915050565b7f4661696c656420746f2073656e64204e69626900000000000000000000000000600082015250565b60006102de601383610297565b91506102e9826102a8565b602082019050919050565b6000602082019050818103600083015261030d816102d1565b9050919050565b600081905092915050565b50565b600061032f600083610314565b915061033a8261031f565b600082019050919050565b600061035082610322565b915081905091905056fea26469706673582212201fcd9f47953315963ca2a2687073914cbb3f29161100cec83979926b96714b2b64736f6c63430008180033", + "deployedBytecode": "0x6080604052600436106100345760003560e01c8063636e082b1461003957806374be480614610055578063830c29ae14610071575b600080fd5b610053600480360381019061004e919061026a565b61008d565b005b61006f600480360381019061006a919061026a565b6100d7565b005b61008b6004803603810190610086919061026a565b610154565b005b8073ffffffffffffffffffffffffffffffffffffffff166108fc349081150290604051600060405180830381858888f193505050501580156100d3573d6000803e3d6000fd5b5050565b60008173ffffffffffffffffffffffffffffffffffffffff166108fc349081150290604051600060405180830381858888f19350505050905080610150576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610147906102f4565b60405180910390fd5b5050565b6000808273ffffffffffffffffffffffffffffffffffffffff163460405161017b90610345565b60006040518083038185875af1925050503d80600081146101b8576040519150601f19603f3d011682016040523d82523d6000602084013e6101bd565b606091505b509150915081610202576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101f9906102f4565b60405180910390fd5b505050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006102378261020c565b9050919050565b6102478161022c565b811461025257600080fd5b50565b6000813590506102648161023e565b92915050565b6000602082840312156102805761027f610207565b5b600061028e84828501610255565b91505092915050565b600082825260208201905092915050565b7f4661696c656420746f2073656e64204e69626900000000000000000000000000600082015250565b60006102de601383610297565b91506102e9826102a8565b602082019050919050565b6000602082019050818103600083015261030d816102d1565b9050919050565b600081905092915050565b50565b600061032f600083610314565b915061033a8261031f565b600082019050919050565b600061035082610322565b915081905091905056fea26469706673582212201fcd9f47953315963ca2a2687073914cbb3f29161100cec83979926b96714b2b64736f6c63430008180033", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/e2e/evm/contracts/SendReceiveNibi.sol b/e2e/evm/contracts/SendReceiveNibi.sol new file mode 100644 index 000000000..1be8479f0 --- /dev/null +++ b/e2e/evm/contracts/SendReceiveNibi.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +contract ReceiveNibi { + /* + Which function is called, fallback() or receive()? + + send Nibi + | + msg.data is empty? + / \ + yes no + / \ + receive() exists? fallback() + / \ + yes no + / \ + receive() fallback() + */ + + // Function to receive Nibi. msg.data must be empty + receive() external payable {} + + // Fallback function is called when msg.data is not empty + fallback() external payable {} + + function getBalance() public view returns (uint256) { + return address(this).balance; + } +} + +contract SendNibi { + function sendViaTransfer(address payable _to) public payable { + // This function is no longer recommended for sending Nibi. + _to.transfer(msg.value); + } + + function sendViaSend(address payable _to) public payable { + // Send returns a boolean value indicating success or failure. + // This function is not recommended for sending Nibi. + bool sent = _to.send(msg.value); + require(sent, "Failed to send Nibi"); + } + + function sendViaCall(address payable _to) public payable { + // Call returns a boolean value indicating success or failure. + // This is the current recommended method to use. + (bool sent, bytes memory data) = _to.call{value : msg.value}(""); + require(sent, "Failed to send Nibi"); + } +} diff --git a/e2e/evm/jest.config.js b/e2e/evm/jest.config.js index ef3b85897..3ee1152ca 100644 --- a/e2e/evm/jest.config.js +++ b/e2e/evm/jest.config.js @@ -1,5 +1,6 @@ module.exports = { testEnvironment: 'node', - testMatch: ['**/test/**/*.js'], + testMatch: ['**/test/**/*.test.js'], verbose: true, + "maxWorkers": 1 }; diff --git a/e2e/evm/test/basic_queries.test.js b/e2e/evm/test/basic_queries.test.js new file mode 100644 index 000000000..4f0d6af26 --- /dev/null +++ b/e2e/evm/test/basic_queries.test.js @@ -0,0 +1,35 @@ +const {ethers} = require('ethers') +const {account, provider, deployContract} = require('./setup') + +describe('Basic Queries', () => { + + it('Simple transfer, balance check', async () => { + const randomAddress = ethers.Wallet.createRandom().address + const amountToSend = 1000n // unibi + const gasLimit = 100_000n // unibi + + const senderBalanceBefore = await provider.getBalance(account.address) + const recipientBalanceBefore = await provider.getBalance(randomAddress) + + expect(senderBalanceBefore).toBeGreaterThan(0) + expect(recipientBalanceBefore).toEqual(0n) + + // Execute EVM transfer + const transaction = { + gasLimit: gasLimit, + to: randomAddress, + value: amountToSend + } + const txResponse = await account.sendTransaction(transaction) + await txResponse.wait() + expect(txResponse).toHaveProperty('blockHash') + + const senderBalanceAfter = await provider.getBalance(account.address) + const recipientBalanceAfter = await provider.getBalance(randomAddress) + + // TODO: gas is not deducted regardless the gas limit, check this + const expectedSenderBalance = senderBalanceBefore - amountToSend + expect(senderBalanceAfter).toBeLessThanOrEqual(expectedSenderBalance) + expect(recipientBalanceAfter).toEqual(amountToSend) + }, 20_000) +}) diff --git a/e2e/evm/test/contract_infinite_loop_gas.test.js b/e2e/evm/test/contract_infinite_loop_gas.test.js new file mode 100644 index 000000000..ad8a5eaf8 --- /dev/null +++ b/e2e/evm/test/contract_infinite_loop_gas.test.js @@ -0,0 +1,24 @@ +const {deployContract} = require('./setup') + +describe('Infinite loop gas contract', () => { + let contract + + beforeAll(async () => { + contract = await deployContract('InfiniteLoopGasCompiled.json') + }) + + it('should fail due to out of gas error', async () => { + const initialCounter = await contract.counter() + expect(initialCounter).toBe(0n) + + try { + const tx = await contract.forever({gasLimit: 1000000}) + await tx.wait() + fail("The transaction should have failed but did not.") + } catch (error) { + expect(error.message).toContain("transaction execution reverted") + } + const finalCounter = await contract.counter() + expect(finalCounter).toEqual(initialCounter) + }, 20000) +}) diff --git a/e2e/evm/test/contract_send_nibi.test.js b/e2e/evm/test/contract_send_nibi.test.js new file mode 100644 index 000000000..9d4fcb8f0 --- /dev/null +++ b/e2e/evm/test/contract_send_nibi.test.js @@ -0,0 +1,37 @@ +const {ethers} = require('ethers') +const {account, provider, deployContract} = require('./setup') + +let contract + +const doContractSend = async (sendMethod) => { + const recipientAddress = ethers.Wallet.createRandom().address + const transferValue = 100n * 10n ** 6n // NIBI + + const ownerBalanceBefore = await provider.getBalance(account.address) // NIBI + const recipientBalanceBefore = await provider.getBalance(recipientAddress) // NIBI + expect(recipientBalanceBefore).toEqual(0n) + + let tx = await contract[sendMethod](recipientAddress, {value: transferValue}) + await tx.wait() + + const ownerBalanceAfter = await provider.getBalance(account.address) // NIBI + const recipientBalanceAfter = await provider.getBalance(recipientAddress) // NIBI + + expect(ownerBalanceAfter).toBeLessThanOrEqual(ownerBalanceBefore - transferValue) + expect(recipientBalanceAfter).toEqual(transferValue) +} + +describe('Send NIBI from smart contract', () => { + + beforeAll(async () => { + contract = await deployContract('SendNibiCompiled.json') + }) + + it.each([ + ['sendViaTransfer'], + ['sendViaSend'], + ['sendViaCall'], + ])('send nibi via %p method', async (sendMethod) => { + await doContractSend(sendMethod) + }, 20000); +}) diff --git a/e2e/evm/test/erc20.test.js b/e2e/evm/test/erc20.test.js new file mode 100644 index 000000000..62d512984 --- /dev/null +++ b/e2e/evm/test/erc20.test.js @@ -0,0 +1,32 @@ +const {ethers} = require('ethers') +const {account, deployContract} = require('./setup') + +describe('ERC-20 contract tests', () => { + + it('send, balanceOf', async () => { + const contract = await deployContract('FunTokenCompiled.json') + const contractAddress = await contract.getAddress() + expect(contractAddress).toBeDefined() + + // Execute contract: ERC20 transfer + const shrimpAddress = ethers.Wallet.createRandom().address + let ownerInitialBalance = ethers.parseUnits("1000000", 18) + + const amountToSend = ethers.parseUnits("1000", 18) // contract tokens + + let ownerBalance = await contract.balanceOf(account.address) + let shrimpBalance = await contract.balanceOf(shrimpAddress) + + expect(ownerBalance).toEqual(ownerInitialBalance) + expect(shrimpBalance).toEqual(ethers.toBigInt(0)) + + let tx = await contract.transfer(shrimpAddress, amountToSend) + await tx.wait() + + ownerBalance = await contract.balanceOf(account.address) + shrimpBalance = await contract.balanceOf(shrimpAddress) + + expect(ownerBalance).toEqual(ownerInitialBalance - amountToSend) + expect(shrimpBalance).toEqual(amountToSend) + }, 20000) +}) diff --git a/e2e/evm/test/evm.test.js b/e2e/evm/test/evm.test.js deleted file mode 100644 index d11276e85..000000000 --- a/e2e/evm/test/evm.test.js +++ /dev/null @@ -1,86 +0,0 @@ -const {ethers} = require('ethers') -const {config} = require('dotenv') -const fs = require('fs') - -config() - -describe('Ethereum JSON-RPC Interface Tests', () => { - let provider - let wallet - let account - - beforeAll(async () => { - const rpcEndpoint = process.env.JSON_RPC_ENDPOINT - const mnemonic = process.env.MNEMONIC - provider = ethers.getDefaultProvider(rpcEndpoint) - wallet = ethers.Wallet.fromPhrase(mnemonic) - account = wallet.connect(provider) - }) - - test('Simple Transfer, balance check', async () => { - const randomAddress = ethers.Wallet.createRandom().address - const amountToSend = ethers.toBigInt(1000) // unibi - const gasLimit = ethers.toBigInt(100_000) // unibi - - const senderBalanceBefore = await provider.getBalance(wallet.address) - const recipientBalanceBefore = await provider.getBalance(randomAddress) - - expect(senderBalanceBefore).toBeGreaterThan(0) - expect(recipientBalanceBefore).toEqual(ethers.toBigInt(0)) - - // Execute EVM transfer - const transaction = { - gasLimit: gasLimit, - to: randomAddress, - value: amountToSend - } - const txResponse = await account.sendTransaction(transaction) - await txResponse.wait() - expect(txResponse).toHaveProperty('blockHash') - - const senderBalanceAfter = await provider.getBalance(wallet.address) - const recipientBalanceAfter = await provider.getBalance(randomAddress) - - // TODO: gas is not deducted regardless the gas limit, check this - const expectedSenderBalance = senderBalanceBefore - amountToSend - expect(senderBalanceAfter).toBeLessThanOrEqual(expectedSenderBalance) - expect(recipientBalanceAfter).toEqual(amountToSend) - }, 20_000) - - test('Smart Contract', async () => { - // Read contract ABI and bytecode - const contractJSON = JSON.parse( - fs.readFileSync('contracts/FunTokenCompiled.json').toString() - ) - const bytecode = contractJSON['bytecode'] - const abi = contractJSON['abi'] - - // Deploy contract - const contractFactory = new ethers.ContractFactory(abi, bytecode, account) - const contract = await contractFactory.deploy() - await contract.waitForDeployment() - const contractAddress = await contract.getAddress() - expect(contractAddress).toBeDefined() - - // Execute contract: ERC20 transfer - const shrimpAddress = ethers.Wallet.createRandom().address - let ownerInitialBalance = ethers.parseUnits("1000000", 18) - - const amountToSend = ethers.parseUnits("1000", 18) // contract tokens - - let ownerBalance = await contract.balanceOf(account.address) - let shrimpBalance = await contract.balanceOf(shrimpAddress) - - expect(ownerBalance).toEqual(ownerInitialBalance) - expect(shrimpBalance).toEqual(ethers.toBigInt(0)) - - let tx = await contract.transfer(shrimpAddress, amountToSend) - await tx.wait() - - ownerBalance = await contract.balanceOf(account.address) - shrimpBalance = await contract.balanceOf(shrimpAddress) - - expect(ownerBalance).toEqual(ownerInitialBalance - amountToSend) - expect(shrimpBalance).toEqual(amountToSend) - }, 20000) -}) diff --git a/e2e/evm/test/setup.js b/e2e/evm/test/setup.js new file mode 100644 index 000000000..74ef7cb9e --- /dev/null +++ b/e2e/evm/test/setup.js @@ -0,0 +1,31 @@ +const {ethers} = require("ethers"); +const {config} = require('dotenv') +const fs = require("fs"); + +config() + +const rpcEndpoint = process.env.JSON_RPC_ENDPOINT +const mnemonic = process.env.MNEMONIC + +const provider = ethers.getDefaultProvider(rpcEndpoint) +const wallet = ethers.Wallet.fromPhrase(mnemonic) +const account = wallet.connect(provider) + +const deployContract = async (path) => { + const contractJSON = JSON.parse( + fs.readFileSync(`contracts/${path}`).toString() + ) + const bytecode = contractJSON['bytecode'] + const abi = contractJSON['abi'] + + const contractFactory = new ethers.ContractFactory(abi, bytecode, account) + const contract = await contractFactory.deploy() + await contract.waitForDeployment() + return contract +} + +module.exports = { + provider, + account, + deployContract, +} \ No newline at end of file From e2e1a81df7fd610da6554c5517e9e3b9bc9edff4 Mon Sep 17 00:00:00 2001 From: Oleg Nikonychev Date: Thu, 30 May 2024 21:51:33 +0400 Subject: [PATCH 2/5] chore: changelog --- CHANGELOG.md | 1 + compare_nibi_eth_keys.go | 48 ++++++++++++++++++++++++++++++++++++++++ e2e/evm/test/setup.js | 2 +- tx_via_gosdk.go | 26 ++++++++++++++++++++++ 4 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 compare_nibi_eth_keys.go create mode 100644 tx_via_gosdk.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 00a50459c..1302435a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -65,6 +65,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [#1887](https://github.com/NibiruChain/nibiru/pull/1887) - test(evm): eth api integration test suite - [#1889](https://github.com/NibiruChain/nibiru/pull/1889) - feat: implemented basic evm tx methods - [#1895](https://github.com/NibiruChain/nibiru/pull/1895) - refactor(geth): Reference go-ethereum as a submodule for easier change tracking with upstream +- [#1901](https://github.com/NibiruChain/nibiru/pull/1901) - test(evm): more e2e test contracts for edge cases #### Dapp modules: perp, spot, oracle, etc diff --git a/compare_nibi_eth_keys.go b/compare_nibi_eth_keys.go new file mode 100644 index 000000000..49de07272 --- /dev/null +++ b/compare_nibi_eth_keys.go @@ -0,0 +1,48 @@ +package main + +import ( + "fmt" + + "github.com/NibiruChain/nibiru/eth" + "github.com/NibiruChain/nibiru/eth/crypto/hd" + "github.com/NibiruChain/nibiru/x/evm/evmtest" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func main() { + //app.SetPrefixes(appconst.AccountAddressPrefix) + a := evmtest.NewEthAccInfo() + fmt.Println(a.EthAddr.String()) + fmt.Println(a.NibiruAddr.String()) + + 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" + + // Default derivation path m/44'/60'/0'/0/0 + // Cosmos derivation path m/44/118/100'/0/0 + //derivationPath := sdk.GetConfig().GetFullBIP44Path() // Default: eth.BIP44HDPath + derivationPath := eth.BIP44HDPath // Default: eth.BIP44HDPath + fmt.Println("Derivation path:", derivationPath) + + // Private & Public Keys + //ethPrivateKeyBytes, _ := hd.EthSecp256k1.Derive()(mnemonic, keyring.DefaultBIP39Passphrase, eth.BIP44HDPath) + ethPrivateKeyBytes, _ := hd.EthSecp256k1.Derive()(mnemonic, keyring.DefaultBIP39Passphrase, derivationPath) + ethPrivateKey := hd.EthSecp256k1.Generate()(ethPrivateKeyBytes) + + // Public key of type go-ethereum ethsecp256k1 + ethPublicKey := ethPrivateKey.PubKey() + + // Convert eth public key to cosmos secp256k (custom address converter) + ethPublicKeyOfCosmosType := secp256k1.PubKey{Key: ethPublicKey.Bytes()} + + ethAddress := ethPublicKey.Address() + ethCosmosAddress := ethPublicKeyOfCosmosType.Address() + + fmt.Println("Nibi addr A eth addr:", sdk.AccAddress(ethAddress.Bytes()).String()) + fmt.Println("Nibi addr 2 cosmos addr:", sdk.AccAddress(ethCosmosAddress.Bytes()).String()) + + fmt.Println("Hex 1:", "0x"+eth.BytesToHex(ethAddress.Bytes())) + fmt.Println("Hex 2:", "0x"+eth.BytesToHex(ethCosmosAddress.Bytes())) + +} diff --git a/e2e/evm/test/setup.js b/e2e/evm/test/setup.js index 74ef7cb9e..f96e51b19 100644 --- a/e2e/evm/test/setup.js +++ b/e2e/evm/test/setup.js @@ -28,4 +28,4 @@ module.exports = { provider, account, deployContract, -} \ No newline at end of file +} diff --git a/tx_via_gosdk.go b/tx_via_gosdk.go new file mode 100644 index 000000000..5e29d1679 --- /dev/null +++ b/tx_via_gosdk.go @@ -0,0 +1,26 @@ +package main + +import ( + "fmt" + + "github.com/NibiruChain/nibiru/app" + "github.com/NibiruChain/nibiru/app/appconst" + "github.com/NibiruChain/nibiru/gosdk" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func main1() { + app.SetPrefixes(appconst.AccountAddressPrefix) + 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" + encCfg := app.MakeEncodingConfig() + kr := keyring.NewInMemory(encCfg.Codec) + privKey, addr, err := gosdk.PrivKeyFromMnemonic(kr, mnemonic, "test") + if err != nil { + panic(err) + } + pubKey := privKey.PubKey() + addrStr := addr.String() + fmt.Println("Address (expected):", addrStr) + fmt.Println("Address from the public key (wrong):", sdk.AccAddress(pubKey.Address().Bytes()).String()) +} From 2bcd9d84eab33c931e5e05ac58c3def74d96f601 Mon Sep 17 00:00:00 2001 From: Oleg Nikonychev Date: Thu, 30 May 2024 21:55:00 +0400 Subject: [PATCH 3/5] chore: cleanup --- compare_nibi_eth_keys.go | 48 ---------------------------------------- tx_via_gosdk.go | 26 ---------------------- 2 files changed, 74 deletions(-) delete mode 100644 compare_nibi_eth_keys.go delete mode 100644 tx_via_gosdk.go diff --git a/compare_nibi_eth_keys.go b/compare_nibi_eth_keys.go deleted file mode 100644 index 49de07272..000000000 --- a/compare_nibi_eth_keys.go +++ /dev/null @@ -1,48 +0,0 @@ -package main - -import ( - "fmt" - - "github.com/NibiruChain/nibiru/eth" - "github.com/NibiruChain/nibiru/eth/crypto/hd" - "github.com/NibiruChain/nibiru/x/evm/evmtest" - "github.com/cosmos/cosmos-sdk/crypto/keyring" - "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -func main() { - //app.SetPrefixes(appconst.AccountAddressPrefix) - a := evmtest.NewEthAccInfo() - fmt.Println(a.EthAddr.String()) - fmt.Println(a.NibiruAddr.String()) - - 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" - - // Default derivation path m/44'/60'/0'/0/0 - // Cosmos derivation path m/44/118/100'/0/0 - //derivationPath := sdk.GetConfig().GetFullBIP44Path() // Default: eth.BIP44HDPath - derivationPath := eth.BIP44HDPath // Default: eth.BIP44HDPath - fmt.Println("Derivation path:", derivationPath) - - // Private & Public Keys - //ethPrivateKeyBytes, _ := hd.EthSecp256k1.Derive()(mnemonic, keyring.DefaultBIP39Passphrase, eth.BIP44HDPath) - ethPrivateKeyBytes, _ := hd.EthSecp256k1.Derive()(mnemonic, keyring.DefaultBIP39Passphrase, derivationPath) - ethPrivateKey := hd.EthSecp256k1.Generate()(ethPrivateKeyBytes) - - // Public key of type go-ethereum ethsecp256k1 - ethPublicKey := ethPrivateKey.PubKey() - - // Convert eth public key to cosmos secp256k (custom address converter) - ethPublicKeyOfCosmosType := secp256k1.PubKey{Key: ethPublicKey.Bytes()} - - ethAddress := ethPublicKey.Address() - ethCosmosAddress := ethPublicKeyOfCosmosType.Address() - - fmt.Println("Nibi addr A eth addr:", sdk.AccAddress(ethAddress.Bytes()).String()) - fmt.Println("Nibi addr 2 cosmos addr:", sdk.AccAddress(ethCosmosAddress.Bytes()).String()) - - fmt.Println("Hex 1:", "0x"+eth.BytesToHex(ethAddress.Bytes())) - fmt.Println("Hex 2:", "0x"+eth.BytesToHex(ethCosmosAddress.Bytes())) - -} diff --git a/tx_via_gosdk.go b/tx_via_gosdk.go deleted file mode 100644 index 5e29d1679..000000000 --- a/tx_via_gosdk.go +++ /dev/null @@ -1,26 +0,0 @@ -package main - -import ( - "fmt" - - "github.com/NibiruChain/nibiru/app" - "github.com/NibiruChain/nibiru/app/appconst" - "github.com/NibiruChain/nibiru/gosdk" - "github.com/cosmos/cosmos-sdk/crypto/keyring" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -func main1() { - app.SetPrefixes(appconst.AccountAddressPrefix) - 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" - encCfg := app.MakeEncodingConfig() - kr := keyring.NewInMemory(encCfg.Codec) - privKey, addr, err := gosdk.PrivKeyFromMnemonic(kr, mnemonic, "test") - if err != nil { - panic(err) - } - pubKey := privKey.PubKey() - addrStr := addr.String() - fmt.Println("Address (expected):", addrStr) - fmt.Println("Address from the public key (wrong):", sdk.AccAddress(pubKey.Address().Bytes()).String()) -} From c7e25eb5db2e9e19b649f6e8937cd4da6c1b5db5 Mon Sep 17 00:00:00 2001 From: Unique Divine <51418232+Unique-Divine@users.noreply.github.com> Date: Fri, 31 May 2024 00:49:31 -0500 Subject: [PATCH 4/5] Update e2e/evm/test/contract_send_nibi.test.js Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- e2e/evm/test/contract_send_nibi.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/evm/test/contract_send_nibi.test.js b/e2e/evm/test/contract_send_nibi.test.js index 9d4fcb8f0..59d70accb 100644 --- a/e2e/evm/test/contract_send_nibi.test.js +++ b/e2e/evm/test/contract_send_nibi.test.js @@ -11,7 +11,7 @@ const doContractSend = async (sendMethod) => { const recipientBalanceBefore = await provider.getBalance(recipientAddress) // NIBI expect(recipientBalanceBefore).toEqual(0n) - let tx = await contract[sendMethod](recipientAddress, {value: transferValue}) + const tx = await contract[sendMethod](recipientAddress, {value: transferValue}) await tx.wait() const ownerBalanceAfter = await provider.getBalance(account.address) // NIBI From 6a2524ea5d1571c8f0110e53274572feff52250e Mon Sep 17 00:00:00 2001 From: Unique Divine <51418232+Unique-Divine@users.noreply.github.com> Date: Fri, 31 May 2024 00:49:41 -0500 Subject: [PATCH 5/5] Update e2e/evm/test/basic_queries.test.js --- e2e/evm/test/basic_queries.test.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/e2e/evm/test/basic_queries.test.js b/e2e/evm/test/basic_queries.test.js index 4f0d6af26..98dd9faa6 100644 --- a/e2e/evm/test/basic_queries.test.js +++ b/e2e/evm/test/basic_queries.test.js @@ -27,7 +27,8 @@ describe('Basic Queries', () => { const senderBalanceAfter = await provider.getBalance(account.address) const recipientBalanceAfter = await provider.getBalance(randomAddress) - // TODO: gas is not deducted regardless the gas limit, check this + // TODO: https://github.com/NibiruChain/nibiru/issues/1902 + // gas is not deducted regardless the gas limit, check this const expectedSenderBalance = senderBalanceBefore - amountToSend expect(senderBalanceAfter).toBeLessThanOrEqual(expectedSenderBalance) expect(recipientBalanceAfter).toEqual(amountToSend)