Skip to content

Commit

Permalink
feat: add isCairo1 utility methods
Browse files Browse the repository at this point in the history
  • Loading branch information
PhilippeR26 authored and penovicp committed Jun 21, 2023
1 parent 9efee20 commit 78e9f87
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 3 deletions.
8 changes: 8 additions & 0 deletions __tests__/cairo1.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
shortString,
stark,
} from '../src';
import { isCairo1Abi } from '../src/utils/calldata/cairo';
import { starknetKeccak } from '../src/utils/selector';
import {
compiledC1Account,
Expand Down Expand Up @@ -71,6 +72,13 @@ describeIfDevnet('Cairo 1 Devnet', () => {
expect(classResponse).toMatchSchemaRef('SierraContractClass');
});

test('isCairo1', async () => {
const isContractCairo1 = cairo1Contract.isCairo1();
expect(isContractCairo1).toBe(true);
const isAbiCairo1 = isCairo1Abi(cairo1Contract.abi);
expect(isAbiCairo1).toBe(true);
});

test('Cairo 1 Contract Interaction - skip invoke validation & call parsing', async () => {
const tx = await cairo1Contract.increase_balance(
CallData.compile({
Expand Down
9 changes: 8 additions & 1 deletion __tests__/contract.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { BigNumberish, Contract, ContractFactory, RawArgs, json, stark } from '../src';
import { CallData } from '../src/utils/calldata';
import { felt, tuple, uint256 } from '../src/utils/calldata/cairo';
import { felt, isCairo1Abi, tuple, uint256 } from '../src/utils/calldata/cairo';
import { getSelectorFromName } from '../src/utils/hash';
import { hexToDecimalString, toBigInt } from '../src/utils/num';
import { encodeShortString } from '../src/utils/shortString';
Expand Down Expand Up @@ -50,6 +50,13 @@ describe('contract module', () => {
);
});

test('isCairo1', async () => {
const isContractCairo1: boolean = erc20Contract.isCairo1();
expect(isContractCairo1).toBe(false);
const isAbiCairo1: boolean = isCairo1Abi(erc20Contract.abi);
expect(isAbiCairo1).toBe(false);
});

test('populate transaction for initial balance of that account', async () => {
const res = await erc20Contract.populateTransaction.balanceOf(wallet);
expect(res).toHaveProperty('contractAddress');
Expand Down
6 changes: 5 additions & 1 deletion src/contract/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
StructAbi,
} from '../types';
import assert from '../utils/assert';
import { CallData } from '../utils/calldata';
import { CallData, cairo } from '../utils/calldata';
import { ContractInterface } from './interface';

export const splitArgsAndOptions = (args: ArgsOrCalldataWithOptions) => {
Expand Down Expand Up @@ -320,4 +320,8 @@ export class Contract implements ContractInterface {
calldata,
};
}

public isCairo1(): boolean {
return cairo.isCairo1Abi(this.abi);
}
}
11 changes: 11 additions & 0 deletions src/contract/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,4 +106,15 @@ export abstract class ContractInterface {
* @returns Invocation object
*/
public abstract populate(method: string, args?: ArgsOrCalldata): Invocation;

/**
* tells if the contract comes from a Cairo 1 contract
*
* @returns TRUE if the contract comes from a Cairo1 contract
* @example
* ```typescript
* const isCairo1: boolean = myContract.isCairo1();
* ```
*/
public abstract isCairo1(): boolean;
}
26 changes: 25 additions & 1 deletion src/utils/calldata/cairo.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AbiStructs, BigNumberish, Uint256 } from '../../types';
import { Abi, AbiStructs, BigNumberish, Uint256 } from '../../types';
import { isBigInt, isHex, isStringWholeNumber } from '../num';
import { encodeShortString, isShortString, isText } from '../shortString';
import { UINT_128_MAX, isUint256 } from '../uint256';
Expand Down Expand Up @@ -33,6 +33,30 @@ export const getArrayType = (type: string) => {
return type.replace('*', '');
};

/**
* tells if an ABI comes from a Cairo 1 contract
*
* @param abi representing the interface of a Cairo contract
* @returns TRUE if it is an ABI from a Cairo1 contract
* @example
* ```typescript
* const isCairo1: boolean = isCairo1Abi(myAbi: Abi);
* ```
*/
export function isCairo1Abi(abi: Abi): boolean {
const firstFunction = abi.find((entry) => entry.type === 'function');
if (!firstFunction) {
throw new Error(`Error in ABI. No function in ABI.`);
}
if (firstFunction.inputs.length) {
return isCairo1Type(firstFunction.inputs[0].type);
}
if (firstFunction.outputs.length) {
return isCairo1Type(firstFunction.outputs[0].type);
}
throw new Error(`Error in ABI. No input/output in function ${firstFunction.name}`);
}

/**
* named tuple are described as js object {}
* struct types are described as js object {}
Expand Down
8 changes: 8 additions & 0 deletions www/docs/guides/define_call_message.md
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,14 @@ const amount = myContract.call(...);
| Struct | ` func get_v() -> MyStruct` | MyStruct = { account: bigint, amount: bigint} | `const res: MyStruct = myContract.call(...` |
| complex array | `func get_v() -> Array<fMyStruct>` | MyStruct[] | `const res: MyStruct[] = myContract.call(...` |

If you don't know if your Contract object is interacting with a Cairo 0 or a Cairo 1 contract, you have these methods:

```typescript
import { cairo } from "starknet";
const isCairo1: boolean = myContract.isCairo1();
const isAbiCairo1: boolean = cairo.isCairo1Abi(myAbi);
```

## Parse configuration

### parseRequest
Expand Down

0 comments on commit 78e9f87

Please sign in to comment.