Skip to content

Commit

Permalink
feat: helpers toHex, Calldata, executeCallData, compile entrypoint, t…
Browse files Browse the repository at this point in the history
…ype improvements
  • Loading branch information
tabaktoni committed Apr 27, 2023
1 parent 837de4b commit a452d64
Show file tree
Hide file tree
Showing 10 changed files with 82 additions and 67 deletions.
2 changes: 1 addition & 1 deletion __tests__/cairo1.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ describeIfDevnetSequencer('Cairo 1 Devnet', () => {
describe('Sequencer API', () => {
const provider = getTestProvider() as SequencerProvider;
const account = getTestAccount(provider);
let classHash: any; // = '0x3e2e625998f89befe4d429d5d958275f86421310bfb00440c2431140e8c90ba';
let classHash: any; //= '0x3e2e625998f89befe4d429d5d958275f86421310bfb00440c2431140e8c90ba';
let contractAddress: any;
let declareV2Tx: any;
let cairo1Contract: Contract;
Expand Down
6 changes: 4 additions & 2 deletions src/account/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -445,9 +445,10 @@ export class Account extends Provider implements AccountInterface {
const nonce = ZERO; // DEPLOY_ACCOUNT transaction will have a nonce zero as it is the first transaction in the account
const chainId = await this.getChainId();

const compiledCalldata = CallData.compile(constructorCalldata);
const contractAddress =
providedContractAddress ??
calculateContractAddressFromHash(addressSalt, classHash, constructorCalldata, 0);
calculateContractAddressFromHash(addressSalt, classHash, compiledCalldata, 0);

const maxFee =
transactionsDetail.maxFee ??
Expand Down Expand Up @@ -576,9 +577,10 @@ export class Account extends Provider implements AccountInterface {
}: DeployAccountContractPayload,
{ nonce, chainId, version, maxFee }: InvocationsSignerDetails
): Promise<DeployAccountContractTransaction> {
const compiledCalldata = CallData.compile(constructorCalldata);
const contractAddress =
providedContractAddress ??
calculateContractAddressFromHash(addressSalt, classHash, constructorCalldata, 0);
calculateContractAddressFromHash(addressSalt, classHash, compiledCalldata, 0);

const signature = await this.signer.signDeployAccountTransaction({
classHash,
Expand Down
9 changes: 5 additions & 4 deletions src/provider/rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@ import {
TransactionStatus,
waitForTransactionOptions,
} from '../types';
import { CallData } from '../utils/calldata';
import fetch from '../utils/fetchPonyfill';
import { getSelectorFromName } from '../utils/hash';
import { stringify } from '../utils/json';
import { BigNumberish, bigNumberishArrayToHexadecimalStringArray, toHex } from '../utils/num';
import { parseCalldata, wait } from '../utils/provider';
import { wait } from '../utils/provider';
import { RPCResponseParser } from '../utils/responseParser/rpc';
import { signatureToHexArray } from '../utils/stark';
import { LibraryError } from './errors';
Expand Down Expand Up @@ -252,7 +253,7 @@ export class RpcProvider implements ProviderInterface {
request: {
type: RPC.TransactionType.INVOKE,
sender_address: invocation.contractAddress,
calldata: parseCalldata(invocation.calldata),
calldata: CallData.toHex(invocation.calldata),
signature: signatureToHexArray(invocation.signature),
version: toHex(invocationDetails?.version || 0),
nonce: toHex(invocationDetails.nonce),
Expand Down Expand Up @@ -369,7 +370,7 @@ export class RpcProvider implements ProviderInterface {
return this.fetchEndpoint('starknet_addInvokeTransaction', {
invoke_transaction: {
sender_address: functionInvocation.contractAddress,
calldata: parseCalldata(functionInvocation.calldata),
calldata: CallData.toHex(functionInvocation.calldata),
type: RPC.TransactionType.INVOKE,
max_fee: toHex(details.maxFee || 0),
version: '0x1',
Expand All @@ -389,7 +390,7 @@ export class RpcProvider implements ProviderInterface {
request: {
contract_address: call.contractAddress,
entry_point_selector: getSelectorFromName(call.entrypoint),
calldata: parseCalldata(call.calldata),
calldata: CallData.toHex(call.calldata),
},
block_id,
});
Expand Down
11 changes: 5 additions & 6 deletions src/provider/sequencer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
TransactionType,
waitForTransactionOptions,
} from '../types';
import { CallData } from '../utils/calldata';
import { isSierra } from '../utils/contract';
import fetch from '../utils/fetchPonyfill';
import { feeTransactionVersion, getSelector, getSelectorFromName } from '../utils/hash';
Expand Down Expand Up @@ -371,7 +372,7 @@ export class SequencerProvider implements ProviderInterface {
return this.fetchEndpoint('add_transaction', undefined, {
type: TransactionType.INVOKE,
sender_address: functionInvocation.contractAddress,
calldata: bigNumberishArrayToDecimalStringArray(functionInvocation.calldata ?? []),
calldata: CallData.compile(functionInvocation.calldata ?? []),
signature: signatureToDecimalArray(functionInvocation.signature),
nonce: toHex(details.nonce),
max_fee: toHex(details.maxFee || 0),
Expand All @@ -386,7 +387,7 @@ export class SequencerProvider implements ProviderInterface {
return this.fetchEndpoint('add_transaction', undefined, {
type: TransactionType.DEPLOY_ACCOUNT,
contract_address_salt: addressSalt ?? randomAddress(),
constructor_calldata: bigNumberishArrayToDecimalStringArray(constructorCalldata ?? []),
constructor_calldata: CallData.compile(constructorCalldata ?? []),
class_hash: toHex(classHash),
max_fee: toHex(details.maxFee || 0),
version: toHex(details.version || 0),
Expand Down Expand Up @@ -500,7 +501,7 @@ export class SequencerProvider implements ProviderInterface {
{
type: TransactionType.DEPLOY_ACCOUNT,
class_hash: toHex(classHash),
constructor_calldata: bigNumberishArrayToDecimalStringArray(constructorCalldata || []),
constructor_calldata: CallData.compile(constructorCalldata || []),
contract_address_salt: toHex(addressSalt || 0),
signature: signatureToDecimalArray(signature),
version: toHex(details?.version || 0),
Expand Down Expand Up @@ -531,9 +532,7 @@ export class SequencerProvider implements ProviderInterface {
res = {
type: invocation.type,
class_hash: toHex(toBigInt(invocation.classHash)),
constructor_calldata: bigNumberishArrayToDecimalStringArray(
invocation.constructorCalldata || []
),
constructor_calldata: CallData.compile(invocation.constructorCalldata || []),
contract_address_salt: toHex(toBigInt(invocation.addressSalt || 0)),
};
}
Expand Down
6 changes: 6 additions & 0 deletions src/types/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,13 @@ export type Result =
| bigint
| string
| boolean;

/**
* Compiled calldata ready to be sent
* decimal-string array
*/
export type Calldata = string[] & { readonly __compiled__?: boolean };

export type ArgsOrCalldata = RawArgsArray | [Calldata] | Calldata;
export type ArgsOrCalldataWithOptions = ArgsOrCalldata & ContractOptions;
export type ContractOptions = {
Expand Down
10 changes: 10 additions & 0 deletions src/types/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,17 @@ export type WeierstrassSignatureType = weierstrass.SignatureType;
export type ArraySignatureType = string[];
export type Signature = ArraySignatureType | WeierstrassSignatureType;

/**
* BigNumberish array
* use CallData.compile() to convert to Calldata
*/
export type RawCalldata = BigNumberish[];

/**
* Hexadecimal-string array
*/
export type HexCalldata = string[];

export type AllowArray<T> = T | T[];

export type RawArgs = RawArgsObject | RawArgsArray;
Expand Down
25 changes: 24 additions & 1 deletion src/utils/calldata/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ import {
ArgsOrCalldata,
Calldata,
FunctionAbi,
HexCalldata,
RawArgs,
RawCalldata,
Result,
} from '../../types';
import assert from '../assert';
import { isBigInt } from '../num';
import { getSelectorFromName } from '../hash';
import { isBigInt, toHex } from '../num';
import { isLongText, splitLongString } from '../shortString';
import { felt, isLen } from './cairo';
import formatter from './formatter';
Expand Down Expand Up @@ -100,6 +103,7 @@ export class CallData {
return Object.entries(oe).flatMap(([k, v]) => {
let value = v;
if (isLongText(value)) value = splitLongString(value);
if (k === 'entrypoint') value = getSelectorFromName(value);
const kk = Array.isArray(oe) && k === '0' ? '$$len' : k;
if (isBigInt(value)) return [[`${prefix}${kk}`, felt(value)]];
return Object(value) === value
Expand Down Expand Up @@ -193,4 +197,23 @@ export class CallData {
{}
);
}

/**
* Helper: Compile RawCalldata to Calldata
* @param rawCalldata
* @returns Calldata
*/
static toCalldata(rawCalldata: RawCalldata = []): Calldata {
return CallData.compile(rawCalldata);
}

/**
* Helper: Convert RawCalldata to HexCalldata
* @param rawCalldata
* @returns HexCalldata
*/
static toHex(rawCalldata: RawCalldata = []): HexCalldata {
const calldata = CallData.compile(rawCalldata);
return calldata.map((it) => toHex(it));
}
}
8 changes: 4 additions & 4 deletions src/utils/hash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ export function calculateTransactionHashCommon(
version: BigNumberish,
contractAddress: BigNumberish,
entryPointSelector: BigNumberish,
calldata: BigNumberish[],
calldata: RawCalldata,
maxFee: BigNumberish,
chainId: StarknetChainId,
additionalData: BigNumberish[] = []
Expand All @@ -119,7 +119,7 @@ export function calculateTransactionHashCommon(

export function calculateDeployTransactionHash(
contractAddress: BigNumberish,
constructorCalldata: BigNumberish[],
constructorCalldata: RawCalldata,
version: BigNumberish,
chainId: StarknetChainId
): string {
Expand Down Expand Up @@ -158,7 +158,7 @@ export function calculateDeclareTransactionHash(
export function calculateDeployAccountTransactionHash(
contractAddress: BigNumberish,
classHash: BigNumberish,
constructorCalldata: BigNumberish[],
constructorCalldata: RawCalldata,
salt: BigNumberish,
version: BigNumberish,
maxFee: BigNumberish,
Expand All @@ -182,7 +182,7 @@ export function calculateDeployAccountTransactionHash(
export function calculateTransactionHash(
contractAddress: BigNumberish,
version: BigNumberish,
calldata: BigNumberish[],
calldata: RawCalldata,
maxFee: BigNumberish,
chainId: StarknetChainId,
nonce: BigNumberish
Expand Down
16 changes: 3 additions & 13 deletions src/utils/provider.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { CompiledContract, ContractClass, RawCalldata, SierraContractClass } from '../types';
import { CompiledContract, ContractClass, SierraContractClass } from '../types';
import { isSierra } from './contract';
import { formatSpaces } from './hash';
import { parse, stringify } from './json';
import { isHex, toHex } from './num';
import { compressProgram } from './stark';

export function wait(delay: number) {
Expand All @@ -11,16 +10,7 @@ export function wait(delay: number) {
});
}

export function parseCalldata(calldata: RawCalldata = []) {
return calldata.map((data) => {
if (typeof data === 'string' && isHex(data as string)) {
return data;
}
return toHex(data);
});
}

export function createSierraContractClass(contract: SierraContractClass): any {
export function createSierraContractClass(contract: SierraContractClass): SierraContractClass {
const result = { ...contract } as any;
delete result.sierra_program_debug_info;
result.abi = formatSpaces(stringify(contract.abi));
Expand All @@ -30,7 +20,7 @@ export function createSierraContractClass(contract: SierraContractClass): any {
}

// TODO: How can we receive string here ?
export function parseContract(contract: CompiledContract | string) {
export function parseContract(contract: CompiledContract | string): ContractClass {
const parsedContract =
typeof contract === 'string' ? (parse(contract) as CompiledContract) : contract;

Expand Down
56 changes: 20 additions & 36 deletions src/utils/transaction.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { CairoVersion, Call, CallStruct, ParsedStruct } from '../types';
import { CairoVersion, Call, CallStruct, Calldata, ParsedStruct } from '../types';
import { CallData } from './calldata';
import { getSelectorFromName } from './hash';
import { BigNumberish, bigNumberishArrayToDecimalStringArray, toBigInt } from './num';
import { BigNumberish, toBigInt } from './num';

/**
* Transforms a list of Calls, each with their own calldata, into
Expand All @@ -23,7 +24,7 @@ export const transformCallsToMulticallArrays = (calls: Call[]) => {
});
return {
callArray,
calldata: bigNumberishArrayToDecimalStringArray(calldata),
calldata: CallData.compile({ calldata }),
};
};

Expand All @@ -33,57 +34,40 @@ export const transformCallsToMulticallArrays = (calls: Call[]) => {
* @param calls
* @returns
*/
export const fromCallsToExecuteCalldata = (calls: Call[]): string[] => {
export const fromCallsToExecuteCalldata = (calls: Call[]) => {
const { callArray, calldata } = transformCallsToMulticallArrays(calls);
return [
callArray.length.toString(),
...callArray
.map(
({ to, selector, data_offset, data_len }) =>
[to, selector, data_offset, data_len] as string[]
)
.flat(),
calldata.length.toString(),
...calldata,
];
const compiledCalls = CallData.compile({ callArray });
return [...compiledCalls, ...calldata] as Calldata;
};

export const fromCallsToExecuteCalldataWithNonce = (
calls: Call[],
nonce: BigNumberish
): string[] => {
return [...fromCallsToExecuteCalldata(calls), toBigInt(nonce).toString()];
export const fromCallsToExecuteCalldataWithNonce = (calls: Call[], nonce: BigNumberish) => {
return [...fromCallsToExecuteCalldata(calls), toBigInt(nonce).toString()] as Calldata;
};

// TT: Can be removed ?
/**
* Transforms a list of Calls, each with their own calldata, into
* two arrays: one with the entrypoints, and one with the concatenated calldata.
* @param calls
* @returns
* Format Data inside Calls
* @param calls Call[]
* @returns CallStruct
*/
export const transformCallsToMulticallArrays_cairo1 = (calls: Call[]) => {
const callArray = calls.map<CallStruct>((call) => ({
to: toBigInt(call.contractAddress).toString(10),
selector: toBigInt(getSelectorFromName(call.entrypoint)).toString(10),
calldata: bigNumberishArrayToDecimalStringArray(call.calldata || []),
calldata: CallData.compile(call.calldata || []),
}));
return callArray;
};

// TT: Can be removed ?
/**
* Transforms a list of calls in the full flattened calldata expected
* by the __execute__ protocol.
* @param calls
* @returns
* @returns Calldata
*/
export const fromCallsToExecuteCalldata_cairo1 = (calls: Call[]): string[] => {
const callArray = transformCallsToMulticallArrays_cairo1(calls);
return [
callArray.length.toString(), // Call size
...callArray
.map(({ to, selector, calldata }) => [to, selector, calldata.length.toString(), ...calldata])
.flat(),
];
export const fromCallsToExecuteCalldata_cairo1 = (calls: Call[]) => {
return CallData.compile({ calls });
};

/**
Expand All @@ -92,9 +76,9 @@ export const fromCallsToExecuteCalldata_cairo1 = (calls: Call[]): string[] => {
* @param cairoVersion Defaults to 0
* @returns string[] of calldata
*/
export const getExecuteCalldata = (calls: Call[], cairoVersion: CairoVersion = '0'): string[] => {
export const getExecuteCalldata = (calls: Call[], cairoVersion: CairoVersion = '0') => {
if (cairoVersion === '1') {
return fromCallsToExecuteCalldata_cairo1(calls);
return CallData.compile({ calls });
}
return fromCallsToExecuteCalldata(calls);
};

0 comments on commit a452d64

Please sign in to comment.