diff --git a/src/contract/Contract.ts b/src/contract/Contract.ts index 7e4bf8eb45..8f41f3e34e 100644 --- a/src/contract/Contract.ts +++ b/src/contract/Contract.ts @@ -171,6 +171,9 @@ class Contract { break; case 'error': message = decode(returnValue).toString(); + if (/Expected \d+ arguments, got \d+/.test(message)) { + throw new ContractError(`ACI doesn't match called contract. Error provided by node: ${message}`); + } break; default: throw new InternalError(`Unknown return type: ${returnType}`); diff --git a/test/integration/contract-aci.ts b/test/integration/contract-aci.ts index a357ccca0d..2223715127 100644 --- a/test/integration/contract-aci.ts +++ b/test/integration/contract-aci.ts @@ -19,6 +19,7 @@ import { NoSuchContractFunctionError, ConsensusProtocolVersion, InvalidTxError, + ContractError, } from '../../src'; import { getSdk } from '.'; import { @@ -362,6 +363,18 @@ describe('Contract instance', () => { expect((await contract.intFn(3)).decodedResult).to.be.equal(3n); }); + it('fails if aci doesn\'t match called contract', async () => { + const aci = structuredClone(testContractAci); + const fn = aci.at(-1)?.contract?.functions.find(({ name }) => name === 'intFn'); + assertNotNull(fn); + fn.arguments.push(fn.arguments[0]); + const contract = await aeSdk.initializeContract<{ + intFn: (a: InputNumber, b: InputNumber) => bigint; + }>({ aci, address: testContract.$options.address }); + await expect(contract.intFn(3, 2)).to.be + .rejectedWith(ContractError, 'ACI doesn\'t match called contract. Error provided by node: Expected 1 arguments, got 2'); + }); + it('deploys and calls by bytecode and aci', async () => { const contract = await aeSdk.initializeContract( { bytecode: testContractBytecode, aci: testContractAci },