Skip to content

Commit

Permalink
feat: show function name along its hash if missed in bytecode
Browse files Browse the repository at this point in the history
  • Loading branch information
davidyuk committed Dec 9, 2024
1 parent ec40d77 commit 9b0379f
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 9 deletions.
8 changes: 6 additions & 2 deletions src/contract/Contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,12 @@ class Contract<M extends ContractMethodsBase> {
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}`,
throw new BytecodeMismatchError('ACI', `. Error provided by node: "${message}".`);
}
if (/Trying to call undefined function: <<\d+,\d+,\d+,\d+>>/.test(message)) {
throw new BytecodeMismatchError(
'ACI',
`. Error provided by node: "${message}", function name: ${fnName}.`,
);
}
break;
Expand Down
4 changes: 2 additions & 2 deletions src/utils/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -449,8 +449,8 @@ export class InvalidAuthDataError extends CompilerError {
* @category exception
*/
export class BytecodeMismatchError extends ContractError {
constructor(source: 'source code' | 'bytecode') {
super(`Contract ${source} do not correspond to the bytecode deployed on the chain`);
constructor(source: 'source code' | 'bytecode' | 'ACI', details: string = '') {
super(`Contract ${source} do not correspond to the bytecode deployed on the chain` + details);
this.name = 'BytecodeMismatchError';
}
}
Expand Down
24 changes: 19 additions & 5 deletions test/integration/contract-aci.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import {
Tag,
NoSuchContractFunctionError,
InvalidTxError,
ContractError,
isAddressValid,
Encoding,
} from '../../src';
Expand All @@ -32,7 +31,7 @@ import includesAci from './contracts/Includes.json';

const identityContractSourceCode = `
contract Identity =
entrypoint getArg(x: int) = x
entrypoint getArg(x: int) = x
`;

const libContractSource = `
Expand Down Expand Up @@ -336,13 +335,27 @@ describe('Contract instance', () => {
await contract.intFn(2, { callStatic: true });
});

it('fails with error if function missed', async () => {
it('fails with error if function missed in aci', async () => {
await expect(testContract.$call('notExisting', [])).to.be.rejectedWith(
NoSuchContractFunctionError,
"Function notExisting doesn't exist in contract",
);
});

it('fails with error if function missed in bytecode', async () => {
const contract = await Contract.initialize<{ notExistInBytecode: () => 42 }>({
...aeSdk.getContext(),
sourceCode: identityContractSourceCode + '\n entrypoint notExistInBytecode() = 42',
address: testContract.$options.address,
});
await expect(contract.notExistInBytecode()).to.be.rejectedWith(
BytecodeMismatchError,
'Contract ACI do not correspond to the bytecode deployed on the chain. Error provided' +
' by node: "Trying to call undefined function: <<240,40,94,10>>", function name:' +
' notExistInBytecode.',
);
});

it('gets actual options from AeSdkBase', async () => {
const [address1, address2] = aeSdk.addresses();
let { result } = await testContract.intFn(2);
Expand Down Expand Up @@ -417,8 +430,9 @@ describe('Contract instance', () => {
intFn: (a: InputNumber, b: InputNumber) => bigint;
}>({ ...aeSdk.getContext(), 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",
BytecodeMismatchError,
'Contract ACI do not correspond to the bytecode deployed on the chain. Error provided' +
' by node: "Expected 1 arguments, got 2"',
);
});

Expand Down

0 comments on commit 9b0379f

Please sign in to comment.