Skip to content

Commit

Permalink
feat: resource bounds and new hashing, tiping system improvement
Browse files Browse the repository at this point in the history
  • Loading branch information
tabaktoni committed Feb 23, 2025
1 parent cb93613 commit c602d1c
Show file tree
Hide file tree
Showing 12 changed files with 177 additions and 473 deletions.
3 changes: 2 additions & 1 deletion src/account/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ import {
UniversalDeployerContractPayload,
UniversalDetails,
} from '../types';
import { ETransactionVersion, ETransactionVersion3, type ResourceBounds } from '../types/api';
import { ETransactionVersion, ETransactionVersion3 } from '../types/api';
import {
OutsideExecutionVersion,
type OutsideExecution,
Expand Down Expand Up @@ -77,6 +77,7 @@ import { buildUDCCall, getExecuteCalldata } from '../utils/transaction';
import { getMessageHash } from '../utils/typedData';
import { AccountInterface } from './interface';
import { config } from '../global/config';
import { ResourceBounds } from '../provider/types/spec.type';

export class Account extends Provider implements AccountInterface {
public signer: SignerInterface;
Expand Down
118 changes: 63 additions & 55 deletions src/channel/rpc_0_8.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ import { Block, getDefaultNodeUrl, isV3Tx, wait } from '../utils/provider';
import { decompressProgram, signatureToHexArray } from '../utils/stark';

Check failure on line 36 in src/channel/rpc_0_8.ts

View workflow job for this annotation

GitHub Actions / Run test on rpc-devnet / Run tests

Missing file extension for "../utils/stark"
import { getVersionsByType } from '../utils/transaction';
import { logger } from '../global/logger';
import { isRPC08_ResourceBounds } from '../provider/types/spec.type';
// TODO: check if we can filet type before entering to this method, as so to specify here only RPC 0.8 types

const defaultOptions = {
headers: { 'Content-Type': 'application/json' },
Expand Down Expand Up @@ -485,23 +487,25 @@ export class RpcChannel {
public async invoke(functionInvocation: Invocation, details: InvocationsDetailsWithNonce) {
let promise;
if (isV3Tx(details)) {
// V3
promise = this.fetchEndpoint('starknet_addInvokeTransaction', {
invoke_transaction: {
type: RPC.ETransactionType.INVOKE,
sender_address: functionInvocation.contractAddress,
calldata: CallData.toHex(functionInvocation.calldata),
version: RPC.ETransactionVersion.V3,
signature: signatureToHexArray(functionInvocation.signature),
nonce: toHex(details.nonce),
resource_bounds: details.resourceBounds,
tip: toHex(details.tip),
paymaster_data: details.paymasterData.map((it) => toHex(it)),
account_deployment_data: details.accountDeploymentData.map((it) => toHex(it)),
nonce_data_availability_mode: details.nonceDataAvailabilityMode,
fee_data_availability_mode: details.feeDataAvailabilityMode,
},
});
if (isRPC08_ResourceBounds(details.resourceBounds)) {
// V3
promise = this.fetchEndpoint('starknet_addInvokeTransaction', {
invoke_transaction: {
type: RPC.ETransactionType.INVOKE,
sender_address: functionInvocation.contractAddress,
calldata: CallData.toHex(functionInvocation.calldata),
version: RPC.ETransactionVersion.V3,
signature: signatureToHexArray(functionInvocation.signature),
nonce: toHex(details.nonce),
resource_bounds: details.resourceBounds,
tip: toHex(details.tip),
paymaster_data: details.paymasterData.map((it) => toHex(it)),
account_deployment_data: details.accountDeploymentData.map((it) => toHex(it)),
nonce_data_availability_mode: details.nonceDataAvailabilityMode,
fee_data_availability_mode: details.feeDataAvailabilityMode,
},
});
} else throw Error(SYSTEM_MESSAGES.SWOldV3);
} else throw Error(SYSTEM_MESSAGES.legacyTxRPC08Message);

return this.waitMode ? this.waitForTransaction((await promise).transaction_hash) : promise;
Expand All @@ -513,29 +517,31 @@ export class RpcChannel {
) {
let promise;
if (isSierra(contract) && isV3Tx(details)) {
// V3 Cairo1
promise = this.fetchEndpoint('starknet_addDeclareTransaction', {
declare_transaction: {
type: RPC.ETransactionType.DECLARE,
sender_address: senderAddress,
compiled_class_hash: compiledClassHash || '',
version: RPC.ETransactionVersion.V3,
signature: signatureToHexArray(signature),
nonce: toHex(details.nonce),
contract_class: {
sierra_program: decompressProgram(contract.sierra_program),
contract_class_version: contract.contract_class_version,
entry_points_by_type: contract.entry_points_by_type,
abi: contract.abi,
if (isRPC08_ResourceBounds(details.resourceBounds)) {
// V3 Cairo1
promise = this.fetchEndpoint('starknet_addDeclareTransaction', {
declare_transaction: {
type: RPC.ETransactionType.DECLARE,
sender_address: senderAddress,
compiled_class_hash: compiledClassHash || '',
version: RPC.ETransactionVersion.V3,
signature: signatureToHexArray(signature),
nonce: toHex(details.nonce),
contract_class: {
sierra_program: decompressProgram(contract.sierra_program),
contract_class_version: contract.contract_class_version,
entry_points_by_type: contract.entry_points_by_type,
abi: contract.abi,
},
resource_bounds: details.resourceBounds,
tip: toHex(details.tip),
paymaster_data: details.paymasterData.map((it) => toHex(it)),
account_deployment_data: details.accountDeploymentData.map((it) => toHex(it)),
nonce_data_availability_mode: details.nonceDataAvailabilityMode,
fee_data_availability_mode: details.feeDataAvailabilityMode,
},
resource_bounds: details.resourceBounds,
tip: toHex(details.tip),
paymaster_data: details.paymasterData.map((it) => toHex(it)),
account_deployment_data: details.accountDeploymentData.map((it) => toHex(it)),
nonce_data_availability_mode: details.nonceDataAvailabilityMode,
fee_data_availability_mode: details.feeDataAvailabilityMode,
},
});
});
} else throw Error(SYSTEM_MESSAGES.SWOldV3);
} else throw Error(SYSTEM_MESSAGES.legacyTxRPC08Message);

return this.waitMode ? this.waitForTransaction((await promise).transaction_hash) : promise;
Expand All @@ -547,23 +553,25 @@ export class RpcChannel {
) {
let promise;
if (isV3Tx(details)) {
if (isRPC08_ResourceBounds(details.resourceBounds)) {
promise = this.fetchEndpoint('starknet_addDeployAccountTransaction', {
deploy_account_transaction: {
type: RPC.ETransactionType.DEPLOY_ACCOUNT,
version: RPC.ETransactionVersion.V3,
signature: signatureToHexArray(signature),
nonce: toHex(details.nonce),
contract_address_salt: toHex(addressSalt || 0),
constructor_calldata: CallData.toHex(constructorCalldata || []),
class_hash: toHex(classHash),
resource_bounds: details.resourceBounds,
tip: toHex(details.tip),
paymaster_data: details.paymasterData.map((it) => toHex(it)),
nonce_data_availability_mode: details.nonceDataAvailabilityMode,
fee_data_availability_mode: details.feeDataAvailabilityMode,
},
});
} else throw Error(SYSTEM_MESSAGES.SWOldV3);
// v3
promise = this.fetchEndpoint('starknet_addDeployAccountTransaction', {
deploy_account_transaction: {
type: RPC.ETransactionType.DEPLOY_ACCOUNT,
version: RPC.ETransactionVersion.V3,
signature: signatureToHexArray(signature),
nonce: toHex(details.nonce),
contract_address_salt: toHex(addressSalt || 0),
constructor_calldata: CallData.toHex(constructorCalldata || []),
class_hash: toHex(classHash),
resource_bounds: details.resourceBounds,
tip: toHex(details.tip),
paymaster_data: details.paymasterData.map((it) => toHex(it)),
nonce_data_availability_mode: details.nonceDataAvailabilityMode,
fee_data_availability_mode: details.feeDataAvailabilityMode,
},
});
} else throw Error(SYSTEM_MESSAGES.legacyTxRPC08Message);

return this.waitMode ? this.waitForTransaction((await promise).transaction_hash) : promise;
Expand Down
5 changes: 5 additions & 0 deletions src/global/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ export enum TransactionHashPrefix {
export const enum FeeMarginPercentage {
L1_BOUND_MAX_AMOUNT = 50,
L1_BOUND_MAX_PRICE_PER_UNIT = 50,
L1_DATA_BOUND_MAX_AMOUNT = 50,
L1_DATA_BOUND_MAX_PRICE_PER_UNIT = 50,
L2_BOUND_MAX_AMOUNT = 50,
L2_BOUND_MAX_PRICE_PER_UNIT = 50,
MAX_FEE = 50,
}

Expand Down Expand Up @@ -113,4 +117,5 @@ export const SYSTEM_MESSAGES = {
legacyTxWarningMessage:
'You are using a deprecated transaction version (V0,V1,V2)!\nUpdate to the latest V3 transactions!',
legacyTxRPC08Message: 'RPC 0.8 do not support legacy transactions',
SWOldV3: 'RPC 0.7 V3 tx (improper resource bounds) not supported in RPC 0.8',
};
4 changes: 2 additions & 2 deletions src/provider/rpc.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { SPEC } from 'starknet-types-07';

import { RPC08, RPC07, RpcChannel } from '../channel';
import { RPC08, RPC07 } from '../channel';
import {
AccountInvocations,
BigNumberish,
Expand Down Expand Up @@ -61,7 +61,7 @@ export class RpcProvider implements ProviderInterface {
? optionsOrProvider.responseParser
: new RPCResponseParser();
} else {
this.channel = new RpcChannel({ ...optionsOrProvider, waitMode: false });
this.channel = new RPC08.RpcChannel({ ...optionsOrProvider, waitMode: false });
this.responseParser = new RPCResponseParser(optionsOrProvider?.feeMarginPercentage);
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/provider/types/configuration.type.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { NetworkName, StarknetChainId } from '../../global/constants';
import { BlockIdentifier } from '../../types/lib';
import { ResourceBoundsOverhead } from './spec.type';

export interface ProviderOptions extends RpcProviderOptions {}

Expand All @@ -15,9 +16,8 @@ export type RpcProviderOptions = {
waitMode?: boolean;
baseFetch?: WindowOrWorkerGlobalScope['fetch'];
feeMarginPercentage?: {
l1BoundMaxAmount: number;
l1BoundMaxPricePerUnit: number;
maxFee: number;
bounds: ResourceBoundsOverhead; // V3 tx
maxFee: number; // V legacy tx
};
batch?: false | number;
};
71 changes: 59 additions & 12 deletions src/provider/types/spec.type.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// this file aims to unify the RPC specification types used by the common Provider class

import { IsPending, IsType, RPCSPEC07, RPCSPEC08 } from '../../types/api';
import { SimpleOneOf } from '../../types/helpers';

// TODO: Check can we remove this ?

Expand All @@ -27,13 +28,15 @@ type MergeProperties<T1 extends Record<any, any>, T2 extends Record<any, any>> =
[K in Exclude<keyof T2, keyof T1>]?: T2[K];
};

// type a = { w: bigint[]; x: bigint; y: string };
// type b = { w: number[]; x: number; z: string };
// type c = Merge<a, b>; // { w: (bigint | number)[] x: bigint | number; y?: string; z?: string; }
//
// NOTE: handling for ambiguous overlaps, such as a shared property being an array or object,
// is simplified to resolve to only one type since there shouldn't be such occurrences in the
// currently supported RPC specifications
/**
* type a = { w: bigint[]; x: bigint; y: string };
type b = { w: number[]; x: number; z: string };
type c = Merge<a, b>; // { w: (bigint | number)[] x: bigint | number; y?: string; z?: string; }
NOTE: handling for ambiguous overlaps, such as a shared property being an array or object,
is simplified to resolve to only one type since there shouldn't be such occurrences in the
currently supported RPC specifications
*/
type Merge<T1, T2> = Simplify<
T1 extends Array<any>
? T2 extends Array<any>
Expand Down Expand Up @@ -91,18 +94,62 @@ export type DeclaredTransaction = Merge<
RPCSPEC08.DeclaredTransaction,
RPCSPEC07.DeclaredTransaction
>;
export type FeeEstimate = Merge<RPCSPEC08.FEE_ESTIMATE, RPCSPEC07.SPEC.FEE_ESTIMATE>;
export type InvokedTransaction = Merge<RPCSPEC08.InvokedTransaction, RPCSPEC07.InvokedTransaction>;
export type PendingReceipt = Merge<
RPCSPEC08.TransactionReceiptPendingBlock,
RPCSPEC07.PendingReceipt
>;
export type Receipt = Merge<RPCSPEC08.TransactionReceiptProductionBlock, RPCSPEC07.Receipt>;
export type ResourceBounds = Merge<RPCSPEC08.ResourceBounds, RPCSPEC07.ResourceBounds>; // TODO: only l1_gas:val, l2_gas:0 OR l1_gas:val, l1_data_gas: val, l2_gas:val ARE VALID COMBO, waiting slack response
export type SimulateTransaction = Merge<
RPCSPEC08.SimulateTransaction,
RPCSPEC07.SimulateTransaction

// One of
export type FeeEstimate = SimpleOneOf<RPCSPEC08.FEE_ESTIMATE, RPCSPEC07.SPEC.FEE_ESTIMATE>;

export function isRPC08_FeeEstimate(entry: FeeEstimate): entry is RPCSPEC08.FEE_ESTIMATE {
return 'l1_data_gas_consumed' in entry;
}

// One of
export type ResourceBounds = Simplify<
SimpleOneOf<RPCSPEC08.ResourceBounds, RPCSPEC07.ResourceBounds>
>;

export function isRPC08_ResourceBounds(entry: ResourceBounds): entry is RPCSPEC08.ResourceBounds {
return 'l1_data_gas' in entry;
}

/**
* overhead percentage on estimate fee
*/
export type ResourceBoundsOverhead = ResourceBoundsOverheadRPC08 | ResourceBoundsOverheadRPC07;

/**
* percentage overhead on estimated fee
*/
export type ResourceBoundsOverheadRPC08 = {
l1_gas: {
max_amount: number;
max_price_per_unit: number;
};
l2_gas: {
max_amount: number;
max_price_per_unit: number;
};
l1_data_gas: {
max_amount: number;
max_price_per_unit: number;
};
};

export type ResourceBoundsOverheadRPC07 = {
l1_gas: {
max_amount: number;
max_price_per_unit: number;
};
};

// TODO: ja mislin da types-js rpc 0.7 ima krivu definiciju za transaction trace
export type SimulateTransaction = RPCSPEC08.SimulateTransaction;

export type TransactionWithHash = Merge<
RPCSPEC08.TransactionWithHash,
RPCSPEC07.TransactionWithHash
Expand Down
3 changes: 2 additions & 1 deletion src/types/account.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { EDataAvailabilityMode, ETransactionVersion, ResourceBounds } from './api';
import { EDataAvailabilityMode, ETransactionVersion } from './api';
import {
AllowArray,
BigNumberish,
Expand All @@ -14,6 +14,7 @@ import {
DeclareTransactionReceiptResponse,
EstimateFeeResponse,
} from '../provider/types/index.type';
import { ResourceBounds } from '../provider/types/spec.type';

export interface EstimateFee extends EstimateFeeResponse {}

Expand Down
3 changes: 2 additions & 1 deletion src/types/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { StarknetChainId } from '../../global/constants';
import { weierstrass } from '../../utils/ec';
import { EDataAvailabilityMode, ResourceBounds } from '../api';
import { EDataAvailabilityMode } from '../api';
import { CairoEnum } from '../cairoEnum';
import { CompiledContract, CompiledSierraCasm, ContractClass } from './contract';
import { ValuesType } from '../helpers/valuesType';
import { ResourceBounds } from '../../provider/types/spec.type';

export type WeierstrassSignatureType = weierstrass.SignatureType;
export type ArraySignatureType = string[];
Expand Down
2 changes: 1 addition & 1 deletion src/utils/hash/transactionHash/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
*/

import { StarknetChainId } from '../../../global/constants';
import { ResourceBounds } from '../../../provider/types/spec.type';
import { BigNumberish, Calldata } from '../../../types';
import {
EDAMode,
ETransactionVersion,
ETransactionVersion2,
ETransactionVersion3,
ResourceBounds,
} from '../../../types/api';
import {
calculateDeclareTransactionHash as v2calculateDeclareTransactionHash,
Expand Down
Loading

0 comments on commit c602d1c

Please sign in to comment.