Repository: 0xs34n/starknet.js
Pull request #598 (2023-04-25 17:26:02)

Fix/0.11.0/improvements
## Motivation and Resolution
[extend test for contract populate](https://github.com/0xs34n/starknet.js/pull/598/commits/0b20581a1ad5e391d5704fd0cdc10abe21fde166)
[boolean to felt - cairo 1, compile()](https://github.com/0xs34n/starknet.js/pull/598/commits/ef34e0a25a52be7a6ac76714bda43233a2f1a6f1)
[prevent missusage of cairoVersion on deploy](https://github.com/0xs34n/starknet.js/pull/598/commits/d920dbe6144006438c917727b153a043fec2531b)
[remove unused cairoVersion from Contract](https://github.com/0xs34n/starknet.js/pull/598/commits/e4fcf244fa1dfd01301addfa7492bf90dac5a854)
[remove deprecated compileCalldata](https://github.com/0xs34n/starknet.js/pull/598/commits/e5adca449a9d1142339d5e63adb857698c5913d6)
[fix: contract types, interface, cleanup, extend tests](https://github.com/0xs34n/starknet.js/pull/598/commits/02c6b72ec41016fdd75537044889e7cffd624b27)
[fix: contractfactory, contract, interface cleanup cleanup & ts](https://github.com/0xs34n/starknet.js/pull/598/commits/b25047ece2eed313eaa776b2a132b9a04c3fbc2f)

## Development related changes
removed deprecated compileCalldata()

## Checklist:

- [x] Performed a self-review of the code
- [x] Rebased to the last commit of the target branch (or merged it into my branch)
- [ ] Linked the issues which this PR resolves
- [x] Documented the changes
- [x] Updated the docs (www)
- [x] Updated the tests
- [x] All tests are passing



Patch:
diff --git a/src/account/default.ts b/src/account/default.ts
index b46723e5..ed99bb4a 100644
--- a/src/account/default.ts
+++ b/src/account/default.ts
@@ -33,6 +33,7 @@ import {
   UniversalDeployerContractPayload,
 } from '../types';
 import { EstimateFeeBulk, TransactionSimulation } from '../types/account';
+import { CallData } from '../utils/calldata';
 import { extractContractHashes, isSierra } from '../utils/contract';
 import { starkCurve } from '../utils/ec';
 import { parseUDCEvent } from '../utils/events';
@@ -44,12 +45,7 @@ import {
 } from '../utils/hash';
 import { BigNumberish, toBigInt, toCairoBool } from '../utils/num';
 import { parseContract } from '../utils/provider';
-import {
-  compileCalldata,
-  estimatedFeeToMaxFee,
-  formatSignature,
-  randomAddress,
-} from '../utils/stark';
+import { estimatedFeeToMaxFee, formatSignature, randomAddress } from '../utils/stark';
 import { getExecuteCalldata } from '../utils/transaction';
 import { TypedData, getMessageHash } from '../utils/typedData';
 import { AccountInterface } from './interface';
@@ -372,7 +368,7 @@ export class Account extends Provider implements AccountInterface {
         constructorCalldata = [],
       } = it as UniversalDeployerContractPayload;
 
-      const compiledConstructorCallData = compileCalldata(constructorCalldata);
+      const compiledConstructorCallData = CallData.compile(constructorCalldata);
       const deploySalt = salt ?? randomAddress();
 
       return {
@@ -398,7 +394,10 @@ export class Account extends Provider implements AccountInterface {
 
     const calls = params.map((it) => it.call);
     const addresses = params.map((it) => it.address);
-    const invokeResponse = await this.execute(calls, undefined, details);
+    const invokeResponse = await this.execute(calls, undefined, {
+      ...details,
+      cairoVersion: '0', // UDC is Cairo0 Contract
+    });
 
     return {
       ...invokeResponse,
@@ -494,7 +493,7 @@ export class Account extends Provider implements AccountInterface {
       await this.callContract({
         contractAddress: this.address,
         entrypoint: 'isValidSignature',
-        calldata: compileCalldata({
+        calldata: CallData.compile({
           hash: toBigInt(hash).toString(),
           signature: formatSignature(signature),
         }),
@@ -610,7 +609,7 @@ export class Account extends Provider implements AccountInterface {
         unique = true,
         constructorCalldata = [],
       } = it as UniversalDeployerContractPayload;
-      const compiledConstructorCallData = compileCalldata(constructorCalldata);
+      const compiledConstructorCallData = CallData.compile(constructorCalldata);
 
       return {
         contractAddress: UDC.ADDRESS,
diff --git a/src/contract/contractFactory.ts b/src/contract/contractFactory.ts
index c93af0e2..1ef8cb51 100644
--- a/src/contract/contractFactory.ts
+++ b/src/contract/contractFactory.ts
@@ -1,8 +1,8 @@
 import { AccountInterface } from '../account';
-import { Abi, CompiledContract, FunctionAbi } from '../types';
+import { Abi, ArgsOrCalldataWithOptions, CompiledContract } from '../types';
 import assert from '../utils/assert';
 import { CallData } from '../utils/calldata';
-import { Contract } from './default';
+import { Contract, getCalldata, splitArgsAndOptions } from './default';
 
 export class ContractFactory {
   abi: Abi;
@@ -13,7 +13,7 @@ export class ContractFactory {
 
   account: AccountInterface;
 
-  private callData: CallData;
+  private CallData: CallData;
 
   constructor(
     compiledContract: CompiledContract,
@@ -25,7 +25,7 @@ export class ContractFactory {
     this.compiledContract = compiledContract;
     this.account = account;
     this.classHash = classHash;
-    this.callData = new CallData(abi);
+    this.CallData = new CallData(abi);
   }
 
   /**
@@ -35,37 +35,25 @@ export class ContractFactory {
    * @param options (optional) Object - parseRequest, parseResponse, addressSalt
    * @returns deployed Contract
    */
-  public async deploy(...args: Array<any>): Promise<Contract> {
-    let constructorCalldata;
-    let parseRequest: Boolean = true;
-    let addressSalt: string | undefined;
+  public async deploy(...args: ArgsOrCalldataWithOptions): Promise<Contract> {
+    const { args: param, options = { parseRequest: true } } = splitArgsAndOptions(args);
 
-    // extract options
-    args.forEach((arg) => {
-      if (typeof arg !== 'object') return;
-      if ('addressSalt' in arg) {
-        addressSalt = arg.addressSalt;
-      }
-      if ('parseRequest' in arg) {
-        parseRequest = arg.parseRequest;
+    const constructorCalldata = getCalldata(param, () => {
+      if (options.parseRequest) {
+        this.CallData.validate('DEPLOY', 'constructor', param);
+        return this.CallData.compile('constructor', param);
       }
+      // eslint-disable-next-line no-console
+      console.warn('Call skipped parsing but provided rawArgs, possible malfunction request');
+      return param;
     });
 
-    if (!parseRequest || args[0]?.compiled) {
-      // eslint-disable-next-line prefer-destructuring
-      constructorCalldata = args[0];
-    } else {
-      this.callData.validate('DEPLOY', 'constructor', args);
-      const { inputs } = this.abi.find((abi) => abi.type === 'constructor') as FunctionAbi;
-      constructorCalldata = this.callData.compile(args, inputs);
-    }
-
     const {
       deploy: { contract_address, transaction_hash },
     } = await this.account.declareAndDeploy({
       contract: this.compiledContract,
       constructorCalldata,
-      salt: addressSalt,
+      salt: options.addressSalt,
     });
     assert(Boolean(contract_address), 'Deployment of the contract failed');
 
@@ -80,7 +68,7 @@ export class ContractFactory {
   }
 
   /**
-   * Attaches to new Provider or Account
+   * Attaches to new Account
    *
    * @param account - new Provider or Account to attach to
    * @returns ContractFactory
@@ -91,7 +79,7 @@ export class ContractFactory {
   }
 
   /**
-   * Attaches current abi and provider or account to the new address
+   * Attaches current abi and account to the new address
    *
    * @param address - Contract address
    * @returns Contract
diff --git a/src/contract/default.ts b/src/contract/default.ts
index f3f44eb1..ff0d06c4 100644
--- a/src/contract/default.ts
+++ b/src/contract/default.ts
@@ -2,20 +2,26 @@ import { AccountInterface } from '../account';
 import { ProviderInterface, defaultProvider } from '../provider';
 import {
   Abi,
+  ArgsOrCalldata,
+  ArgsOrCalldataWithOptions,
   AsyncContractFunction,
   Call,
+  CallOptions,
+  Calldata,
   ContractFunction,
+  ContractOptions,
+  EstimateFeeResponse,
   FunctionAbi,
   InvokeFunctionResponse,
-  Overrides,
+  InvokeOptions,
   Result,
   StructAbi,
 } from '../types';
 import assert from '../utils/assert';
 import { CallData } from '../utils/calldata';
-import { CallOptions, ContractInterface } from './interface';
+import { ContractInterface } from './interface';
 
-const splitArgsAndOptions = (args: any) => {
+export const splitArgsAndOptions = (args: ArgsOrCalldataWithOptions) => {
   const options = [
     'blockIdentifier',
     'parseRequest',
@@ -24,19 +30,20 @@ const splitArgsAndOptions = (args: any) => {
     'maxFee',
     'nonce',
     'signature',
+    'addressSalt',
   ];
   const lastArg = args[args.length - 1];
   if (typeof lastArg === 'object' && options.some((x) => x in lastArg)) {
-    return { args, options: args.pop() };
+    return { args: args as ArgsOrCalldata, options: args.pop() as ContractOptions };
   }
-  return { args, options: {} };
+  return { args: args as ArgsOrCalldata };
 };
 
 /**
  * Adds call methods to the contract
  */
 function buildCall(contract: Contract, functionAbi: FunctionAbi): AsyncContractFunction {
-  return async function (...args: Array<any>): Promise<any> {
+  return async function (...args: ArgsOrCalldataWithOptions): Promise<any> {
     const params = splitArgsAndOptions(args);
     return contract.call(functionAbi.name, params.args, {
       parseRequest: true,
@@ -87,10 +94,20 @@ function buildEstimate(contract: Contract, functionAbi: FunctionAbi): ContractFu
   };
 }
 
-const detectCairoVersion = (abi: Abi) => {
+export function getCalldata(args: ArgsOrCalldata, callback: Function): Calldata {
+  // Check if Calldata in args or args[0] else compile
+  if ('__compiled__' in args) return args as Calldata;
+  if (Array.isArray(args[0]) && '__compiled__' in args[0]) return args[0] as Calldata;
+  return callback();
+}
+
+/**
+ * Not used at the moment
+ */
+/* const detectCairoVersion = (abi: Abi) => {
   if (!abi) return '0';
   return abi.find((it) => 'state_mutability' in it) ? '1' : '0';
-};
+}; */
 
 export class Contract implements ContractInterface {
   abi: Abi;
@@ -115,28 +132,23 @@ export class Contract implements ContractInterface {
 
   private callData: CallData;
 
-  private version: string = '0';
-
   /**
    * Contract class to handle contract methods
    *
    * @param abi - Abi of the contract object
    * @param address (optional) - address to connect to
    * @param providerOrAccount (optional) - Provider or Account to attach to
-   * @param cairoVersion (optional) - default '0', for Cairo 1 set '1'
    */
   constructor(
     abi: Abi,
     address: string,
-    providerOrAccount: ProviderInterface | AccountInterface = defaultProvider,
-    cairoVersion: string = detectCairoVersion(abi)
+    providerOrAccount: ProviderInterface | AccountInterface = defaultProvider
   ) {
     this.address = address && address.toLowerCase();
     this.providerOrAccount = providerOrAccount;
     this.callData = new CallData(abi);
     this.structs = CallData.getAbiStruct(abi);
     this.abi = abi;
-    this.version = cairoVersion;
 
     const options = { enumerable: true, value: {}, writable: false };
     Object.defineProperties(this, {
@@ -199,19 +211,25 @@ export class Contract implements ContractInterface {
 
   public async call(
     method: string,
-    args: Array<any> = [],
-    options: CallOptions = { parseRequest: true, parseResponse: true, formatResponse: undefined }
+    args: ArgsOrCalldata = [],
+    {
+      parseRequest = true,
+      parseResponse = true,
+      formatResponse = undefined,
+      blockIdentifier = undefined,
+    }: CallOptions = {}
   ): Promise<Result> {
     assert(this.address !== null, 'contract is not connected to an address');
-    const blockIdentifier = options?.blockIdentifier || undefined;
-    let calldata = 'compiled' in args ? args : args[0];
-
-    if (options.parseRequest && !calldata?.compiled) {
-      const { inputs } = this.abi.find((abi) => abi.name === method) as FunctionAbi;
 
-      this.callData.validate('CALL', method, args);
-      calldata = this.callData.compile(args, inputs);
-    }
+    const calldata = getCalldata(args, () => {
+      if (parseRequest) {
+        this.callData.validate('CALL', method, args);
+        return this.callData.compile(method, args);
+      }
+      // eslint-disable-next-line no-console
+      console.warn('Call skipped parsing but provided rawArgs, possible malfunction request');
+      return args;
+    });
 
     return this.providerOrAccount
       .callContract(
@@ -223,11 +241,11 @@ export class Contract implements ContractInterface {
         blockIdentifier
       )
       .then((x) => {
-        if (!options.parseResponse) {
+        if (!parseResponse) {
           return x.result;
         }
-        if (options.formatResponse) {
-          return this.callData.format(method, x.result, options.formatResponse);
+        if (formatResponse) {
+          return this.callData.format(method, x.result, formatResponse);
         }
         return this.callData.parse(method, x.result);
       });
@@ -235,20 +253,20 @@ export class Contract implements ContractInterface {
 
   public invoke(
     method: string,
-    args: Array<any> = [],
-    options: Overrides = {
-      parseRequest: true,
-    }
+    args: ArgsOrCalldata = [],
+    { parseRequest = true, maxFee, nonce, signature }: InvokeOptions = {}
   ): Promise<InvokeFunctionResponse> {
     assert(this.address !== null, 'contract is not connected to an address');
-    let calldata = 'compiled' in args ? args : args[0];
 
-    if (options.parseRequest && !calldata?.compiled) {
-      const { inputs } = this.abi.find((abi) => abi.name === method) as FunctionAbi;
-
-      this.callData.validate('INVOKE', method, args);
-      calldata = this.callData.compile(args, inputs);
-    }
+    const calldata = getCalldata(args, () => {
+      if (parseRequest) {
+        this.callData.validate('INVOKE', method, args);
+        return this.callData.compile(method, args);
+      }
+      // eslint-disable-next-line no-console
+      console.warn('Invoke skipped parsing but provided rawArgs, possible malfunction request');
+      return args;
+    });
 
     const invocation = {
       contractAddress: this.address,
@@ -257,46 +275,42 @@ export class Contract implements ContractInterface {
     };
     if ('execute' in this.providerOrAccount) {
       return this.providerOrAccount.execute(invocation, undefined, {
-        maxFee: options.maxFee,
-        nonce: options.nonce,
+        maxFee,
+        nonce,
       });
     }
 
-    if (!options.nonce) {
-      throw new Error(`Nonce is required when invoking a function without an account`);
-    }
-
+    if (!nonce) throw new Error(`Nonce is required when invoking a function without an account`);
     // eslint-disable-next-line no-console
     console.warn(`Invoking ${method} without an account. This will not work on a public node.`);
 
     return this.providerOrAccount.invokeFunction(
       {
         ...invocation,
-        signature: options.signature,
+        signature,
       },
       {
-        nonce: options.nonce,
+        nonce,
       }
     );
   }
 
-  public async estimate(method: string, args: Array<any> = []) {
+  public async estimate(method: string, args: ArgsOrCalldata = []): Promise<EstimateFeeResponse> {
     assert(this.address !== null, 'contract is not connected to an address');
 
-    if (!args[0]?.compiled) {
+    if (!getCalldata(args, () => false)) {
       this.callData.validate('INVOKE', method, args);
     }
 
-    const invocation = this.populateTransaction[method](...args);
+    const invocation = this.populate(method, args);
     if ('estimateInvokeFee' in this.providerOrAccount) {
       return this.providerOrAccount.estimateInvokeFee(invocation);
     }
     throw Error('Contract must be connected to the account contract to estimate');
   }
 
-  public populate(method: string, args: Array<any> = []): Call {
-    const { inputs } = this.abi.find((abi) => abi.name === method) as FunctionAbi;
-    const calldata = args?.[0]?.compiled ? args?.[0] : this.callData.compile(args, inputs);
+  public populate(method: string, args: ArgsOrCalldata = []): Call {
+    const calldata = getCalldata(args, () => this.callData.compile(method, args));
 
     return {
       contractAddress: this.address,
diff --git a/src/contract/interface.ts b/src/contract/interface.ts
index abdc0e71..23550a70 100644
--- a/src/contract/interface.ts
+++ b/src/contract/interface.ts
@@ -3,20 +3,17 @@ import { ProviderInterface } from '../provider';
 import { BlockIdentifier } from '../provider/utils';
 import {
   Abi,
+  ArgsOrCalldata,
   AsyncContractFunction,
+  CallOptions,
   ContractFunction,
+  EstimateFeeResponse,
   Invocation,
   InvokeFunctionResponse,
-  Overrides,
+  InvokeOptions,
+  Result,
 } from '../types';
 
-export type CallOptions = {
-  blockIdentifier?: BlockIdentifier;
-  parseRequest: Boolean;
-  parseResponse: Boolean;
-  formatResponse?: object | null;
-};
-
 export abstract class ContractInterface {
   public abstract abi: Abi;
 
@@ -66,43 +63,47 @@ export abstract class ContractInterface {
    * @param options optional blockIdentifier
    * @returns Result of the call as an array with key value pars
    */
-  public abstract call(method: string, args?: Array<any>, options?: CallOptions): Promise<Object>;
+  public abstract call(
+    method: string,
+    args?: ArgsOrCalldata,
+    options?: CallOptions
+  ): Promise<Result>;
 
   /**
    * Invokes a method on a contract
    *
    * @param method name of the method
-   * @param args Array of the arguments for the invoke
+   * @param args Array of the arguments for the invoke or Calldata
    * @param options
    * @returns Add Transaction Response
    */
   public abstract invoke(
     method: string,
-    args?: Array<any>,
-    options?: Overrides
+    args?: ArgsOrCalldata,
+    options?: InvokeOptions
   ): Promise<InvokeFunctionResponse>;
 
   /**
    * Estimates a method on a contract
    *
    * @param method name of the method
-   * @param args Array of the arguments for the call
+   * @param args Array of the arguments for the call or Calldata
    * @param options optional blockIdentifier
    */
   public abstract estimate(
     method: string,
-    args?: Array<any>,
+    args?: ArgsOrCalldata,
     options?: {
       blockIdentifier?: BlockIdentifier;
     }
-  ): Promise<any>;
+  ): Promise<EstimateFeeResponse>;
 
   /**
    * Calls a method on a contract
    *
    * @param method name of the method
-   * @param args Array of the arguments for the call
+   * @param args Array of the arguments for the call or Calldata
    * @returns Invocation object
    */
-  public abstract populate(method: string, args?: Array<any>): Invocation;
+  public abstract populate(method: string, args?: ArgsOrCalldata): Invocation;
 }
diff --git a/src/provider/starknetId.ts b/src/provider/starknetId.ts
index e78be607..701d8e1a 100644
--- a/src/provider/starknetId.ts
+++ b/src/provider/starknetId.ts
@@ -1,5 +1,5 @@
+import { CallData } from '../utils/calldata';
 import { BigNumberish } from '../utils/num';
-import { compileCalldata } from '../utils/stark';
 import { getStarknetIdContract, useDecoded, useEncoded } from '../utils/starknetId';
 import { ProviderInterface } from './interface';
 
@@ -15,7 +15,7 @@ export async function getStarkName(
     const hexDomain = await provider.callContract({
       contractAddress: contract,
       entrypoint: 'address_to_domain',
-      calldata: compileCalldata({
+      calldata: CallData.compile({
         address,
       }),
     });
@@ -48,7 +48,7 @@ export async function getAddressFromStarkName(
     const addressData = await provider.callContract({
       contractAddress: contract,
       entrypoint: 'domain_to_address',
-      calldata: compileCalldata({
+      calldata: CallData.compile({
         domain: [useEncoded(name.replace('.stark', '')).toString(10)],
       }),
     });
diff --git a/src/types/api/index.ts b/src/types/api/index.ts
deleted file mode 100644
index 72e436c3..00000000
--- a/src/types/api/index.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { BigNumberish } from '../../utils/num';
-import { Signature } from '../lib';
-
-export type Calldata = string[];
-
-export type Overrides = {
-  maxFee?: BigNumberish;
-  nonce?: BigNumberish;
-  signature?: Signature;
-  parseRequest?: Boolean;
-};
diff --git a/src/types/contract.ts b/src/types/contract.ts
index bcba6b2a..1c8143e3 100644
--- a/src/types/contract.ts
+++ b/src/types/contract.ts
@@ -1,5 +1,9 @@
-export type AsyncContractFunction<T = any> = (...args: Array<any>) => Promise<T>;
-export type ContractFunction = (...args: Array<any>) => any;
+import { BlockIdentifier } from '../provider/utils';
+import { BigNumberish } from '../utils/num';
+import { RawArgsArray, Signature } from './lib';
+
+export type AsyncContractFunction<T = any> = (...args: ArgsOrCalldataWithOptions) => Promise<T>;
+export type ContractFunction = (...args: ArgsOrCalldataWithOptions) => any;
 export type Result =
   | {
       [key: string]: any;
@@ -8,3 +12,26 @@ export type Result =
   | bigint
   | string
   | boolean;
+export type Calldata = string[] & { readonly __compiled__?: boolean };
+export type ArgsOrCalldata = RawArgsArray | [Calldata] | Calldata;
+export type ArgsOrCalldataWithOptions = ArgsOrCalldata & ContractOptions;
+export type ContractOptions = {
+  blockIdentifier?: BlockIdentifier;
+  parseRequest?: boolean;
+  parseResponse?: boolean;
+  formatResponse?: { [key: string]: any };
+  maxFee?: BigNumberish;
+  nonce?: BigNumberish;
+  signature?: Signature;
+  addressSalt?: string;
+};
+
+export type CallOptions = Pick<
+  ContractOptions,
+  'blockIdentifier' | 'parseRequest' | 'parseResponse' | 'formatResponse'
+>;
+
+export type InvokeOptions = Pick<
+  ContractOptions,
+  'maxFee' | 'nonce' | 'signature' | 'parseRequest'
+>;
diff --git a/src/types/index.ts b/src/types/index.ts
index 37482cd7..74ae6554 100644
--- a/src/types/index.ts
+++ b/src/types/index.ts
@@ -1,5 +1,4 @@
 export * from './lib';
-export { Calldata, Overrides } from './api';
 export * from './signer';
 export * from './contract';
 export * from './account';
diff --git a/src/types/lib/index.ts b/src/types/lib/index.ts
index 685ccddb..ff9e9903 100644
--- a/src/types/lib/index.ts
+++ b/src/types/lib/index.ts
@@ -1,6 +1,7 @@
 import { StarknetChainId } from '../../constants';
 import { weierstrass } from '../../utils/ec';
 import type { BigNumberish } from '../../utils/num';
+import { Uint256 } from '../../utils/uint256';
 import { CompiledContract, CompiledSierraCasm, ContractClass } from './contract';
 
 export type WeierstrassSignatureType = weierstrass.SignatureType;
@@ -9,14 +10,16 @@ export type Signature = ArraySignatureType | WeierstrassSignatureType;
 
 export type RawCalldata = BigNumberish[];
 export type AllowArray<T> = T | T[];
-export type RawArgs =
-  | {
-      [inputName: string]:
-        | BigNumberish
-        | BigNumberish[]
-        | { type: 'struct'; [k: string]: BigNumberish };
-    }
-  | BigNumberish[];
+
+export type RawArgs = RawArgsObject | RawArgsArray;
+
+export type RawArgsObject = {
+  [inputName: string]: MultiType | MultiType[] | RawArgs;
+};
+
+export type RawArgsArray = Array<MultiType | MultiType[] | RawArgs>;
+
+export type MultiType = BigNumberish | Uint256 | object | boolean;
 
 export type UniversalDeployerContractPayload = {
   classHash: BigNumberish;
diff --git a/src/types/provider.ts b/src/types/provider.ts
index 1b083994..39935561 100644
--- a/src/types/provider.ts
+++ b/src/types/provider.ts
@@ -104,6 +104,7 @@ export interface EstimateFeeResponse {
   overall_fee: bigint;
   gas_consumed?: bigint;
   gas_price?: bigint;
+  suggestedMaxFee?: bigint;
 }
 
 export interface InvokeFunctionResponse {
diff --git a/src/utils/calldata/cairo.ts b/src/utils/calldata/cairo.ts
index 0f16a0ba..d7fc3449 100644
--- a/src/utils/calldata/cairo.ts
+++ b/src/utils/calldata/cairo.ts
@@ -84,6 +84,10 @@ export function felt(it: BigNumberish): string {
   if (typeof it === 'string' && isStringWholeNumber(it)) {
     return it;
   }
+  // bool to felt
+  if (typeof it === 'boolean') {
+    return `${+it}`;
+  }
 
   throw new Error(`${it} can't be computed by felt()`);
 }
diff --git a/src/utils/calldata/index.ts b/src/utils/calldata/index.ts
index e8e3f2db..cf4ad050 100644
--- a/src/utils/calldata/index.ts
+++ b/src/utils/calldata/index.ts
@@ -1,4 +1,14 @@
-import { Abi, AbiEntry, AbiStructs, Args, Calldata, FunctionAbi, Result } from '../../types';
+import {
+  Abi,
+  AbiEntry,
+  AbiStructs,
+  Args,
+  ArgsOrCalldata,
+  Calldata,
+  FunctionAbi,
+  RawArgs,
+  Result,
+} from '../../types';
 import assert from '../assert';
 import { isBigInt } from '../num';
 import { isLongText, splitLongString } from '../shortString';
@@ -21,13 +31,12 @@ export class CallData {
   }
 
   /**
-   * Validates if all arguments that are passed to the method are corresponding to the ones in the abi
-   *
-   * @param type - type of the method
-   * @param method  - name of the method
-   * @param args - arguments that are passed to the method
+   * Validate arguments passed to the method as corresponding to the ones in the abi
+   * @param type string - type of the method
+   * @param method string - name of the method
+   * @param args ArgsOrCalldata - arguments that are passed to the method
    */
-  public validate(type: 'INVOKE' | 'CALL' | 'DEPLOY', method: string, args: Array<any> = []) {
+  public validate(type: 'INVOKE' | 'CALL' | 'DEPLOY', method: string, args: ArgsOrCalldata = []) {
     // ensure provided method of type exists
     if (type !== 'DEPLOY') {
       const invocableFunctionNames = this.abi
@@ -63,14 +72,15 @@ export class CallData {
   }
 
   /**
+   * Compile contract callData with abi
    * Parse the calldata by using input fields from the abi for that method
-   *
-   * @param args - arguments passed the the method
-   * @param inputs  - list of inputs(fields) that are in the abi
-   * @return {Calldata} - parsed arguments in format that contract is expecting
+   * @param method string - method name
+   * @param args ArgsOrCalldata - arguments passed to the method
+   * @return Calldata - parsed arguments in format that contract is expecting
    */
-  public compile(args: Array<any>, inputs: AbiEntry[]): Calldata {
+  public compile(method: string, args: ArgsOrCalldata): Calldata {
     const argsIterator = args[Symbol.iterator]();
+    const { inputs } = this.abi.find((abi) => abi.name === method) as FunctionAbi;
     return inputs.reduce(
       (acc, input) =>
         isLen(input.name) ? acc : acc.concat(parseCalldataField(argsIterator, input, this.structs)),
@@ -80,10 +90,10 @@ export class CallData {
 
   /**
    * Compile contract callData without abi
-   * @param data Object representing cairo method arguments or string array of compiled data
-   * @returns string[]
+   * @param rawArgs RawArgs representing cairo method arguments or string array of compiled data
+   * @returns Calldata
    */
-  static compile(data: object | string[]): Calldata {
+  static compile(rawArgs: RawArgs): Calldata {
     const createTree = (obj: object) => {
       const getEntries = (o: object, prefix = ''): any => {
         const oe = Array.isArray(o) ? [o.length.toString(), ...o] : o;
@@ -101,18 +111,21 @@ export class CallData {
     };
 
     let callTreeArray;
-    if (!Array.isArray(data)) {
+    if (!Array.isArray(rawArgs)) {
       // flatten structs, tuples, add array length. Process leafs as Felt
-      const callTree = createTree(data);
+      const callTree = createTree(rawArgs);
       // convert to array
       callTreeArray = Object.values(callTree);
     } else {
-      // data are already compiled or some missuses
-      callTreeArray = data;
+      // already compiled data but modified or raw args provided as array, recompile it
+      // recreate tree
+      const callObj = { ...rawArgs };
+      const callTree = createTree(callObj);
+      callTreeArray = Object.values(callTree);
     }
 
     // add compiled property to array object
-    Object.defineProperty(callTreeArray, 'compiled', {
+    Object.defineProperty(callTreeArray, '__compiled__', {
       enumerable: false,
       writable: false,
       value: true,
@@ -122,9 +135,9 @@ export class CallData {
 
   /**
    * Parse elements of the response array and structuring them into response object
-   * @param method - method name
-   * @param response  - response from the method
-   * @return - parsed response corresponding to the abi
+   * @param method string - method name
+   * @param response string[] - response from the method
+   * @return Result - parsed response corresponding to the abi
    */
   public parse(method: string, response: string[]): Result {
     const { outputs } = this.abi.find((abi) => abi.name === method) as FunctionAbi;
@@ -145,23 +158,31 @@ export class CallData {
 
   /**
    * Format cairo method response data to native js values based on provided format schema
-   * @param method - cairo method name
-   * @param response - cairo method response
-   * @param format - formatter object schema
-   * @returns parsed and formatted response object
+   * @param method string - cairo method name
+   * @param response string[] - cairo method response
+   * @param format object - formatter object schema
+   * @returns Result - parsed and formatted response object
    */
-  public format(method: string, response: string[], format: object): object {
+  public format(method: string, response: string[], format: object): Result {
     const parsed = this.parse(method, response);
     return formatter(parsed, format);
   }
 
-  // Helper to calculate inputs
+  /**
+   * Helper to calculate inputs from abi
+   * @param inputs AbiEntry
+   * @returns number
+   */
   static abiInputsLength(inputs: AbiEntry[]) {
     return inputs.reduce((acc, input) => (!isLen(input.name) ? acc + 1 : acc), 0);
   }
 
-  // Helper to extract structs
-  static getAbiStruct(abi: Abi) {
+  /**
+   * Helper to extract structs from abi
+   * @param abi Abi
+   * @returns AbiStructs - structs from abi
+   */
+  static getAbiStruct(abi: Abi): AbiStructs {
     return abi
       .filter((abiEntry) => abiEntry.type === 'struct')
       .reduce(
diff --git a/src/utils/stark.ts b/src/utils/stark.ts
index 87860d84..388596f8 100644
--- a/src/utils/stark.ts
+++ b/src/utils/stark.ts
@@ -1,14 +1,7 @@
 import { getStarkKey, utils } from 'micro-starknet';
 import { gzip } from 'pako';
 
-import {
-  ArraySignatureType,
-  Calldata,
-  CompressedProgram,
-  Program,
-  RawArgs,
-  Signature,
-} from '../types';
+import { ArraySignatureType, CompressedProgram, Program, Signature } from '../types';
 import { addHexPrefix, btoaUniversal } from './encode';
 import { stringify } from './json';
 import {
@@ -62,27 +55,6 @@ export function signatureToHexArray(sig?: Signature): ArraySignatureType {
   return bigNumberishArrayToHexadecimalStringArray(formatSignature(sig));
 }
 
-/**
- * @deprecated this function is deprecated use callData instead from calldata.ts
- */
-export function compileCalldata(args: RawArgs): Calldata {
-  const compiledData = Object.values(args).flatMap((value) => {
-    if (Array.isArray(value))
-      return [toBigInt(value.length).toString(), ...value.map((x) => toBigInt(x).toString())];
-    if (typeof value === 'object' && 'type' in value)
-      return Object.entries<BigNumberish>(value)
-        .filter(([k]) => k !== 'type')
-        .map(([, v]) => toBigInt(v).toString());
-    return toBigInt(value).toString();
-  });
-  Object.defineProperty(compiledData, 'compiled', {
-    enumerable: false,
-    writable: false,
-    value: true,
-  });
-  return compiledData;
-}
-
 export function estimatedFeeToMaxFee(estimatedFee: BigNumberish, overhead: number = 0.5): bigint {
   // BN can only handle Integers, so we need to do all calulations with integers
   const overHeadPercent = Math.round((1 + overhead) * 100);
diff --git a/www/docs/API/account.md b/www/docs/API/account.md
index d073a1e5..548b68ff 100644
--- a/www/docs/API/account.md
+++ b/www/docs/API/account.md
@@ -178,7 +178,7 @@ const call = await account.execute(
   {
     contractAddress: '0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7',  // ETH contract address
     entrypoint: 'approve',
-    calldata: starknet.stark.compileCalldata(
+    calldata: starknet.CallData.compile(
       {
         spender: "0x15e90f807a00a01df845460324fbcd33986f2df3cc9d981e9e8b5005b7f595e",
         amount: {
@@ -201,7 +201,7 @@ const multiCall = await account.execute(
     {
       contractAddress: '0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7',  // ETH contract address
       entrypoint: 'approve',
-      calldata: starknet.stark.compileCalldata(
+      calldata: starknet.CallData.compile(
         {
           spender: "0x15e90f807a00a01df845460324fbcd33986f2df3cc9d981e9e8b5005b7f595e",
           amount: {
diff --git a/www/docs/API/utils.md b/www/docs/API/utils.md
index a8eda1f3..b448f11f 100644
--- a/www/docs/API/utils.md
+++ b/www/docs/API/utils.md
@@ -77,9 +77,9 @@ Function that formats a Signature to BigNum and then to string array.
 
 Returns a string array.
 
-### compileCalldata
+### CallData.compile
 
-`compileCalldata(args: RawArgs): Calldata`
+`CallData.compile(args: RawArgs): Calldata`
 
 Function that creates calldata that gets sent to the contract.
 
@@ -87,7 +87,7 @@ Function that creates calldata that gets sent to the contract.
 await this.callContract({
     contractAddress: this.address,
     entrypoint: 'is_valid_signature',
-    calldata: compileCalldata({
+    calldata: CallData.compile({
         hash: toBigInt(hash).toString(),
         signature: signature.map((x) => toBigInt(x).toString()),
     }),
@@ -315,12 +315,12 @@ Functions to compile and validate arguments passed in invoke, call and deploy fu
 
 ### compile
 
-`compileCalldata(args: Array<any>, inputs: AbiEntry[]): Calldata`
+`compile(args: Array<any>, inputs: AbiEntry[]): Calldata`
 
 Parse the calldata by using input fields from the abi for that method.
 
 ### validate
 
-`validateMethodAndArgs(type: 'INVOKE' | 'CALL' | 'DEPLOY', method: string, args: Array<any> = [])`
+`validate(type: 'INVOKE' | 'CALL' | 'DEPLOY', method: string, args: Array<any> = [])`
 
 Validates if all arguments that are passed to the method are corresponding to the ones in the abi.
diff --git a/www/docs/guides/create_account.md b/www/docs/guides/create_account.md
index 9c543e47..ee2dccc8 100644
--- a/www/docs/guides/create_account.md
+++ b/www/docs/guides/create_account.md
@@ -21,7 +21,7 @@ Create an account is a bit tricky ; you have several steps :
 Here, we will create a wallet with the Open Zeppelin smart contract v0.5.1. The contract class is already implemented in both Testnet 1 & 2.
 
 ```typescript
-import { Account, ec, json, stark, Provider, hash } from "starknet";
+import { Account, ec, json, stark, Provider, hash, CallData } from "starknet";
 ```
 
 ### compute address :
@@ -40,7 +40,7 @@ console.log('publicKey=', starkKeyPub);
 
 const OZaccountClassHash = "0x2794ce20e5f2ff0d40e632cb53845b9f4e526ebd8471983f7dbd355b721d5a";
 // Calculate future address of the account
-const OZaccountConstructorCallData = stark.compileCalldata({ publicKey: starkKeyPub });
+const OZaccountConstructorCallData = CallData.compile({ publicKey: starkKeyPub });
 const OZcontractAddress = hash.calculateContractAddressFromHash(
     starkKeyPub,
     OZaccountClassHash,
@@ -90,7 +90,7 @@ Here, we will create a wallet with the Argent smart contract v0.2.3. This case i
 > If necessary OZ contracts can also be created with a proxy.
 
 ```typescript
-import { Account, ec, json, stark, Provider, hash } from "starknet";
+import { Account, ec, json, stark, Provider, hash, CallData } from "starknet";
 ```
 
 ### compute address
@@ -111,10 +111,10 @@ const starkKeyPubAX = ec.getStarkKey(starkKeyPairAX);
 console.log('AX_ACCOUNT_PUBLIC_KEY=', starkKeyPubAX);
 
 // Calculate future address of the ArgentX account
-const AXproxyConstructorCallData = stark.compileCalldata({
+const AXproxyConstructorCallData = CallData.compile({
     implementation: argentXaccountClassHash,
     selector: hash.getSelectorFromName("initialize"),
-    calldata: stark.compileCalldata({ signer: starkKeyPubAX, guardian: "0" }),
+    calldata: CallData.compile({ signer: starkKeyPubAX, guardian: "0" }),
 });
 const AXcontractAddress = hash.calculateContractAddressFromHash(
     starkKeyPubAX,
@@ -177,7 +177,7 @@ Here is an example of a customized wallet, including super administrator managem
 > launch `starknet-devnet --seed 0` before using this script
 
 ```typescript
-import { Account, ec, json, stark, Provider, hash } from "starknet";
+import { Account, ec, json, stark, Provider, hash, CallData } from "starknet";
 import axios from "axios";
 ```
 
@@ -210,7 +210,7 @@ console.log('Customized account class hash =', decCH);
 await provider.waitForTransaction(declTH);
 
 // Calculate future address of the account
-const AAaccountConstructorCallData = stark.compileCalldata({
+const AAaccountConstructorCallData = CallData.compile({
     super_admin_address: account0.address,
     publicKey: AAstarkKeyPub
 });
diff --git a/www/docs/guides/define_call_message.md b/www/docs/guides/define_call_message.md
index e9f2347b..9502ce2d 100644
--- a/www/docs/guides/define_call_message.md
+++ b/www/docs/guides/define_call_message.md
@@ -93,7 +93,7 @@ const myCallData = [
 // in Typescript, this object type is : `Calldata`
 ```
 
-Or you can use the function `stark.compileCalldata()`, that converts an object type to an `array of string` type.
+Or you can use the function `CallData.compile()`, that converts an object type to an `array of string` type.
 
 For a cairo contract, with this constructor :
 
@@ -107,7 +107,7 @@ You will have to create in your code this set of data :
 
 ```typescript
 const initialTk = uint256.bnToUint256(100);
-const ERC20ConstructorCallData = stark.compileCalldata({
+const ERC20ConstructorCallData = CallData.compile({
 	name: shortString.encodeShortString('MyToken'),
 	symbol: shortString.encodeShortString('MTK'),
 	decimals: "18",
diff --git a/www/docs/guides/interact.md b/www/docs/guides/interact.md
index c74be573..adab56cc 100644
--- a/www/docs/guides/interact.md
+++ b/www/docs/guides/interact.md
@@ -149,7 +149,7 @@ const executeHash = await account.execute(
   {
     contractAddress: myContractAddress,
     entrypoint: 'transfer',
-    calldata: stark.compileCalldata({
+    calldata: CallData.compile({
       recipient: receiverAddress,
       amount: ['10']
     })
diff --git a/www/docs/guides/multiCall.md b/www/docs/guides/multiCall.md
index c0722250..d370a5b5 100644
--- a/www/docs/guides/multiCall.md
+++ b/www/docs/guides/multiCall.md
@@ -40,7 +40,7 @@ const multiCall = await account.execute(
     contractAddress: contractAddress_1,
     entrypoint: "approve",
     // approve 1 wei for bridge
-    calldata: stark.compileCalldata({
+    calldata: CallData.compile({
         spender: contractAddress_2,
         amount: {type: 'struct', low: '1', high: '0'},
       })
@@ -50,7 +50,7 @@ const multiCall = await account.execute(
       contractAddress: contractAddress_2,
       entrypoint: "transfer_ether",
       // transfer 1 wei to the contract address
-      calldata: stark.compileCalldata({
+      calldata: CallData.compile({
           amount: {type: 'struct', low: '1', high: '0'},
       })
     }
diff --git a/www/docs/guides/use_ERC20.md b/www/docs/guides/use_ERC20.md
index 0d15ce0f..dc282414 100644
--- a/www/docs/guides/use_ERC20.md
+++ b/www/docs/guides/use_ERC20.md
@@ -61,7 +61,7 @@ const compiledErc20mintable = json.parse(fs.readFileSync("compiled_contracts/ERC
 const ERC20mintableClassHash = "0x795be772eab12ee65d5f3d9e8922d509d6672039978acc98697c0a563669e8";
 const initialTk = { low: 100, high: 0 };
 
-const ERC20ConstructorCallData = stark.compileCalldata({
+const ERC20ConstructorCallData = CallData.compile({
     name: shortString.encodeShortString('MyToken'),
     symbol: shortString.encodeShortString('MTK'),
     decimals: "18",
@@ -117,7 +117,7 @@ console.log("account0 has a balance of :", uint256.uint256ToBN(balanceBeforeTran
 // Execute tx transfer of 10 tokens
 console.log(`Invoke Tx - Transfer 10 tokens back to erc20 contract...`);
 const toTransferTk: uint256.Uint256 = uint256.bnToUint256(10);
-const transferCallData = stark.compileCalldata({
+const transferCallData = CallData.compile({
 	recipient: erc20Address,
 	initial_supply: { type: 'struct', low: toTransferTk.low, high: toTransferTk.high }
 });


Test patch:
diff --git a/__tests__/cairo1.test.ts b/__tests__/cairo1.test.ts
index 03da361b..99a4f4e3 100644
--- a/__tests__/cairo1.test.ts
+++ b/__tests__/cairo1.test.ts
@@ -49,6 +49,16 @@ describeIfDevnetSequencer('Cairo 1 Devnet', () => {
       });
     });
 
+    test('deployContract Cairo 1 with false cairoVersion UDC parameter', async () => {
+      const deploy = await account.deployContract(
+        {
+          classHash,
+        },
+        { cairoVersion: '1' }
+      );
+      expect(deploy).toHaveProperty('address');
+    });
+
     test('getCompiledClassByClassHash', async () => {
       const compiledClass = await provider.getCompiledClassByClassHash(classHash);
       expect(compiledClass).toMatchSchemaRef('CompiledClass');
@@ -109,6 +119,9 @@ describeIfDevnetSequencer('Cairo 1 Devnet', () => {
     });
 
     test('Cairo 1 Contract Interaction - bool', async () => {
+      const cdata = CallData.compile({ false: false, true: true });
+      expect(cdata).toEqual(['0', '1']);
+
       let tx = await cairo1Contract.set_status(true);
       await account.waitForTransaction(tx.transaction_hash);
       let status = await cairo1Contract.get_status();
diff --git a/__tests__/contract.test.ts b/__tests__/contract.test.ts
index 8056913c..9679171b 100644
--- a/__tests__/contract.test.ts
+++ b/__tests__/contract.test.ts
@@ -1,10 +1,9 @@
-import { Contract, ContractFactory, json, stark } from '../src';
+import { Contract, ContractFactory, RawArgs, json, stark } from '../src';
 import { CallData } from '../src/utils/calldata';
 import { felt, tuple, uint256 } from '../src/utils/calldata/cairo';
 import { getSelectorFromName } from '../src/utils/hash';
 import { BigNumberish, hexToDecimalString, toBigInt } from '../src/utils/num';
 import { encodeShortString } from '../src/utils/shortString';
-import { compileCalldata } from '../src/utils/stark';
 import { uint256ToBN } from '../src/utils/uint256';
 import {
   compiledErc20,
@@ -76,12 +75,12 @@ describe('contract module', () => {
           erc20Contract.address,
           getSelectorFromName('balanceOf'),
           Object.keys(args1).length,
-          ...compileCalldata(args1),
+          ...CallData.compile(args1),
 
           erc20Contract.address,
           getSelectorFromName('decimals'),
           Object.keys(args2).length,
-          ...compileCalldata(args2),
+          ...CallData.compile(args2),
         ];
         const { block_number, result } = await multicallContract.aggregate(calls);
         expect(BigInt(block_number));
@@ -210,7 +209,7 @@ describe('contract module', () => {
     test('deployment of new contract', async () => {
       const factory = new ContractFactory(compiledErc20, classHash, account);
       const erc20 = await factory.deploy(
-        compileCalldata({
+        CallData.compile({
           name: encodeShortString('Token'),
           symbol: encodeShortString('ERC20'),
           recipient: wallet,
@@ -221,7 +220,7 @@ describe('contract module', () => {
     test('wait for deployment transaction', async () => {
       const factory = new ContractFactory(compiledErc20, classHash, account);
       const contract = await factory.deploy(
-        compileCalldata({
+        CallData.compile({
           name: encodeShortString('Token'),
           symbol: encodeShortString('ERC20'),
           recipient: wallet,
@@ -326,7 +325,7 @@ describe('Complex interaction', () => {
   });
 
   test('callData compile', async () => {
-    const newCalldata = {
+    const newCalldata: RawArgs = {
       name: 'TokenMTK',
       symbol: 'MTK',
       decimals: 18,
@@ -475,12 +474,25 @@ describe('Complex interaction', () => {
     };
 
     test('call compiled data', async () => {
-      const result = await erc20Echo20Contract.echo(CallData.compile(request), {
+      const calldata = CallData.compile(request);
+      const args = Object.values(request);
+
+      const result = await erc20Echo20Contract.echo(calldata, {
         parseRequest: true,
         parseResponse: true,
         formatResponse,
       });
 
+      const result2 = await erc20Echo20Contract.echo(...args, {
+        formatResponse,
+      });
+      const result3 = await erc20Echo20Contract.call('echo', calldata, {
+        formatResponse,
+      });
+      const result4 = await erc20Echo20Contract.call('echo', args, {
+        formatResponse,
+      });
+
       // Convert request uint256 to match response
       const compareRequest = {
         ...request,
@@ -488,6 +500,9 @@ describe('Complex interaction', () => {
         au1: request.au1.map((it) => uint256ToBN(it)),
       };
       expect(json.stringify(compareRequest)).toBe(json.stringify(result));
+      expect(json.stringify(compareRequest)).toBe(json.stringify(result2));
+      expect(json.stringify(compareRequest)).toBe(json.stringify(result3));
+      expect(json.stringify(compareRequest)).toBe(json.stringify(result4));
     });
 
     test('invoke compiled data', async () => {
@@ -497,6 +512,28 @@ describe('Complex interaction', () => {
       expect(transaction.status).toBeDefined();
     });
 
+    // skip on live for performance
+    test('invoke unit test arguments', async () => {
+      const calldata = CallData.compile(request);
+      const args = Object.values(request);
+
+      const result = await erc20Echo20Contract.iecho(calldata);
+      const transaction = await provider.waitForTransaction(result.transaction_hash);
+      expect(transaction.status).toBeDefined();
+
+      const result1 = await erc20Echo20Contract.iecho(...args);
+      const transaction1 = await provider.waitForTransaction(result1.transaction_hash);
+      expect(transaction1.status).toBeDefined();
+
+      const result2 = await erc20Echo20Contract.invoke('iecho', calldata);
+      const transaction2 = await provider.waitForTransaction(result2.transaction_hash);
+      expect(transaction2.status).toBeDefined();
+
+      const result3 = await erc20Echo20Contract.invoke('iecho', args);
+      const transaction3 = await provider.waitForTransaction(result3.transaction_hash);
+      expect(transaction3.status).toBeDefined();
+    });
+
     describe('speedup live tests', () => {
       test('call parameterized data', async () => {
         const result = await erc20Echo20Contract.echo(
@@ -552,15 +589,27 @@ describe('Complex interaction', () => {
     });
 
     test('populate transaction and call with populated data', async () => {
-      const populated = await erc20Echo20Contract.populateTransaction.echo(
-        CallData.compile(request)
-      );
-      expect(
-        '["474107654995566025798705","123","8","135049554883004558383340439742929429255072943744440858662311072577337126766","203887170123222058415354283980421533276985178030994883159827760142323294308","196343614134218459150194337625778954700414868493373034945803514629145850912","191491606203201332235940470946533476219373216944002683254566549675726417440","150983476482645969577707455338206408996455974968365254240526141964709732462","196916864427988120570407658938236398782031728400132565646592333804118761826","196909666192589839125749789377187946419246316474617716408635151520594095469","2259304674248048077001042434290734","1","1","2","3","4","5","6","1","2","3","4","5","6","7","8","9","10","11","5000","0","1","2","1","2","200","1","2","6","1","2","3","4","5","6","4","1000","0","2000","0","3000","0","4000","0","2","10","11","20","22","2","1","2","3","4","1","2","3","4","3","1","2","3","4","1","2","3","4","1","2","3","4"]'
-      ).toBe(json.stringify(populated.calldata));
+      const args = Object.values(request);
+      // populateTransaction
+      const populated1 = erc20Echo20Contract.populateTransaction.echo(...args);
+      // populate
+      const populated2 = erc20Echo20Contract.populate('echo', args);
+      // populate with apply
+      const populated3 = erc20Echo20Contract.populate.apply(erc20Echo20Contract, ['echo', args]);
+      // populateTransaction with compiledCalldata
+      const calldata = CallData.compile(request);
+      const populated4 = erc20Echo20Contract.populateTransaction.echo(calldata);
+      const populated5 = erc20Echo20Contract.populate('echo', calldata);
+      const expected =
+        '["474107654995566025798705","123","8","135049554883004558383340439742929429255072943744440858662311072577337126766","203887170123222058415354283980421533276985178030994883159827760142323294308","196343614134218459150194337625778954700414868493373034945803514629145850912","191491606203201332235940470946533476219373216944002683254566549675726417440","150983476482645969577707455338206408996455974968365254240526141964709732462","196916864427988120570407658938236398782031728400132565646592333804118761826","196909666192589839125749789377187946419246316474617716408635151520594095469","2259304674248048077001042434290734","1","1","2","3","4","5","6","1","2","3","4","5","6","7","8","9","10","11","5000","0","1","2","1","2","200","1","2","6","1","2","3","4","5","6","4","1000","0","2000","0","3000","0","4000","0","2","10","11","20","22","2","1","2","3","4","1","2","3","4","3","1","2","3","4","1","2","3","4","1","2","3","4"]';
+      expect(expected).toBe(json.stringify(populated1.calldata));
+      expect(expected).toBe(json.stringify(populated2.calldata));
+      expect(expected).toBe(json.stringify(populated3.calldata));
+      expect(expected).toBe(json.stringify(populated4.calldata));
+      expect(expected).toBe(json.stringify(populated5.calldata));
 
       // mark data as compiled (it can be also done manually check defineProperty compiled in CallData.compile)
-      const compiledCallData = CallData.compile(populated.calldata);
+      const compiledCallData = CallData.compile(populated4.calldata);
       const result = await erc20Echo20Contract.echo(compiledCallData, { formatResponse });
 
       // Convert request uint256 to match response
@@ -573,8 +622,16 @@ describe('Complex interaction', () => {
     });
 
     test('estimate fee', async () => {
-      const gas = await erc20Echo20Contract.estimateFee.iecho(CallData.compile(request));
-      expect(gas).toMatchSchemaRef('EstimateFee');
+      const args = Object.values(request);
+      const calldata = CallData.compile(request);
+      const gas1 = await erc20Echo20Contract.estimateFee.iecho(calldata);
+      const gas2 = await erc20Echo20Contract.estimateFee.iecho(...args);
+      const gas3 = await erc20Echo20Contract.estimate('iecho', calldata);
+      const gas4 = await erc20Echo20Contract.estimate('iecho', args);
+      expect(gas1).toMatchSchemaRef('EstimateFee');
+      expect(gas2).toMatchSchemaRef('EstimateFee');
+      expect(gas3).toMatchSchemaRef('EstimateFee');
+      expect(gas4).toMatchSchemaRef('EstimateFee');
     });
 
     test('estimate fee transfer', async () => {
diff --git a/__tests__/defaultProvider.test.ts b/__tests__/defaultProvider.test.ts
index a5aae32d..a83fd167 100644
--- a/__tests__/defaultProvider.test.ts
+++ b/__tests__/defaultProvider.test.ts
@@ -1,4 +1,4 @@
-import { BlockNumber, GetBlockResponse, LibraryError, Provider, stark } from '../src';
+import { BlockNumber, CallData, GetBlockResponse, LibraryError, Provider, stark } from '../src';
 import { toBigInt } from '../src/utils/num';
 import { encodeShortString } from '../src/utils/shortString';
 import {
@@ -10,8 +10,6 @@ import {
 } from './fixtures';
 import { initializeMatcher } from './schema';
 
-const { compileCalldata } = stark;
-
 const testProvider = new Provider(getTestProvider());
 
 describe('defaultProvider', () => {
@@ -133,7 +131,7 @@ describe('defaultProvider', () => {
           testProvider.callContract({
             contractAddress: erc20ContractAddress,
             entrypoint: 'balanceOf',
-            calldata: compileCalldata({
+            calldata: CallData.compile({
               user: '0x9ff64f4ab0e1fe88df4465ade98d1ea99d5732761c39279b8e1374fa943e9b',
             }),
           })
@@ -146,7 +144,7 @@ describe('defaultProvider', () => {
             .callContract({
               contractAddress: erc20ContractAddress,
               entrypoint: 'balanceOf',
-              calldata: compileCalldata({
+              calldata: CallData.compile({
                 user: wallet,
               }),
             })
@@ -161,7 +159,7 @@ describe('defaultProvider', () => {
           testProvider.callContract({
             contractAddress: erc20ContractAddress,
             entrypoint: 'non_existent_entrypoint',
-            calldata: compileCalldata({
+            calldata: CallData.compile({
               user: '0xdeadbeef',
             }),
           })
diff --git a/__tests__/utils/stark.test.ts b/__tests__/utils/stark.test.ts
index 4c6d10b0..a2990667 100644
--- a/__tests__/utils/stark.test.ts
+++ b/__tests__/utils/stark.test.ts
@@ -1,9 +1,8 @@
-import fs from 'fs';
-
-import { RawArgs, json, stark } from '../../src';
+import { CallData, RawArgs, json, stark } from '../../src';
 import { toBigInt, toHex } from '../../src/utils/num';
+import { compiledOpenZeppelinAccount } from '../fixtures';
 
-const compiledAccount = json.parse(fs.readFileSync('./__mocks__/Account.json').toString('ascii'));
+const compiledAccount = compiledOpenZeppelinAccount;
 
 describe('stark', () => {
   describe('compressProgram()', () => {
@@ -23,11 +22,11 @@ describe('stark', () => {
     });
   });
 
-  describe('compileCalldata() ', () => {
+  describe('CallData.compile() ', () => {
     test('compiles BigNumberish[] calldata', () => {
       const callData = ['0x000', 2n, 10000];
 
-      const compiled = stark.compileCalldata(callData);
+      const compiled = CallData.compile(callData);
 
       expect(compiled).toEqual(['0', '2', '10000']);
     });
@@ -40,7 +39,7 @@ describe('stark', () => {
         d: [1n, 2n, '0x3'],
       };
 
-      const compiled = stark.compileCalldata(callData);
+      const compiled = CallData.compile(callData);
 
       expect(compiled).toEqual(['0', '2', '10000', '3', '1', '2', '3']);
     });
@@ -48,7 +47,6 @@ describe('stark', () => {
     test('compiles Struct type calldata', () => {
       const calldata: RawArgs = {
         a: {
-          type: 'struct',
           x: 1n,
           y: 2n,
           z: 3n,
@@ -57,7 +55,7 @@ describe('stark', () => {
         c: ['1', '2', toBigInt(3), toHex(4)],
       };
 
-      const compiled = stark.compileCalldata(calldata);
+      const compiled = CallData.compile(calldata);
 
       expect(compiled).toEqual(['1', '2', '3', '10000000000', '4', '1', '2', '3', '4']);
     });