Skip to content

Commit

Permalink
chore: refactor execute txn
Browse files Browse the repository at this point in the history
  • Loading branch information
stanleyyconsensys committed Dec 10, 2024
1 parent 8b8d4b6 commit 0ee7431
Show file tree
Hide file tree
Showing 6 changed files with 504 additions and 197 deletions.
132 changes: 46 additions & 86 deletions packages/starknet-snap/src/chain/data-client/starkscan.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,18 @@
import { TransactionType, constants } from 'starknet';
import type { Struct } from 'superstruct';

import {
ContractFuncName,
TransactionDataVersion,
type Network,
type Transaction,
type TranscationAccountCall,
} from '../../types/snapState';
import {
TRANSFER_SELECTOR_HEX,
UPGRADE_SELECTOR_HEX,
} from '../../utils/constants';
import type { V2Transaction } from '../../types/snapState';
import { type Network, type Transaction } from '../../types/snapState';
import { InvalidNetworkError } from '../../utils/exceptions';
import {
newDeployTransaction,
newInvokeTransaction,
} from '../../utils/transaction';
import type { HttpHeaders } from '../api-client';
import { ApiClient, HttpMethod } from '../api-client';
import type { IDataClient } from '../data-client';
import type { StarkScanTransactionsResponse } from './starkscan.type';
import {
type StarkScanAccountCall,
type StarkScanTransaction,
type StarkScanOptions,
StarkScanTransactionsResponseStruct,
Expand Down Expand Up @@ -185,10 +179,6 @@ export class StarkScanClient extends ApiClient implements IDataClient {
return tx.transaction_type === TransactionType.DEPLOY_ACCOUNT;
}

protected isFundTransferTransaction(entrypoint: string): boolean {
return entrypoint === TRANSFER_SELECTOR_HEX;
}

protected getContractAddress(tx: StarkScanTransaction): string {
// backfill the contract address if it is null
return tx.contract_address ?? '';
Expand All @@ -207,94 +197,64 @@ export class StarkScanClient extends ApiClient implements IDataClient {
}

protected toTransaction(tx: StarkScanTransaction): Transaction {
/* eslint-disable @typescript-eslint/naming-convention */
/* eslint-disable @typescript-eslint/naming-convention, camelcase */
const {
transaction_hash: txnHash,
transaction_type: txnType,
timestamp,
transaction_finality_status: finalityStatus,
transaction_execution_status: executionStatus,
max_fee: maxFee,
max_fee,
actual_fee: actualFee,
revert_error: failureReason,
revert_error,
// account_calls representing the calls to invoke from the account contract, it can be multiple
// If the transaction is a deploy transaction, the account_calls is a empty array
account_calls: calls,
version,
version: txnVersion,
} = tx;

// account_calls representing the calls to invoke from the account contract, it can be multiple
// If the transaction is a deploy transaction, the account_calls is a empty array
const accountCalls = this.toAccountCall(calls);
const { chainId } = this.network;
const senderAddress = this.getSenderAddress(tx);
const failureReason = revert_error ?? '';
const maxFee = max_fee ?? '0';

let transaction: V2Transaction;

// eslint-disable-next-line no-negated-condition
if (!this.isDeployTransaction(tx)) {
transaction = newInvokeTransaction({
txnHash,
senderAddress,
chainId,
maxFee,
calls: calls.map((call) => ({
contractAddress: call.contract_address,
entrypoint: call.selector,
calldata: call.calldata,
})),
txnVersion,
});
} else {
transaction = newDeployTransaction({
txnHash,
senderAddress,
chainId,
txnVersion,
});
}

return {
txnHash,
txnType,
chainId: this.network.chainId,
senderAddress: this.getSenderAddress(tx),
...transaction,
// Override the fields from the StarkScanTransaction
timestamp,
finalityStatus,
executionStatus,
maxFee,
actualFee,
maxFee,
contractAddress: this.getContractAddress(tx),
accountCalls,
failureReason: failureReason ?? '',
version,
dataVersion: TransactionDataVersion.V2,
failureReason,
txnType,
};

/* eslint-enable */
}

protected toAccountCall(
accountCalls: StarkScanAccountCall[],
): Record<string, TranscationAccountCall[]> | null {
if (!accountCalls || accountCalls.length === 0) {
return null;
}

return accountCalls.reduce(
(
data: Record<string, TranscationAccountCall[]>,
accountCallArg: StarkScanAccountCall,
) => {
const {
contract_address: contract,
selector,
calldata: contractCallData,
} = accountCallArg;

const contractFuncName = this.selectorHexToName(selector);
if (!Object.prototype.hasOwnProperty.call(data, contract)) {
data[contract] = [];
}

const accountCall: TranscationAccountCall = {
contract,
contractFuncName,
contractCallData,
};

if (this.isFundTransferTransaction(selector)) {
accountCall.recipient = accountCallArg.calldata[0];
accountCall.amount = accountCallArg.calldata[1];
}

data[contract].push(accountCall);

return data;
},
{},
);
}

protected selectorHexToName(selector: string): string {
switch (selector.toLowerCase()) {
case TRANSFER_SELECTOR_HEX.toLowerCase():
return ContractFuncName.Transfer;
case UPGRADE_SELECTOR_HEX.toLowerCase():
return ContractFuncName.Upgrade;
default:
return selector;
}
}
}
7 changes: 4 additions & 3 deletions packages/starknet-snap/src/rpcs/execute-txn.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import * as formatUtils from '../utils/formatter-utils';
import * as starknetUtils from '../utils/starknetUtils';
import {
feeTokenToTransactionVersion,
newDeployTransaction as newDeployTransactionFn,
newInvokeTransaction as newInvokeTransactionFn,
transactionVersionToFeeToken,
transactionVersionToNumber,
} from '../utils/transaction';
Expand Down Expand Up @@ -627,16 +629,15 @@ describe('ExecuteTxn', () => {
calls,
} as unknown as SaveDataToStateParamas;

const txnMgr = new TransactionStateManager(true);
const newInvokeTransaction = txnMgr.newInvokeTransaction({
const newInvokeTransaction = newInvokeTransactionFn({
senderAddress: account.address,
txnHash: request.txnHashForExecute,
chainId: network.chainId,
maxFee,
txnVersion: transactionVersionToNumber(txnVersion),
calls,
});
const newDeployTransaction = txnMgr.newDeployTransaction({
const newDeployTransaction = newDeployTransactionFn({
senderAddress: account.address,
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
txnHash: request.txnHashForDeploy!,
Expand Down
6 changes: 4 additions & 2 deletions packages/starknet-snap/src/rpcs/execute-txn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ import {
transactionVersionToNumber,
feeTokenToTransactionVersion,
transactionVersionToFeeToken,
newDeployTransaction,
newInvokeTransaction,
} from '../utils/transaction';
import type { AccountRpcControllerOptions } from './abstract/account-rpc-controller';
import { AccountRpcController } from './abstract/account-rpc-controller';
Expand Down Expand Up @@ -368,7 +370,7 @@ export class ExecuteTxnRpc extends AccountRpcController<

if (txnHashForDeploy) {
await this.txnStateManager.addTransaction(
this.txnStateManager.newDeployTransaction({
newDeployTransaction({
senderAddress: address,
txnHash: txnHashForDeploy,
chainId,
Expand All @@ -383,7 +385,7 @@ export class ExecuteTxnRpc extends AccountRpcController<
}

await this.txnStateManager.addTransaction(
this.txnStateManager.newInvokeTransaction({
newInvokeTransaction({
senderAddress: address,
txnHash: txnHashForExecute,
chainId,
Expand Down
105 changes: 1 addition & 104 deletions packages/starknet-snap/src/state/transaction-state-manager.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { Call, constants } from 'starknet';
import type { constants, TransactionType } from 'starknet';
import {
TransactionType,
TransactionFinalityStatus,
TransactionExecutionStatus,
} from 'starknet';
Expand All @@ -11,7 +10,6 @@ import {
TransactionDataVersion,
TransactionStatusType,
} from '../types/snapState';
import { msToSec } from '../utils';
import type { IFilter } from './filter';
import {
BigIntFilter,
Expand Down Expand Up @@ -339,105 +337,4 @@ export class TransactionStateManager extends StateManager<Transaction> {
throw new StateManagerError(error.message);
}
}

/**
* Creates a new transaction object with the given data.
*
* @param params - The parameters of the new transaction object.
* @param params.txnHash - The txn hash.
* @param params.senderAddress - The sender address.
* @param params.chainId - The chain id.
* @param params.maxFee - The max fee.
* @param params.calls - The array of `Call` object.
* @param params.txnVersion - The transaction version.
* @returns The new transaction object.
*/
newInvokeTransaction({
txnHash,
senderAddress,
chainId,
calls,
txnVersion,
maxFee,
}: {
txnHash: string;
senderAddress: string;
chainId: string;
maxFee: string;
calls: Call[];
txnVersion: number;
}): V2Transaction {
return {
txnHash,
txnType: TransactionType.INVOKE,
chainId,
senderAddress,
contractAddress: '',
finalityStatus: TransactionFinalityStatus.RECEIVED,
// FIXME: executionStatus will be using the same result as finality if the transaction is yet confirmed
executionStatus: TransactionFinalityStatus.RECEIVED,
failureReason: '',
timestamp: msToSec(Date.now()),
dataVersion: TransactionDataVersion.V2,
version: txnVersion,
maxFee,
// actualFee is always null if the transaction is yet confirmed
actualFee: null,
accountCalls: calls.reduce((acc, callData) => {
const { contractAddress, calldata, entrypoint } = callData;

if (!Object.prototype.hasOwnProperty.call(acc, contractAddress)) {
acc[contractAddress] = [];
}
acc[contractAddress].push({
contract: contractAddress,
contractFuncName: entrypoint,
contractCallData: calldata,
});

return acc;
}, {}),
};
}

/**
* Creates a new transaction object for the deploy account transaction.
*
* @param params - The parameters of the new transaction object.
* @param params.txnHash - The txn hash.
* @param params.senderAddress - The sender address.
* @param params.chainId - The chain id.
* @param params.txnVersion - The transaction version.
* @returns The new transaction object.
*/
newDeployTransaction({
txnHash,
senderAddress,
chainId,
txnVersion,
}: {
txnHash: string;
senderAddress: string;
chainId: string;
txnVersion: number;
}): V2Transaction {
return {
txnHash,
txnType: TransactionType.DEPLOY_ACCOUNT,
chainId,
senderAddress,
contractAddress: senderAddress,
finalityStatus: TransactionFinalityStatus.RECEIVED,
// FIXME: executionStatus will be using the same result as finality if the transaction is yet confirmed
executionStatus: TransactionFinalityStatus.RECEIVED,
failureReason: '',
timestamp: msToSec(Date.now()),
dataVersion: TransactionDataVersion.V2,
version: txnVersion,
maxFee: null,
// actualFee is always null if the transaction is yet confirmed
actualFee: null,
accountCalls: null,
};
}
}
Loading

0 comments on commit 0ee7431

Please sign in to comment.