From 2993e328fc26d39f0a0390f9be9643ce8e0963ed Mon Sep 17 00:00:00 2001 From: Miguel Angel Rojo Date: Wed, 30 Oct 2024 09:40:59 +0000 Subject: [PATCH] refactor(`ContractCallResult`): Added `errorMessage`, `plain` value and `success` flag (#1440) * refactor: first commit * refactor: fixed some tests * refactor: fixed some tests * feat: fixed tests * refactor: fixed some tests * refactor: fixed docs tests * feat: refactor --------- Co-authored-by: Fabio Rigamonti <73019897+fabiorigam@users.noreply.github.com> --- docs/contracts.md | 32 ++- .../contracts/contract-create-ERC20-token.ts | 32 ++- docs/examples/evm-extension/evm-extension.ts | 8 +- .../src/available-errors/contract/contract.ts | 10 +- .../methods/eth_gasPrice/eth_gasPrice.ts | 10 +- .../thor-client/contracts/contracts-module.ts | 75 ++++-- .../contracts/model/contract-proxy.ts | 53 ++-- .../src/thor-client/contracts/types.d.ts | 9 +- packages/network/src/utils/vns/index.ts | 12 +- .../contracts/contract.erc20.solo.test.ts | 76 ++++-- .../contracts/contract.solo.test.ts | 48 ++-- .../contracts/contract.testnet.test.ts | 17 +- .../tests/thor-client/contracts/fixture.ts | 230 +++++++++++++----- 13 files changed, 465 insertions(+), 147 deletions(-) diff --git a/docs/contracts.md b/docs/contracts.md index 37b3b3736..8f4d639c2 100644 --- a/docs/contracts.md +++ b/docs/contracts.md @@ -149,10 +149,34 @@ const multipleClausesResult = contract.clause.decimals() ]); -expect(multipleClausesResult[0]).toEqual([expectedBalance]); -expect(multipleClausesResult[1]).toEqual(['SampleToken']); -expect(multipleClausesResult[2]).toEqual(['ST']); -expect(multipleClausesResult[3]).toEqual([18]); +expect(multipleClausesResult[0]).toEqual({ + success: true, + result: { + plain: expectedBalance, + array: [expectedBalance] + } +}); +expect(multipleClausesResult[1]).toEqual({ + success: true, + result: { + plain: 'SampleToken', + array: ['SampleToken'] + } +}); +expect(multipleClausesResult[2]).toEqual({ + success: true, + result: { + plain: 'ST', + array: ['ST'] + } +}); +expect(multipleClausesResult[3]).toEqual({ + success: true, + result: { + plain: 18, + array: [18] + } +}); ``` > ⚠️ **Warning:** diff --git a/docs/examples/contracts/contract-create-ERC20-token.ts b/docs/examples/contracts/contract-create-ERC20-token.ts index 9370e90e7..602b5e65b 100644 --- a/docs/examples/contracts/contract-create-ERC20-token.ts +++ b/docs/examples/contracts/contract-create-ERC20-token.ts @@ -70,9 +70,33 @@ const multipleClausesResult = contract.clause.decimals() ]); -expect(multipleClausesResult[0]).toEqual([expectedBalance]); -expect(multipleClausesResult[1]).toEqual(['SampleToken']); -expect(multipleClausesResult[2]).toEqual(['ST']); -expect(multipleClausesResult[3]).toEqual([18]); +expect(multipleClausesResult[0]).toEqual({ + success: true, + result: { + plain: expectedBalance, + array: [expectedBalance] + } +}); +expect(multipleClausesResult[1]).toEqual({ + success: true, + result: { + plain: 'SampleToken', + array: ['SampleToken'] + } +}); +expect(multipleClausesResult[2]).toEqual({ + success: true, + result: { + plain: 'ST', + array: ['ST'] + } +}); +expect(multipleClausesResult[3]).toEqual({ + success: true, + result: { + plain: 18, + array: [18] + } +}); // END_SNIPPET: ERC20MultiClausesReadSnippet diff --git a/docs/examples/evm-extension/evm-extension.ts b/docs/examples/evm-extension/evm-extension.ts index cbe8c5422..f4c9ca13d 100644 --- a/docs/examples/evm-extension/evm-extension.ts +++ b/docs/examples/evm-extension/evm-extension.ts @@ -791,4 +791,10 @@ const totalSupply = await thorSoloClient.contracts.executeCall( // END_SNIPPET: EVMExtensionSnippet // Check the result -expect(totalSupply).toStrictEqual([10000000000000000000000000000n]); +expect(totalSupply).toStrictEqual({ + result: { + array: [10000000000000000000000000000n], + plain: 10000000000000000000000000000n + }, + success: true +}); diff --git a/packages/errors/src/available-errors/contract/contract.ts b/packages/errors/src/available-errors/contract/contract.ts index 199e5d449..ae9f482eb 100644 --- a/packages/errors/src/available-errors/contract/contract.ts +++ b/packages/errors/src/available-errors/contract/contract.ts @@ -9,4 +9,12 @@ import { type ObjectErrorData } from '../types'; */ class ContractDeploymentFailed extends VechainSDKError {} -export { ContractDeploymentFailed }; +/** + * Error when calling a read function on a contract. + * + * WHEN TO USE: + * * Error will be thrown when a read (call) operation fails. + */ +class ContractCallError extends VechainSDKError {} + +export { ContractCallError, ContractDeploymentFailed }; diff --git a/packages/network/src/provider/utils/rpc-mapper/methods/eth_gasPrice/eth_gasPrice.ts b/packages/network/src/provider/utils/rpc-mapper/methods/eth_gasPrice/eth_gasPrice.ts index 597d747b9..15e196c12 100644 --- a/packages/network/src/provider/utils/rpc-mapper/methods/eth_gasPrice/eth_gasPrice.ts +++ b/packages/network/src/provider/utils/rpc-mapper/methods/eth_gasPrice/eth_gasPrice.ts @@ -6,13 +6,11 @@ import { type ThorClient } from '../../../../../thor-client'; * @returns The current gas price in Wei unit considering that 1 VTHO equals 1e18 Wei. */ const ethGasPrice = async (thorClient: ThorClient): Promise => { - const result = BigInt( - (await Promise.resolve( - thorClient.contracts.getBaseGasPrice() - )) as string - ); + const { + result: { plain } + } = await thorClient.contracts.getBaseGasPrice(); - return '0x' + result.toString(16); + return '0x' + BigInt(plain as bigint).toString(16); }; export { ethGasPrice }; diff --git a/packages/network/src/thor-client/contracts/contracts-module.ts b/packages/network/src/thor-client/contracts/contracts-module.ts index f89578aeb..0772012f7 100644 --- a/packages/network/src/thor-client/contracts/contracts-module.ts +++ b/packages/network/src/thor-client/contracts/contracts-module.ts @@ -1,11 +1,11 @@ import { ABIContract, + Address, + Clause, dataUtils, Hex, - Address, - VET, Units, - Clause, + VET, type ABIFunction } from '@vechain/sdk-core'; import { type Abi } from 'abitype'; @@ -68,6 +68,41 @@ class ContractsModule { return new Contract(address, abi, this.thor, signer); } + /** + * Extracts the decoded contract call result from the response of a simulated transaction. + * @param {string} encodedData Data returned from the simulated transaction. + * @param {ABIFunction} functionAbi Function ABI of the contract function. + * @param {boolean} reverted Whether the transaction was reverted. + * @returns {ContractCallResult} An object containing the decoded contract call result. + */ + private getContractCallResult( + encodedData: string, + functionAbi: ABIFunction, + reverted: boolean + ): ContractCallResult { + if (reverted) { + const errorMessage = decodeRevertReason(encodedData) ?? ''; + return { + success: false, + result: { + errorMessage + } + }; + } + + // Returning the decoded result both as plain and array. + const encodedResult = Hex.of(encodedData); + const plain = functionAbi.decodeResult(encodedResult); + const array = functionAbi.decodeOutputAsArray(encodedResult); + return { + success: true, + result: { + plain, + array + } + }; + } + /** * Executes a read-only call to a smart contract function, simulating the transaction to obtain the result. * @@ -84,7 +119,7 @@ class ContractsModule { functionAbi: ABIFunction, functionData: unknown[], contractCallOptions?: ContractCallOptions - ): Promise { + ): Promise { // Simulate the transaction to get the result of the contract call const response = await this.thor.transactions.simulateTransaction( [ @@ -97,39 +132,35 @@ class ContractsModule { contractCallOptions ); - if (response[0].reverted) { - /** - * The decoded revert reason of the transaction. - * Solidity may revert with Error(string) or Panic(uint256). - * - * @link see [Error handling: Assert, Require, Revert and Exceptions](https://docs.soliditylang.org/en/latest/control-structures.html#error-handling-assert-require-revert-and-exceptions) - */ - return decodeRevertReason(response[0].data) ?? ''; - } else { - // Returning an array of values. - // The viem format is a single value/JSON object (ABIFunction#decodeResult) - return functionAbi.decodeOutputAsArray(Hex.of(response[0].data)); - } + return this.getContractCallResult( + response[0].data, + functionAbi, + response[0].reverted + ); } /** * Executes a read-only call to multiple smart contract functions, simulating the transaction to obtain the results. * @param clauses - An array of contract clauses to interact with the contract functions. * @param options - (Optional) Additional options for the contract call, such as the sender's address, gas limit, and gas price, which can affect the simulation's context. + * @returns A promise that resolves to an array of decoded outputs of the smart contract function calls, the format of which depends on the functions' return types. */ public async executeMultipleClausesCall( clauses: ContractClause[], options?: SimulateTransactionOptions - ): Promise> { + ): Promise { // Simulate the transaction to get the result of the contract call const response = await this.thor.transactions.simulateTransaction( clauses.map((clause) => clause.clause), options ); - // Returning an array of values. - // The viem format is a single value/JSON object (ABIFunction#decodeResult) + // Returning the decoded results both as plain and array. return response.map((res, index) => - clauses[index].functionAbi.decodeOutputAsArray(Hex.of(res.data)) + this.getContractCallResult( + res.data, + clauses[index].functionAbi, + res.reverted + ) ); } @@ -226,7 +257,7 @@ class ContractsModule { * * @returns The base gas price in wei. */ - public async getBaseGasPrice(): Promise { + public async getBaseGasPrice(): Promise { return await this.executeCall( BUILT_IN_CONTRACTS.PARAMS_ADDRESS, ABIContract.ofAbi(BUILT_IN_CONTRACTS.PARAMS_ABI).getFunction('get'), diff --git a/packages/network/src/thor-client/contracts/model/contract-proxy.ts b/packages/network/src/thor-client/contracts/model/contract-proxy.ts index 747b67f21..e45339415 100644 --- a/packages/network/src/thor-client/contracts/model/contract-proxy.ts +++ b/packages/network/src/thor-client/contracts/model/contract-proxy.ts @@ -5,7 +5,10 @@ import { Units, VET } from '@vechain/sdk-core'; -import { InvalidTransactionField } from '@vechain/sdk-errors'; +import { + ContractCallError, + InvalidTransactionField +} from '@vechain/sdk-errors'; import type { Abi, AbiEvent, @@ -17,7 +20,7 @@ import type { import { type VeChainSigner } from '../../../signer'; import { type FilterCriteria } from '../../logs'; import { type SendTransactionResult } from '../../transactions/types'; -import { type ContractCallResult, type ContractClause } from '../types'; +import { type ContractClause } from '../types'; import { type Contract } from './contract'; import { ContractFilter } from './contract-filter'; import { @@ -48,7 +51,7 @@ function getReadProxy( ExtractAbiFunction['inputs'], 'inputs' > - ): Promise => { + ): Promise => { // check if the clause comment is provided as an argument const extractOptionsResult = extractAndRemoveAdditionalOptions( @@ -61,21 +64,35 @@ function getReadProxy( const revisionValue = extractOptionsResult.clauseAdditionalOptions?.revision; - return (await contract.thor.contracts.executeCall( - contract.address, - contract.getFunctionAbi(prop), - extractOptionsResult.args, - { - caller: - contract.getSigner() !== undefined - ? await contract.getSigner()?.getAddress() - : undefined, - ...contract.getContractReadOptions(), - comment: clauseComment, - revision: revisionValue, - includeABI: true - } - )) as ContractCallResult; + const functionAbi = contract.getFunctionAbi(prop); + + const executeCallResult = + await contract.thor.contracts.executeCall( + contract.address, + functionAbi, + extractOptionsResult.args, + { + caller: + contract.getSigner() !== undefined + ? await contract.getSigner()?.getAddress() + : undefined, + ...contract.getContractReadOptions(), + comment: clauseComment, + revision: revisionValue, + includeABI: true + } + ); + + if (!executeCallResult.success) { + throw new ContractCallError( + functionAbi.stringSignature, + executeCallResult.result.errorMessage as string, + { + contractAddress: contract.address + } + ); + } + return executeCallResult.result.array as unknown[]; }; } }); diff --git a/packages/network/src/thor-client/contracts/types.d.ts b/packages/network/src/thor-client/contracts/types.d.ts index 2caf0ea81..bc25d82c6 100644 --- a/packages/network/src/thor-client/contracts/types.d.ts +++ b/packages/network/src/thor-client/contracts/types.d.ts @@ -43,7 +43,14 @@ type ContractCallOptions = SimulateTransactionOptions & ClauseOptions; /** * Represents the result of a contract call operation, encapsulating the output of the call. */ -type ContractCallResult = unknown[]; +interface ContractCallResult { + success: boolean; + result: { + plain?: unknown; // Success result as a plain value (might be literal or object). + array?: unknown[]; // Success result as an array (values are the same as in plain). + errorMessage?: string; + }; +} /** * Represents a contract clause, which includes the clause and the corresponding function ABI. diff --git a/packages/network/src/utils/vns/index.ts b/packages/network/src/utils/vns/index.ts index e01aac93b..a688e2dcf 100644 --- a/packages/network/src/utils/vns/index.ts +++ b/packages/network/src/utils/vns/index.ts @@ -42,14 +42,16 @@ const resolveNames = async ( const resolveUtilsAddress = NetworkContracts[genesisBlock.id].resolveUtils; // use the resolveUtils to lookup names - const [addresses] = (await thorClient.contracts.executeCall( + const callGetAddresses = await thorClient.contracts.executeCall( resolveUtilsAddress, ABIItem.ofSignature( ABIFunction, 'function getAddresses(string[] names) returns (address[] addresses)' ), [names] - )) as string[][]; + ); + + const [addresses] = callGetAddresses.result.array as string[][]; return addresses.map((address) => { // zero addresses are missing configuration entries @@ -101,14 +103,16 @@ const lookupAddresses = async ( const resolveUtilsAddress = NetworkContracts[genesisBlock.id].resolveUtils; // use the resolveUtils to lookup names - const [names] = (await thorClient.contracts.executeCall( + const callGetNames = await thorClient.contracts.executeCall( resolveUtilsAddress, ABIItem.ofSignature( ABIFunction, 'function getNames(address[] addresses) returns (string[] names)' ), [addresses] - )) as string[][]; + ); + + const [names] = callGetNames.result.array as string[][]; return names.map((name) => { // empty strings indicate a missing entry diff --git a/packages/network/tests/thor-client/contracts/contract.erc20.solo.test.ts b/packages/network/tests/thor-client/contracts/contract.erc20.solo.test.ts index 50eea22e2..8dce9b158 100644 --- a/packages/network/tests/thor-client/contracts/contract.erc20.solo.test.ts +++ b/packages/network/tests/thor-client/contracts/contract.erc20.solo.test.ts @@ -1,4 +1,5 @@ import { beforeEach, describe, expect, test } from '@jest/globals'; +import { Address, ERC20_ABI, HexUInt } from '@vechain/sdk-core'; import { ProviderInternalBaseWallet, THOR_SOLO_URL, @@ -10,7 +11,6 @@ import { } from '../../../src'; import { TEST_ACCOUNTS } from '../../fixture'; import { erc20ContractBytecode } from './fixture'; -import { Address, ERC20_ABI, HexUInt } from '@vechain/sdk-core'; /** * Tests for the ThorClient class, specifically focusing on ERC20 contract-related functionality. @@ -131,7 +131,7 @@ describe('ThorClient - ERC20 Contracts', () => { // Ensure that the transfer transaction was successful and the balance is as expected expect(transactionReceiptTransfer.reverted).toBe(false); - expect(balanceOfResult).toEqual([BigInt(1000)]); + expect(balanceOfResult).toEqual([1000n]); }, 10000); // Set a timeout of 10000ms for this test test('Execute ERC20 contract operations with comments', async () => { @@ -168,7 +168,7 @@ describe('ThorClient - ERC20 Contracts', () => { // Ensure that the transfer transaction was successful and the balance is as expected expect(transactionReceiptTransfer.reverted).toBe(false); - expect(balanceOfResult).toEqual([BigInt(1000)]); + expect(balanceOfResult).toEqual([1000n]); }, 10000); // Set a timeout of 10000ms for this test test('Execute ERC20 contract operations with revision', async () => { @@ -205,7 +205,7 @@ describe('ThorClient - ERC20 Contracts', () => { // Ensure that the transfer transaction was successful and the balance is as expected expect(transactionReceiptTransfer.reverted).toBe(false); - expect(balanceOfResult).toEqual([BigInt(1000)]); + expect(balanceOfResult).toEqual([1000n]); }, 10000); /** @@ -269,7 +269,7 @@ describe('ThorClient - ERC20 Contracts', () => { await contract.read.balanceOf( TEST_ACCOUNTS.TRANSACTION.DELEGATOR.address ) - ).toEqual([BigInt(1000)]); + ).toEqual([1000n]); }, 10000); /** @@ -294,9 +294,27 @@ describe('ThorClient - ERC20 Contracts', () => { contract.clause.decimals() ]); - expect(contractRead[0]).toEqual(['SampleToken']); - expect(contractRead[1]).toEqual(['ST']); - expect(contractRead[2]).toEqual([18]); + expect(contractRead[0]).toEqual({ + success: true, + result: { + plain: 'SampleToken', + array: ['SampleToken'] + } + }); + expect(contractRead[1]).toEqual({ + success: true, + result: { + plain: 'ST', + array: ['ST'] + } + }); + expect(contractRead[2]).toEqual({ + success: true, + result: { + plain: 18, + array: [18] + } + }); }, 10000); /** @@ -321,9 +339,27 @@ describe('ThorClient - ERC20 Contracts', () => { contract.clause.decimals() ]); - expect(contractRead[0]).toEqual(['SampleToken']); - expect(contractRead[1]).toEqual(['ST']); - expect(contractRead[2]).toEqual([18]); + expect(contractRead[0]).toEqual({ + success: true, + result: { + plain: 'SampleToken', + array: ['SampleToken'] + } + }); + expect(contractRead[1]).toEqual({ + success: true, + result: { + plain: 'ST', + array: ['ST'] + } + }); + expect(contractRead[2]).toEqual({ + success: true, + result: { + plain: 18, + array: [18] + } + }); }, 10000); /** @@ -377,9 +413,21 @@ describe('ThorClient - ERC20 Contracts', () => { ] ); - expect(reads[0]).toEqual([BigInt(1000)]); + expect(reads[0]).toEqual({ + success: true, + result: { + plain: 1000n, + array: [1000n] + } + }); - expect(reads[1]).toEqual([BigInt(4000)]); + expect(reads[1]).toEqual({ + success: true, + result: { + plain: 4000n, + array: [4000n] + } + }); }, 10000); /** @@ -412,6 +460,6 @@ describe('ThorClient - ERC20 Contracts', () => { await contract.read.balanceOf( TEST_ACCOUNTS.TRANSACTION.DELEGATOR.address ) - ).toEqual([BigInt(1000)]); + ).toEqual([1000n]); }, 30000); }); diff --git a/packages/network/tests/thor-client/contracts/contract.solo.test.ts b/packages/network/tests/thor-client/contracts/contract.solo.test.ts index d02a9b151..a2a55a8d1 100644 --- a/packages/network/tests/thor-client/contracts/contract.solo.test.ts +++ b/packages/network/tests/thor-client/contracts/contract.solo.test.ts @@ -1,12 +1,13 @@ /* eslint-disable */ import { beforeEach, describe, expect, test } from '@jest/globals'; -import { ABIContract, Address, HexUInt, type DeployParams } from '@vechain/sdk-core'; +import { ABIContract, Address, type DeployParams, HexUInt } from '@vechain/sdk-core'; import { CannotFindTransaction, ContractDeploymentFailed, InvalidTransactionField } from '@vechain/sdk-errors'; +import { fail } from 'assert'; import { Contract, type ContractFactory, @@ -227,7 +228,7 @@ describe('ThorClient - Contracts', () => { const callFunctionGetResult = await contract.read.get(); - expect(callFunctionGetResult).toEqual([BigInt(123)]); + expect(callFunctionGetResult).toEqual([123n]); }, 10000); /** @@ -241,7 +242,7 @@ describe('ThorClient - Contracts', () => { const contract = await factory.waitForDeployment(); await (await contract.transact.set(123n)).wait(); - expect(await contract.read.get()).toEqual([BigInt(123)]); + expect(await contract.read.get()).toEqual([123n]); contract.setContractReadOptions({ caller: 'invalid address' }); @@ -258,7 +259,7 @@ describe('ThorClient - Contracts', () => { contract.clearContractTransactOptions(); await (await contract.transact.set(22323n)).wait(); - expect(await contract.read.get()).toEqual([BigInt(22323)]); + expect(await contract.read.get()).toEqual([22323n]); }, 15000); /** @@ -290,7 +291,7 @@ describe('ThorClient - Contracts', () => { const callFunctionGetResult = await contract.read.get(); - expect(callFunctionGetResult).toEqual([BigInt(123)]); + expect(callFunctionGetResult).toEqual([123n]); }, 10000); /** @@ -312,7 +313,7 @@ describe('ThorClient - Contracts', () => { // Call the get function of the loaded contract to verify that the stored value is 100 let callFunctionGetResult = await loadedContract.read.get(); - expect(callFunctionGetResult).toEqual([BigInt(100)]); + expect(callFunctionGetResult).toEqual([100n]); // Set the private key of the caller for signing transactions loadedContract.setSigner(contract.getSigner() as VeChainSigner); @@ -329,7 +330,7 @@ describe('ThorClient - Contracts', () => { callFunctionGetResult = await loadedContract.read.get(); // Assertion: The value should be 123 - expect(callFunctionGetResult).toEqual([BigInt(123)]); + expect(callFunctionGetResult).toEqual([123n]); }, 10000); /** @@ -429,7 +430,7 @@ describe('ThorClient - Contracts', () => { await deployedDepositContract.read.getBalance( TEST_ACCOUNTS.TRANSACTION.TRANSACTION_SENDER.address ) - ).toEqual([BigInt(1000)]); + ).toEqual([1000n]); }, 10000); test('Deploy a contract that returns two values', async () => { @@ -469,17 +470,28 @@ describe('ThorClient - Contracts', () => { const deployedContract = await factory.waitForDeployment(); - const secretData = await deployedContract.read.getSecretData(); + const [secretData] = await deployedContract.read.getSecretData(); - expect(secretData[0]).toEqual(42n); + expect(secretData).toEqual(42n); const loadedContract = thorSoloClient.contracts.load( deployedContract.address, OWNER_RESTRICTION_ABI, receiverSigner ); - const secretDataNotOwner = await loadedContract.read.getSecretData(); - expect(secretDataNotOwner).toEqual('Not the contract owner'); + try { + await loadedContract.read.getSecretData(); + fail('Should fail'); + } catch (error) { + if (error instanceof Error) { + expect(error.message).toEqual( + `Method 'getSecretData()' failed.` + + `\n-Reason: 'Not the contract owner'` + + `\n-Parameters: \n\t` + + `{\n "contractAddress": "${deployedContract.address}"\n}` + ); + } + } }); /** @@ -599,7 +611,7 @@ describe('ThorClient - Contracts', () => { ), params ); - expect(response).toBe(expected); + expect(response).toStrictEqual(expected); }); } ); @@ -797,8 +809,14 @@ describe('ThorClient - Contracts', () => { test('Should return the base gas price of the Solo network', async () => { const baseGasPrice = await thorSoloClient.contracts.getBaseGasPrice(); - expect(baseGasPrice).toEqual([1000000000000000n]); - expect(baseGasPrice).toEqual([BigInt(10 ** 15)]); // 10^13 wei + expect(baseGasPrice).toEqual( { + success: true, + result: { plain: 1000000000000000n, array: [1000000000000000n] } + }); + expect(baseGasPrice).toEqual( { + success: true, + result: { plain: BigInt(10 ** 15), array: [BigInt(10 ** 15)] } + }); // 10^13 wei }); }); }); diff --git a/packages/network/tests/thor-client/contracts/contract.testnet.test.ts b/packages/network/tests/thor-client/contracts/contract.testnet.test.ts index 2cabce075..2d0b7f4f7 100644 --- a/packages/network/tests/thor-client/contracts/contract.testnet.test.ts +++ b/packages/network/tests/thor-client/contracts/contract.testnet.test.ts @@ -19,7 +19,20 @@ describe('ThorClient - Gas Module', () => { */ test('Should return the base gas price of the Testnet', async () => { const baseGasPrice = await thorClient.contracts.getBaseGasPrice(); - expect(baseGasPrice).toEqual([10000000000000n]); - expect(baseGasPrice).toEqual([BigInt(10 ** 13)]); // 10^13 wei + const expected = { + success: true, + result: { + plain: 10000000000000n, + array: [10000000000000n] + } + }; + expect(baseGasPrice).toEqual(expected); + expect(baseGasPrice).toEqual({ + ...expected, + result: { + plain: BigInt(10 ** 13), + array: [BigInt(10 ** 13)] + } + }); // 10^13 wei }); }); diff --git a/packages/network/tests/thor-client/contracts/fixture.ts b/packages/network/tests/thor-client/contracts/fixture.ts index 4afc2a280..cdd428f60 100644 --- a/packages/network/tests/thor-client/contracts/fixture.ts +++ b/packages/network/tests/thor-client/contracts/fixture.ts @@ -322,7 +322,13 @@ const erc721ContractTestCases: TestCase[] = [ 'should get the current NFT balance of the CONTRACT_MANAGER address', functionName: 'balanceOf', params: [TEST_ACCOUNTS.TRANSACTION.CONTRACT_MANAGER.address], - expected: [2n], + expected: { + success: true, + result: { + plain: 2n, + array: [2n] + } + }, reverted: false, isReadOnly: true }, @@ -331,7 +337,13 @@ const erc721ContractTestCases: TestCase[] = [ 'should get the current NFT balance of the DELEGATOR address', functionName: 'balanceOf', params: [TEST_ACCOUNTS.TRANSACTION.DELEGATOR.address], - expected: [1n], + expected: { + success: true, + result: { + plain: 1n, + array: [1n] + } + }, reverted: false, isReadOnly: true }, @@ -360,7 +372,13 @@ const erc721ContractTestCases: TestCase[] = [ 'should get the current NFT balance of the CONTRACT_MANAGER address', functionName: 'balanceOf', params: [TEST_ACCOUNTS.TRANSACTION.CONTRACT_MANAGER.address], - expected: [1n], + expected: { + success: true, + result: { + plain: 1n, + array: [1n] + } + }, reverted: false, isReadOnly: true }, @@ -369,7 +387,13 @@ const erc721ContractTestCases: TestCase[] = [ 'should get the current NFT balance of the DELEGATOR address', functionName: 'balanceOf', params: [TEST_ACCOUNTS.TRANSACTION.DELEGATOR.address], - expected: [2n], + expected: { + success: true, + result: { + plain: 2n, + array: [2n] + } + }, reverted: false, isReadOnly: true } @@ -380,7 +404,7 @@ const testingContractTestCases: TestCase[] = [ description: 'should return the bool value false', functionName: 'boolData', params: [false], - expected: [false], + expected: { result: { array: [false], plain: false }, success: true }, reverted: false, isReadOnly: true }, @@ -388,7 +412,7 @@ const testingContractTestCases: TestCase[] = [ description: 'should return the bool value true', functionName: 'boolData', params: [true], - expected: [true], + expected: { result: { array: [true], plain: true }, success: true }, reverted: false, isReadOnly: true }, @@ -396,7 +420,7 @@ const testingContractTestCases: TestCase[] = [ description: 'should return the int value 1', functionName: 'intData', params: [1], - expected: [1n], + expected: { result: { array: [1n], plain: 1n }, success: true }, reverted: false, isReadOnly: true }, @@ -404,7 +428,7 @@ const testingContractTestCases: TestCase[] = [ description: 'should return the int value -1', functionName: 'intData', params: [-1], - expected: [-1n], + expected: { result: { array: [-1n], plain: -1n }, success: true }, reverted: false, isReadOnly: true }, @@ -412,7 +436,7 @@ const testingContractTestCases: TestCase[] = [ description: 'should return the int value 0', functionName: 'intData', params: [0], - expected: [0n], + expected: { result: { array: [0n], plain: 0n }, success: true }, reverted: false, isReadOnly: true }, @@ -420,7 +444,7 @@ const testingContractTestCases: TestCase[] = [ description: 'should return the uint value 0', functionName: 'uintData', params: [0], - expected: [0n], + expected: { result: { array: [0n], plain: 0n }, success: true }, reverted: false, isReadOnly: true }, @@ -428,7 +452,7 @@ const testingContractTestCases: TestCase[] = [ description: 'should return the uint value 1', functionName: 'uintData', params: [1], - expected: [1n], + expected: { result: { array: [1n], plain: 1n }, success: true }, reverted: false, isReadOnly: true }, @@ -437,7 +461,13 @@ const testingContractTestCases: TestCase[] = [ 'should return the address value 0x0000000000000000000000000000000000000000', functionName: 'addressData', params: ['0x0000000000000000000000000000000000000000'], - expected: ['0x0000000000000000000000000000000000000000'], + expected: { + result: { + array: ['0x0000000000000000000000000000000000000000'], + plain: '0x0000000000000000000000000000000000000000' + }, + success: true + }, reverted: false, isReadOnly: true }, @@ -448,9 +478,15 @@ const testingContractTestCases: TestCase[] = [ params: [ '0x123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0' ], - expected: [ - '0x123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0' - ], + expected: { + result: { + array: [ + '0x123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0' + ], + plain: '0x123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0' + }, + success: true + }, reverted: false, isReadOnly: true }, @@ -458,7 +494,7 @@ const testingContractTestCases: TestCase[] = [ description: 'should return the string value "a"', functionName: 'stringData', params: ['a'], - expected: ['a'], + expected: { result: { array: ['a'], plain: 'a' }, success: true }, reverted: false, isReadOnly: true }, @@ -466,7 +502,10 @@ const testingContractTestCases: TestCase[] = [ description: 'should return the passed fixed array', functionName: 'fixedArrayData', params: [[123, 456, 789]], - expected: [[123n, 456n, 789n]], + expected: { + result: { array: [[123n, 456n, 789n]], plain: [123n, 456n, 789n] }, + success: true + }, reverted: false, isReadOnly: true }, @@ -474,7 +513,13 @@ const testingContractTestCases: TestCase[] = [ description: 'should return the passed dynamic array', functionName: 'dynamicArrayData', params: [[123, 456, 789, 323, 123]], - expected: [[123n, 456n, 789n, 323n, 123n]], + expected: { + result: { + array: [[123n, 456n, 789n, 323n, 123n]], + plain: [123n, 456n, 789n, 323n, 123n] + }, + success: true + }, reverted: false, isReadOnly: true }, @@ -482,7 +527,13 @@ const testingContractTestCases: TestCase[] = [ description: 'should return the passed struct', functionName: 'structData', params: [{ id: 10, name: 'test' }], - expected: [[10n, 'test']], + expected: { + result: { + array: [[10n, 'test']], + plain: { id: 10n, name: 'test' } + }, + success: true + }, reverted: false, isReadOnly: true }, @@ -490,7 +541,10 @@ const testingContractTestCases: TestCase[] = [ description: 'should return the passed enum', functionName: 'enumData', params: [ExampleEnum.SMALL], - expected: [ExampleEnum.SMALL], + expected: { + result: { array: [ExampleEnum.SMALL], plain: ExampleEnum.SMALL }, + success: true + }, reverted: false, isReadOnly: true }, @@ -507,16 +561,31 @@ const testingContractTestCases: TestCase[] = [ { id: 10, name: 'test' }, ExampleEnum.SMALL ], - expected: [ - 1n, - '0x0000000000000000000000000000000000000000', - '0x123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0', - 'a', - [123n, 456n, 789n], - [123n, 456n, 789n, 323n, 123n], - [10n, 'test'], - ExampleEnum.SMALL - ], + expected: { + result: { + array: [ + 1n, + '0x0000000000000000000000000000000000000000', + '0x123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0', + 'a', + [123n, 456n, 789n], + [123n, 456n, 789n, 323n, 123n], + [10n, 'test'], + ExampleEnum.SMALL + ], + plain: [ + 1n, + '0x0000000000000000000000000000000000000000', + '0x123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0', + 'a', + [123n, 456n, 789n], + [123n, 456n, 789n, 323n, 123n], + { id: 10n, name: 'test' }, + 0 + ] + }, + success: true + }, reverted: false, isReadOnly: true }, @@ -524,7 +593,13 @@ const testingContractTestCases: TestCase[] = [ description: 'should return the passed multiple int values', functionName: 'multipleIntData', params: [1, 222, 333, 287274, 390343843, 123223663], - expected: [1, 222, 333, 287274n, 390343843n, 123223663n], + expected: { + result: { + array: [1, 222, 333, 287274n, 390343843n, 123223663n], + plain: [1, 222, 333, 287274n, 390343843n, 123223663n] + }, + success: true + }, reverted: false, isReadOnly: true } @@ -535,7 +610,10 @@ const testingContractNegativeTestCases: TestCase[] = [ description: 'testRequireError() test', functionName: 'testRequireError', params: [8], - expected: 'Value must be greater than 10', + expected: { + result: { errorMessage: 'Value must be greater than 10' }, + success: false + }, reverted: true, isReadOnly: true }, @@ -543,7 +621,7 @@ const testingContractNegativeTestCases: TestCase[] = [ description: 'testAssertError() test', functionName: 'testAssertError', params: [1], - expected: 'Panic(0x01)', + expected: { result: { errorMessage: 'Panic(0x01)' }, success: false }, reverted: true, isReadOnly: true }, @@ -551,7 +629,10 @@ const testingContractNegativeTestCases: TestCase[] = [ description: 'testRevertError() test', functionName: 'testRevertError', params: [4], - expected: 'Value must be at least 5', + expected: { + result: { errorMessage: 'Value must be at least 5' }, + success: false + }, reverted: true, isReadOnly: true }, @@ -559,7 +640,7 @@ const testingContractNegativeTestCases: TestCase[] = [ description: 'testOverflowError() test', functionName: 'testOverflowError', params: [255], - expected: 'Panic(0x11)', + expected: { result: { errorMessage: 'Panic(0x11)' }, success: false }, reverted: true, isReadOnly: true }, @@ -567,7 +648,7 @@ const testingContractNegativeTestCases: TestCase[] = [ description: 'testInvalidOpcodeError() test', functionName: 'testInvalidOpcodeError', params: [], - expected: '', + expected: { result: { errorMessage: '' }, success: false }, reverted: true, isReadOnly: true } @@ -578,9 +659,15 @@ const testingContractEVMExtensionTestCases: TestCase[] = [ description: 'should return the blockID of the given block number', functionName: 'getBlockID', params: [1], - expected: [ - '0x00000001fb5387f59d35a8e76dcce151cb229a3910ac5f4731ff55f7ca36a809' - ], + expected: { + result: { + array: [ + '0x00000001fb5387f59d35a8e76dcce151cb229a3910ac5f4731ff55f7ca36a809' + ], + plain: '0x00000001fb5387f59d35a8e76dcce151cb229a3910ac5f4731ff55f7ca36a809' + }, + success: true + }, reverted: false, isReadOnly: true }, @@ -589,7 +676,7 @@ const testingContractEVMExtensionTestCases: TestCase[] = [ 'should return the block total score of the given block defined by the block number', functionName: 'getBlockTotalScore', params: [1], - expected: [1n], + expected: { result: { array: [1n], plain: 1n }, success: true }, reverted: false, isReadOnly: true }, @@ -597,7 +684,10 @@ const testingContractEVMExtensionTestCases: TestCase[] = [ description: 'should return the block time of the given block number', functionName: 'getBlockTime', params: [1], - expected: [1702231120n], + expected: { + result: { array: [1702231120n], plain: 1702231120n }, + success: true + }, reverted: false, isReadOnly: true }, @@ -605,7 +695,13 @@ const testingContractEVMExtensionTestCases: TestCase[] = [ description: 'should return the block signer of the given block number', functionName: 'getBlockSigner', params: [1], - expected: ['0xf077b491b355E64048cE21E3A6Fc4751eEeA77fa'], + expected: { + result: { + array: ['0xf077b491b355E64048cE21E3A6Fc4751eEeA77fa'], + plain: '0xf077b491b355E64048cE21E3A6Fc4751eEeA77fa' + }, + success: true + }, reverted: false, isReadOnly: true }, @@ -613,7 +709,13 @@ const testingContractEVMExtensionTestCases: TestCase[] = [ description: 'should return the total supply of VET', functionName: 'getTotalSupply', params: [], - expected: [10000000000000000000000000000n], + expected: { + result: { + array: [10000000000000000000000000000n], + plain: 10000000000000000000000000000n + }, + success: true + }, reverted: false, isReadOnly: true }, @@ -622,7 +724,7 @@ const testingContractEVMExtensionTestCases: TestCase[] = [ 'should return the `provedWork` of the current transaction', functionName: 'getTxProvedWork', params: [], - expected: [0n], + expected: { result: { array: [0n], plain: 0n }, success: true }, reverted: false, isReadOnly: true }, @@ -631,9 +733,15 @@ const testingContractEVMExtensionTestCases: TestCase[] = [ 'should return the transaction ID of the current transaction', functionName: 'getTxID', params: [], - expected: [ - '0x0000000000000000000000000000000000000000000000000000000000000000' - ], + expected: { + result: { + array: [ + '0x0000000000000000000000000000000000000000000000000000000000000000' + ], + plain: '0x0000000000000000000000000000000000000000000000000000000000000000' + }, + success: true + }, reverted: false, isReadOnly: true }, @@ -641,7 +749,13 @@ const testingContractEVMExtensionTestCases: TestCase[] = [ description: 'should return the `blockRef` of the current transaction', functionName: 'getTxBlockRef', params: [], - expected: ['0x0000000000000000'], + expected: { + result: { + array: ['0x0000000000000000'], + plain: '0x0000000000000000' + }, + success: true + }, reverted: false, isReadOnly: true }, @@ -650,7 +764,7 @@ const testingContractEVMExtensionTestCases: TestCase[] = [ 'should return the `expiration` of the current transaction', functionName: 'getTxExpiration', params: [], - expected: [0n], + expected: { result: { array: [0n], plain: 0n }, success: true }, reverted: false, isReadOnly: true }, @@ -658,9 +772,15 @@ const testingContractEVMExtensionTestCases: TestCase[] = [ description: 'should return the data hashed using Blake2b256', functionName: 'calculateBlake2b256', params: ['0x'], - expected: [ - '0x0e5751c026e543b2e8ab2eb06099daa1d1e5df47778f7787faab45cdf12fe3a8' - ], + expected: { + result: { + array: [ + '0x0e5751c026e543b2e8ab2eb06099daa1d1e5df47778f7787faab45cdf12fe3a8' + ], + plain: '0x0e5751c026e543b2e8ab2eb06099daa1d1e5df47778f7787faab45cdf12fe3a8' + }, + success: true + }, reverted: false, isReadOnly: true } @@ -3700,12 +3820,12 @@ export { multipleClausesTestCases, OWNER_RESTRICTION_ABI, OWNER_RESTRICTION_BYTECODE, + sampleTwoValuesReturnAbi, + sampleTwoValuesReturnBytecode, testingContractEVMExtensionTestCases, testingContractNegativeTestCases, testingContractTestCases, TESTNET_DELEGATE_URL, xAllocationAddress, - xAllocationVotingGovernorABI, - sampleTwoValuesReturnAbi, - sampleTwoValuesReturnBytecode + xAllocationVotingGovernorABI };