> ## Documentation Index
> Fetch the complete documentation index at: https://voltaire.tevm.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# getSelector

> Extract 4-byte function selector from CallData

Extracts the function selector (first 4 bytes) from calldata. The selector identifies which function to invoke in a smart contract.

## Signature

<Tabs>
  <Tab title="Namespace">
    ```typescript theme={null}
    function getSelector(calldata: CallDataType): [4]u8
    ```
  </Tab>

  <Tab title="Class">
    ```typescript theme={null}
    calldata.getSelector(): [4]u8
    ```
  </Tab>
</Tabs>

## Parameters

* **calldata** - CallData instance to extract selector from

## Returns

`[4]u8` - 4-byte array containing function selector

## Examples

<Tabs>
  <Tab title="Basic Usage">
    ```typescript theme={null}
    import { CallData } from '@tevm/voltaire';

    const calldata = CallData("0xa9059cbb...");
    const selector = CallData.getSelector(calldata);

    console.log(selector);
    // [0xa9, 0x05, 0x9c, 0xbb]
    ```
  </Tab>

  <Tab title="Hex Format">
    ```typescript theme={null}
    import { CallData, Hex } from '@tevm/voltaire';

    const calldata = CallData("0xa9059cbb...");
    const selector = CallData.getSelector(calldata);

    // Convert to hex string
    const hex = Hex.fromBytes(selector);
    console.log(hex); // "0xa9059cbb"
    ```
  </Tab>

  <Tab title="Class API">
    ```typescript theme={null}
    import { CallData } from '@tevm/voltaire';

    const calldata = CallData("0xa9059cbb...");
    const selector = calldata.getSelector(); // Method on instance

    console.log(selector);
    ```
  </Tab>
</Tabs>

## Function Selectors

Function selector is first 4 bytes of `keccak256(signature)`:

```typescript theme={null}
import { Keccak256 } from '@tevm/voltaire';

// Compute selector manually
const signature = "transfer(address,uint256)";
const hash = Keccak256.hashString(signature);
const selector = hash.slice(0, 4);

console.log(selector);
// [0xa9, 0x05, 0x9c, 0xbb]

// Same as extracting from calldata
const calldata = abi.transfer.encode(recipient, amount);
console.log(CallData.getSelector(calldata));
// [0xa9, 0x05, 0x9c, 0xbb] (identical)
```

## Common Selectors

<Tabs>
  <Tab title="ERC20">
    ```typescript theme={null}
    const ERC20_SELECTORS = {
      TRANSFER: [0xa9, 0x05, 0x9c, 0xbb],      // transfer(address,uint256)
      APPROVE: [0x09, 0x5e, 0xa7, 0xb3],       // approve(address,uint256)
      TRANSFER_FROM: [0x23, 0xb8, 0x72, 0xdd], // transferFrom(address,address,uint256)
      BALANCE_OF: [0x70, 0xa0, 0x82, 0x31],    // balanceOf(address)
      ALLOWANCE: [0xdd, 0x62, 0xed, 0x3e],     // allowance(address,address)
    } as const;

    function matchERC20Function(calldata: CallDataType): string {
      const selector = CallData.getSelector(calldata);

      if (selectorEquals(selector, ERC20_SELECTORS.TRANSFER)) {
        return "transfer";
      } else if (selectorEquals(selector, ERC20_SELECTORS.APPROVE)) {
        return "approve";
      }
      // ...
    }
    ```
  </Tab>

  <Tab title="ERC721">
    ```typescript theme={null}
    const ERC721_SELECTORS = {
      SAFE_TRANSFER_FROM: [0x42, 0x84, 0x2e, 0x0e], // safeTransferFrom(address,address,uint256)
      TRANSFER_FROM: [0x23, 0xb8, 0x72, 0xdd],      // transferFrom(address,address,uint256)
      APPROVE: [0x09, 0x5e, 0xa7, 0xb3],            // approve(address,uint256)
      SET_APPROVAL_FOR_ALL: [0xa2, 0x2c, 0xb4, 0x65], // setApprovalForAll(address,bool)
      OWNER_OF: [0x63, 0x52, 0x21, 0x1e],           // ownerOf(uint256)
    } as const;
    ```
  </Tab>
</Tabs>

## Use Cases

### Function Routing

```typescript theme={null}
import { CallData } from '@tevm/voltaire';

function routeCall(calldata: CallDataType) {
  const selector = CallData.getSelector(calldata);
  const selectorHex = Hex.fromBytes(selector);

  switch (selectorHex) {
    case "0xa9059cbb":
      return handleTransfer(calldata);
    case "0x095ea7b3":
      return handleApprove(calldata);
    case "0x23b872dd":
      return handleTransferFrom(calldata);
    default:
      throw new Error(`Unknown function: ${selectorHex}`);
  }
}
```

### Selector Matching

```typescript theme={null}
import { CallData } from '@tevm/voltaire';

function isTransfer(calldata: CallDataType): boolean {
  const selector = CallData.getSelector(calldata);
  const TRANSFER_SELECTOR = [0xa9, 0x05, 0x9c, 0xbb];

  return selector.every((byte, i) => byte === TRANSFER_SELECTOR[i]);
}

// Or use hasSelector helper
const isTransfer = CallData.hasSelector(calldata, "0xa9059cbb");
```

### Transaction Filtering

```typescript theme={null}
import { CallData } from '@tevm/voltaire';

interface Transaction {
  to: string;
  data: string;
}

function filterERC20Transfers(txs: Transaction[]): Transaction[] {
  const TRANSFER_SELECTOR = [0xa9, 0x05, 0x9c, 0xbb];

  return txs.filter(tx => {
    try {
      const calldata = CallData(tx.data);
      const selector = CallData.getSelector(calldata);
      return selector.every((byte, i) => byte === TRANSFER_SELECTOR[i]);
    } catch {
      return false;
    }
  });
}
```

### Contract Interface Detection

```typescript theme={null}
import { CallData } from '@tevm/voltaire';

const ERC20_SELECTORS = new Set([
  "0xa9059cbb", // transfer
  "0x095ea7b3", // approve
  "0x23b872dd", // transferFrom
  "0x70a08231", // balanceOf
]);

function looksLikeERC20(calldata: CallDataType): boolean {
  const selector = CallData.getSelector(calldata);
  const hex = Hex.fromBytes(selector);
  return ERC20_SELECTORS.has(hex);
}
```

## Performance

Selector extraction is extremely fast (just array slice):

```typescript theme={null}
// Benchmark: 10M iterations
const calldata = CallData("0xa9059cbb...");

console.time("getSelector");
for (let i = 0; i < 10_000_000; i++) {
  CallData.getSelector(calldata);
}
console.timeEnd("getSelector");

// Pure JS: ~120ms
// WASM: ~65ms (1.8x faster)
// Effectively zero-cost operation
```

## Selector Collisions

Different functions can have same selector (rare but possible):

```typescript theme={null}
// Example collision (contrived)
const sig1 = "transfer(address,uint256)";
const sig2 = "transferFrom(address,address)"; // Hypothetical collision

// Both hash to same first 4 bytes (extremely rare)
// Probability: 1 in 4,294,967,296 (2^32)
```

Real collisions are virtually impossible but:

* Always validate full function signature when security-critical
* Use ABI decoding to verify parameter types
* Don't rely solely on selector for authentication

## Zero-Copy Access

Direct byte access without allocation:

```typescript theme={null}
import { CallData } from '@tevm/voltaire';

const calldata = CallData.fromBytes(
  new Uint8Array([0xa9, 0x05, 0x9c, 0xbb, ...])
);

// Zero-copy: Returns view of first 4 bytes
const selector = CallData.getSelector(calldata);

// Mutations visible (don't mutate!)
selector[0] = 0xff;
console.log(calldata[0]); // 0xff (affected!)
```

For immutability, copy selector:

```typescript theme={null}
const selector = CallData.getSelector(calldata).slice(); // Copy
```

## Related

* [hasSelector](/primitives/calldata/has-selector) - Check for specific selector
* [decode](/primitives/calldata/decode) - Decode full calldata
* [Fundamentals](/primitives/calldata/fundamentals) - How selectors work
* [Keccak256](/crypto/keccak256) - Selector computation
