diff --git a/packages/relay/src/lib/clients/sdkClient.ts b/packages/relay/src/lib/clients/sdkClient.ts index eab04a43a..a5a2b4526 100644 --- a/packages/relay/src/lib/clients/sdkClient.ts +++ b/packages/relay/src/lib/clients/sdkClient.ts @@ -194,7 +194,7 @@ export class SDKClient { .setEthereumData(transactionBuffer), callerName); } - async submitContractCallQuery(to: string, data: string, gas: number, callerName: string): Promise { + async submitContractCallQuery(to: string, data: string, gas: number, from: string, callerName: string): Promise { const contract = SDKClient.prune0x(to); const contractId = contract.startsWith("00000000000") ? ContractId.fromSolidityAddress(contract) @@ -209,6 +209,10 @@ export class SDKClient { contractCallQuery.setFunctionParameters(Buffer.from(SDKClient.prune0x(data), 'hex')); } + if (from) { + contractCallQuery.setSenderAccountId(AccountId.fromEvmAddress(0,0, from)) + } + if (this.clientMain.operatorAccountId !== null) { contractCallQuery .setPaymentTransactionId(TransactionId.generate(this.clientMain.operatorAccountId)); diff --git a/packages/relay/src/lib/eth.ts b/packages/relay/src/lib/eth.ts index 6b98d1a07..9a9bb8b20 100644 --- a/packages/relay/src/lib/eth.ts +++ b/packages/relay/src/lib/eth.ts @@ -738,10 +738,10 @@ export class EthImpl implements Eth { gas = call.gas; } } - + // Execute the call and get the response - this.logger.debug('Making eth_call on contract %o with gas %d and call data "%s"', call.to, gas, call.data); - const contractCallResponse = await this.sdkClient.submitContractCallQuery(call.to, call.data, gas, EthImpl.ethCall); + this.logger.debug('Making eth_call on contract %o with gas %d and call data "%s" from "%s"', call.to, gas, call.data, call.from); + const contractCallResponse = await this.sdkClient.submitContractCallQuery(call.to, call.data, gas, call.from, EthImpl.ethCall); // FIXME Is this right? Maybe so? return EthImpl.prepend0x(Buffer.from(contractCallResponse.asBytes()).toString('hex')); diff --git a/packages/relay/tests/lib/eth.spec.ts b/packages/relay/tests/lib/eth.spec.ts index 6732354d8..387075e00 100644 --- a/packages/relay/tests/lib/eth.spec.ts +++ b/packages/relay/tests/lib/eth.spec.ts @@ -37,7 +37,6 @@ import pino from 'pino'; import { Block, Transaction } from '../../src/lib/model'; import constants from '../../src/lib/constants'; import { SDKClient } from '../../src/lib/clients'; -import { TextEncoder } from 'util'; const logger = pino(); const registry = new Registry(); const Relay = new RelayImpl(logger, registry); @@ -115,6 +114,7 @@ describe('Eth calls using MirrorNode', async function () { const gasUsed2 = 800000; const maxGasLimit = 250000; const maxGasLimitHex = EthImpl.numberTo0x(maxGasLimit); + const contractCallData = "0xef641f44" const firstTransactionTimestampSeconds = '1653077547'; const firstTransactionTimestampSecondsHex = EthImpl.numberTo0x(Number(firstTransactionTimestampSeconds)); const contractAddress1 = '0x000000000000000000000000000000000000055f'; @@ -1318,6 +1318,81 @@ describe('Eth calls using MirrorNode', async function () { expect(error.message).to.equal('Error encountered estimating the gas price'); } }); + + describe('eth_call', async function () { + it('eth_call with no gas', async function () { + sdkClientStub.submitContractCallQuery.returns({ + asBytes: function () { + return Uint8Array.of(0) + } + } + ); + + const result = await ethImpl.call({ + "from": contractAddress1, + "to": contractAddress2, + "data": contractCallData, + }, 'latest') + + sinon.assert.calledWith(sdkClientStub.submitContractCallQuery, contractAddress2, contractCallData, 400_000, contractAddress1, 'eth_call'); + expect(result).to.equal("0x00") + }); + + it('eth_call with no data', async function () { + sdkClientStub.submitContractCallQuery.returns({ + asBytes: function () { + return Uint8Array.of(0) + } + } + ); + + var result = await ethImpl.call({ + "from": contractAddress1, + "to": contractAddress2, + "gas": maxGasLimitHex + }, 'latest') + + sinon.assert.calledWith(sdkClientStub.submitContractCallQuery, contractAddress2, undefined, maxGasLimit, contractAddress1, 'eth_call'); + expect(result).to.equal("0x00") + }); + + it('eth_call with no from address', async function () { + sdkClientStub.submitContractCallQuery.returns({ + asBytes: function () { + return Uint8Array.of(0) + } + } + ); + + const result = await ethImpl.call({ + "to": contractAddress2, + "data": contractCallData, + "gas": maxGasLimitHex + }, 'latest') + + sinon.assert.calledWith(sdkClientStub.submitContractCallQuery, contractAddress2, contractCallData, maxGasLimit, undefined, 'eth_call'); + expect(result).to.equal("0x00") + }); + + it('eth_call with all fields', async function () { + sdkClientStub.submitContractCallQuery.returns({ + asBytes: function () { + return Uint8Array.of(0) + } + } + ); + + const result = await ethImpl.call({ + "from": contractAddress1, + "to": contractAddress2, + "data": contractCallData, + "gas": maxGasLimitHex + }, 'latest') + + sinon.assert.calledWith(sdkClientStub.submitContractCallQuery, contractAddress2, contractCallData, maxGasLimit, contractAddress1, 'eth_call'); + expect(result).to.equal("0x00") + }); + }); }); describe('Eth', async function () { diff --git a/packages/server/tests/acceptance/erc20.spec.ts b/packages/server/tests/acceptance/erc20.spec.ts index aec811d6d..c0c4442fc 100644 --- a/packages/server/tests/acceptance/erc20.spec.ts +++ b/packages/server/tests/acceptance/erc20.spec.ts @@ -32,7 +32,7 @@ import {Utils} from '../helpers/utils'; describe('ERC20 Acceptance Tests', async function () { this.timeout(240 * 1000); // 240 seconds - const {servicesNode, relay, logger} = global; + const {servicesNode, relay} = global; // cached entities const accounts: AliasAccount[] = []; @@ -175,7 +175,8 @@ describe('ERC20 Acceptance Tests', async function () { if (testTitles[i].testName !== HTS) { describe('when the spender has enough allowance', function () { before(async function () { - await contract.connect(tokenOwnerWallet).approve(spender, initialSupply); + const tx = await contract.connect(tokenOwnerWallet).approve(spender, initialSupply); + await tx.wait(); }); describe('when the token owner has enough balance', function () { @@ -190,6 +191,7 @@ describe('ERC20 Acceptance Tests', async function () { it('transfers the requested amount', async function () { tx = await contract.connect(spenderWallet).transferFrom(tokenOwner, to, initialSupply); + await tx.wait(); const ownerBalance = await contract.balanceOf(tokenOwner); const toBalance = await contract.balanceOf(to); expect(ownerBalance.toString()).to.be.equal('0'); @@ -336,7 +338,7 @@ describe('ERC20 Acceptance Tests', async function () { const receipt = await relay.provider.getTransactionReceipt(contract.deployTransaction.hash); contract = new ethers.Contract(receipt.to, contractJson.abi, accounts[0].wallet); return contract; - }; + } const createHTS = async(tokenName, symbol, adminAccount, initialSupply, abi, associatedAccounts) => { const htsResult = await servicesNode.createHTS({ @@ -356,8 +358,6 @@ describe('ERC20 Acceptance Tests', async function () { // Setup initial balance of token owner account await servicesNode.transferHTSToken(accounts[0].accountId, htsResult.receipt.tokenId, initialSupply, htsResult.client); const evmAddress = Utils.idToEvmAddress(htsResult.receipt.tokenId.toString()); - const contract = new ethers.Contract(evmAddress, abi, accounts[0].wallet); - - return contract; + return new ethers.Contract(evmAddress, abi, accounts[0].wallet); }; -}); \ No newline at end of file +});