Skip to content

Commit

Permalink
improve the API
Browse files Browse the repository at this point in the history
  • Loading branch information
Dhaiwat10 committed Apr 4, 2024
1 parent 13545da commit 36a88ab
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 26 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { bn } from 'fuels';

import { DocSnippetProjectsEnum } from '../../../test/fixtures/forc-projects';
import { createAndDeployContractFromProject } from '../../utils';

Expand All @@ -10,7 +8,7 @@ test('isReadOnly returns true for read-only functions', async () => {
const contract = await createAndDeployContractFromProject(DocSnippetProjectsEnum.COUNTER);

// #region is-function-readonly-1
const isReadOnly = contract.functions.get_count().isReadOnly();
const isReadOnly = contract.functions.get_count.isReadOnly();

if (isReadOnly) {
await contract.functions.get_count().get();
Expand All @@ -21,11 +19,3 @@ test('isReadOnly returns true for read-only functions', async () => {

expect(isReadOnly).toBe(true);
});

test('isReadOnly returns false for functions containing write operations', async () => {
const contract = await createAndDeployContractFromProject(DocSnippetProjectsEnum.COUNTER);

const isReadOnly = contract.functions.increment_count(bn(1)).isReadOnly();

expect(isReadOnly).toBe(false);
});
10 changes: 10 additions & 0 deletions packages/abi-coder/src/FunctionFragment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,4 +210,14 @@ export class FunctionFragment<

return coder.decode(bytes, 0) as [DecodedValue | undefined, number];
}

/**
* Checks if the function is read-only i.e. it only reads from storage, does not write to it.
*
* @returns True if the function is read-only, false otherwise.
*/
isReadOnly() {
const storageAttribute = this.attributes.find((attr) => attr.name === 'storage');
return !storageAttribute?.arguments.includes('write');
}
}
22 changes: 22 additions & 0 deletions packages/fuel-gauge/src/is-function-readonly.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { FuelGaugeProjectsEnum } from '../test/fixtures';

import { getSetupContract } from './utils';

/**
* @group node
*/
test('isReadOnly returns true for a read-only function', async () => {
const contract = await getSetupContract(FuelGaugeProjectsEnum.STORAGE_TEST_CONTRACT)();

const isReadOnly = contract.functions.counter.isReadOnly();

expect(isReadOnly).toBe(true);
});

test('isReadOnly returns false for a function containing write operations', async () => {
const contract = await getSetupContract(FuelGaugeProjectsEnum.STORAGE_TEST_CONTRACT)();

const isReadOnly = contract.functions.increment_counter.isReadOnly();

expect(isReadOnly).toBe(false);
});
14 changes: 12 additions & 2 deletions packages/program/src/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type { AbstractAddress, AbstractContract, BytesLike } from '@fuel-ts/inte

import { FunctionInvocationScope } from './functions/invocation-scope';
import { MultiCallInvocationScope } from './functions/multicall-scope';
import type { InvokeFunctions } from './types';
import type { InvokeFunction, InvokeFunctions } from './types';

/**
* `Contract` provides a way to interact with the contract program type.
Expand Down Expand Up @@ -89,7 +89,17 @@ export default class Contract implements AbstractContract {
* @returns A function that creates a FunctionInvocationScope.
*/
buildFunction(func: FunctionFragment) {
return (...args: Array<unknown>) => new FunctionInvocationScope(this, func, args);
return (() => {
const funcInvocationScopeCreator = (...args: Array<unknown>) =>
new FunctionInvocationScope(this, func, args);

Object.defineProperty(funcInvocationScopeCreator, 'isReadOnly', {
value: () => func.isReadOnly(),
writable: false,
});

return funcInvocationScopeCreator;
})() as InvokeFunction;
}

/**
Expand Down
10 changes: 0 additions & 10 deletions packages/program/src/functions/invocation-scope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,4 @@ export class FunctionInvocationScope<

return this;
}

/**
* Checks if the function is read-only i.e. it only reads from storage, does not write to it.
*
* @returns True if the function is read-only, false otherwise.
*/
isReadOnly(): boolean {
const storageAttribute = this.func.attributes.find((attr) => attr.name === 'storage');
return !storageAttribute?.arguments.includes('write');
}
}
7 changes: 4 additions & 3 deletions packages/program/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,10 @@ export type CallConfig<T = unknown> = {
* @template TReturn - Type of the function's return value.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type InvokeFunction<TArgs extends Array<any> = Array<any>, TReturn = any> = (
...args: TArgs
) => FunctionInvocationScope<TArgs, TReturn>;
export interface InvokeFunction<TArgs extends Array<any> = Array<any>, TReturn = any> {
(...args: TArgs): FunctionInvocationScope<TArgs, TReturn>;
isReadOnly: () => boolean;
}

/**
* Represents a collection of functions that can be invoked.
Expand Down

0 comments on commit 36a88ab

Please sign in to comment.