Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 0.12.1 #698

Merged
merged 8 commits into from
Aug 5, 2023
14 changes: 5 additions & 9 deletions __tests__/account.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import {
Account,
Contract,
DeclareDeployUDCResponse,
DeployTransactionReceiptResponse,
Provider,
TransactionStatus,
TransactionType,
cairo,
contractClassResponseToLegacyCompiledContract,
Expand Down Expand Up @@ -338,9 +338,7 @@ describe('deploy and test Wallet', () => {
calldata: [erc20.address, '10', '0'],
});

await provider.waitForTransaction(transaction_hash, {
successStates: [TransactionStatus.ACCEPTED_ON_L2],
});
await provider.waitForTransaction(transaction_hash);
});

test('read balance of wallet after transfer', async () => {
Expand Down Expand Up @@ -379,9 +377,7 @@ describe('deploy and test Wallet', () => {
},
]);

await provider.waitForTransaction(transaction_hash, {
successStates: [TransactionStatus.ACCEPTED_ON_L2],
});
await provider.waitForTransaction(transaction_hash);

const response = await dapp.get_number(account.address);
expect(toBigInt(response.number as string).toString()).toStrictEqual('57');
Expand Down Expand Up @@ -552,7 +548,7 @@ describe('deploy and test Wallet', () => {

// check pre-calculated address
const txReceipt = await provider.waitForTransaction(deployment.transaction_hash);
const udcEvent = parseUDCEvent(txReceipt);
const udcEvent = parseUDCEvent(txReceipt as DeployTransactionReceiptResponse);
expect(cleanHex(deployment.contract_address[0])).toBe(cleanHex(udcEvent.contract_address));
});

Expand All @@ -573,7 +569,7 @@ describe('deploy and test Wallet', () => {

// check pre-calculated address
const txReceipt = await provider.waitForTransaction(deployment.transaction_hash);
const udcEvent = parseUDCEvent(txReceipt);
const udcEvent = parseUDCEvent(txReceipt as DeployTransactionReceiptResponse);
expect(cleanHex(deployment.contract_address[0])).toBe(cleanHex(udcEvent.contract_address));
});

Expand Down
59 changes: 33 additions & 26 deletions __tests__/schemas/rpc.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,41 @@
"$id": "rpcSchemas",
"definitions": {
"GetSyncingStatsResponse": {
"type": "object",
"properties": {
"current_block_hash": {
"type": "string"
},
"current_block_num": {
"type": "string"
},
"highest_block_hash": {
"type": "string"
"oneOf": [
{
"type": "object",
"properties": {
"current_block_hash": {
"type": "string"
},
"current_block_num": {
"type": "number"
},
"highest_block_hash": {
"type": "string"
},
"highest_block_num": {
"type": "number"
},
"starting_block_hash": {
"type": "string"
},
"starting_block_num": {
"type": "number"
}
},
"required": [
"current_block_hash",
"current_block_num",
"highest_block_hash",
"highest_block_num",
"starting_block_hash",
"starting_block_num"
]
},
"highest_block_num": {
"type": "string"
},
"starting_block_hash": {
"type": "string"
},
"starting_block_num": {
"type": "string"
{
"type": "boolean"
}
},
"required": [
"current_block_hash",
"current_block_num",
"highest_block_hash",
"highest_block_num",
"starting_block_hash",
"starting_block_num"
]
},
"StarknetEmittedEvent": {
Expand Down
3 changes: 2 additions & 1 deletion src/account/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
DeployAccountContractTransaction,
DeployContractResponse,
DeployContractUDCResponse,
DeployTransactionReceiptResponse,
Details,
EstimateFee,
EstimateFeeAction,
Expand Down Expand Up @@ -399,7 +400,7 @@ export class Account extends Provider implements AccountInterface {
): Promise<DeployContractUDCResponse> {
const deployTx = await this.deploy(payload, details);
const txReceipt = await this.waitForTransaction(deployTx.transaction_hash);
return parseUDCEvent(txReceipt);
return parseUDCEvent(txReceipt as DeployTransactionReceiptResponse);
}

public async declareAndDeploy(
Expand Down
3 changes: 3 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
export { IS_BROWSER } from './utils/encode';

export const HEX_STR_TRANSACTION_VERSION_1 = '0x1';
export const HEX_STR_TRANSACTION_VERSION_2 = '0x2';

export const ZERO = 0n;
export const MASK_250 = 2n ** 250n - 1n; // 2 ** 250 - 1
export const MASK_251 = 2n ** 251n;
Expand Down
96 changes: 53 additions & 43 deletions src/provider/rpc.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { StarknetChainId } from '../constants';
import {
HEX_STR_TRANSACTION_VERSION_1,
HEX_STR_TRANSACTION_VERSION_2,
StarknetChainId,
} from '../constants';
import {
AccountInvocationItem,
AccountInvocations,
BigNumberish,
BlockIdentifier,
BlockTag,
Call,
CallContractResponse,
ContractClassResponse,
Expand All @@ -19,27 +24,24 @@ import {
Invocation,
InvocationsDetailsWithNonce,
InvokeFunctionResponse,
LegacyContractClass,
RPC,
RpcProviderOptions,
SIMULATION_FLAG,
SierraContractClass,
SimulateTransactionResponse,
TransactionStatus,
TransactionType,
getEstimateFeeBulkOptions,
getSimulateTransactionOptions,
waitForTransactionOptions,
} from '../types';
import {
SimulationFlag,
TransactionExecutionStatus,
TransactionFinalityStatus,
} from '../types/api/rpc';
import { CallData } from '../utils/calldata';
import { isSierra } from '../utils/contract';
import { pascalToSnake } from '../utils/encode';
import fetch from '../utils/fetchPonyfill';
import {
getSelectorFromName,
getVersionsByType,
transactionVersion,
transactionVersion_2,
} from '../utils/hash';
import { getSelectorFromName, getVersionsByType } from '../utils/hash';
import { stringify } from '../utils/json';
import { toHex, toStorageKey } from '../utils/num';
import { wait } from '../utils/provider';
Expand All @@ -54,7 +56,7 @@ import { Block } from './utils';
// Note that pending support is disabled by default and must be enabled by setting poll-pending=true in the configuration options.
const defaultOptions = {
headers: { 'Content-Type': 'application/json' },
blockIdentifier: 'latest',
blockIdentifier: BlockTag.pending,
retries: 200,
};

Expand Down Expand Up @@ -345,7 +347,7 @@ export class RpcProvider implements ProviderInterface {
entry_points_by_type: contract.entry_points_by_type,
abi: contract.abi,
},
version: toHex(transactionVersion),
version: HEX_STR_TRANSACTION_VERSION_1,
max_fee: toHex(details.maxFee || 0),
signature: signatureToHexArray(signature),
sender_address: senderAddress,
Expand All @@ -363,7 +365,7 @@ export class RpcProvider implements ProviderInterface {
abi: contract.abi,
},
compiled_class_hash: compiledClassHash || '',
version: toHex(transactionVersion_2),
version: HEX_STR_TRANSACTION_VERSION_2,
max_fee: toHex(details.maxFee || 0),
signature: signatureToHexArray(signature),
sender_address: senderAddress,
Expand Down Expand Up @@ -434,15 +436,17 @@ export class RpcProvider implements ProviderInterface {
}

public async waitForTransaction(txHash: string, options?: waitForTransactionOptions) {
const errorStates = [TransactionStatus.REJECTED, TransactionStatus.NOT_RECEIVED];
let { retries } = this;
let onchain = false;
let isErrorState = false;
// eslint-disable-next-line no-undef-init
let txReceipt: any = {};

const retryInterval = options?.retryInterval ?? 8000;
const successStates = options?.successStates ?? [
TransactionStatus.ACCEPTED_ON_L1,
TransactionStatus.ACCEPTED_ON_L2,
const retryInterval = options?.retryInterval ?? 5000;
const errorStates: any = options?.errorStates ?? [TransactionExecutionStatus.REVERTED];
const successStates: any = options?.successStates ?? [
TransactionExecutionStatus.SUCCEEDED,
TransactionFinalityStatus.ACCEPTED_ON_L1,
TransactionFinalityStatus.ACCEPTED_ON_L2,
];

while (!onchain) {
Expand All @@ -452,21 +456,28 @@ export class RpcProvider implements ProviderInterface {
// eslint-disable-next-line no-await-in-loop
txReceipt = await this.getTransactionReceipt(txHash);

if (!('status' in txReceipt)) {
const error = new Error('transaction status');
// TODO: Hotfix until Pathfinder release fixed casing
const executionStatus = pascalToSnake(txReceipt.execution_status);
const finalityStatus = pascalToSnake(txReceipt.finality_status);

if (!executionStatus || !finalityStatus) {
// Transaction is potentially REJECTED or NOT_RECEIVED but RPC doesn't have dose statuses
// so we will retry '{ retries }' times
const error = new Error('waiting for transaction status');
throw error;
}

if (txReceipt.status && successStates.includes(txReceipt.status)) {
if (successStates.includes(executionStatus) || successStates.includes(finalityStatus)) {
onchain = true;
} else if (txReceipt.status && errorStates.includes(txReceipt.status)) {
const message = txReceipt.status;
const error = new Error(message) as Error & { response: any };
} else if (errorStates.includes(executionStatus) || errorStates.includes(finalityStatus)) {
const message = `${executionStatus}: ${finalityStatus}: ${txReceipt.revert_reason}`;
const error = new Error(message) as Error & { response: RPC.TransactionReceipt };
error.response = txReceipt;
isErrorState = true;
throw error;
}
} catch (error: unknown) {
if (error instanceof Error && errorStates.includes(error.message as TransactionStatus)) {
} catch (error) {
if (error instanceof Error && isErrorState) {
throw error;
}

Expand Down Expand Up @@ -531,18 +542,19 @@ export class RpcProvider implements ProviderInterface {
{
blockIdentifier = this.blockIdentifier,
skipValidate = false,
skipExecute = false,
skipExecute = false, // @deprecated
skipFeeCharge = true, // Pathfinder currently does not support `starknet_simulateTransactions` without `SKIP_FEE_CHARGE` simulation flag being set. This will become supported in a future release
}: getSimulateTransactionOptions
): Promise<SimulateTransactionResponse> {
const block_id = new Block(blockIdentifier).identifier;

const simulationFlags = [];
if (skipValidate) simulationFlags.push(SIMULATION_FLAG.SKIP_VALIDATE);
if (skipExecute) simulationFlags.push(SIMULATION_FLAG.SKIP_EXECUTE);
if (skipValidate) simulationFlags.push(SimulationFlag.SKIP_VALIDATE);
if (skipExecute || skipFeeCharge) simulationFlags.push(SimulationFlag.SKIP_FEE_CHARGE);

return this.fetchEndpoint('starknet_simulateTransaction', {
return this.fetchEndpoint('starknet_simulateTransactions', {
block_id,
transactions: invocations.map((it) => this.buildTransaction(it)), // TODO: Pathfinder 0.5.6 bug, should be transaction
transactions: invocations.map((it) => this.buildTransaction(it)),
simulation_flags: simulationFlags,
}).then(this.responseParser.parseSimulateTransactionResponse);
}
Expand All @@ -558,7 +570,7 @@ export class RpcProvider implements ProviderInterface {
public buildTransaction(
invocation: AccountInvocationItem,
versionType?: 'fee' | 'transaction'
): RPC.BroadcastedTransaction {
): RPC.BaseTransaction {
const defaultVersions = getVersionsByType(versionType);
const details = {
signature: signatureToHexArray(invocation.signature),
Expand All @@ -571,32 +583,30 @@ export class RpcProvider implements ProviderInterface {
type: RPC.TransactionType.INVOKE, // Diff between sequencer and rpc invoke type
sender_address: invocation.contractAddress,
calldata: CallData.toHex(invocation.calldata),
version: toHex(invocation.version || defaultVersions.v1),
version: toHex(invocation.version || defaultVersions.v1) as any, // HEX_STR_TRANSACTION_VERSION_1, // as any HOTFIX TODO: Resolve spec version
...details,
};
}
if (invocation.type === RPC.TransactionType.DECLARE) {
if (invocation.type === TransactionType.DECLARE) {
if (!isSierra(invocation.contract)) {
const legacyContract = invocation.contract as LegacyContractClass;
return {
type: invocation.type,
contract_class: legacyContract,
contract_class: invocation.contract,
sender_address: invocation.senderAddress,
version: toHex(invocation.version || defaultVersions.v1),
version: toHex(invocation.version || defaultVersions.v1) as any, // HEX_STR_TRANSACTION_VERSION_1, // as any HOTFIX TODO: Resolve spec version
...details,
};
}
const sierraContract = invocation.contract as SierraContractClass;
return {
// compiled_class_hash
type: invocation.type,
contract_class: {
...sierraContract,
sierra_program: decompressProgram(sierraContract.sierra_program),
...invocation.contract,
sierra_program: decompressProgram(invocation.contract.sierra_program),
},
compiled_class_hash: invocation.compiledClassHash || '',
sender_address: invocation.senderAddress,
version: toHex(invocation.version || defaultVersions.v2),
version: toHex(invocation.version || defaultVersions.v2) as any, // HEX_STR_TRANSACTION_VERSION_2, // as any HOTFIX TODO: Resolve spec version
...details,
};
}
Expand Down
Loading