> For the complete documentation index, see [llms.txt](https://hinkal-team.gitbook.io/hinkal/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://hinkal-team.gitbook.io/hinkal/technical-description/evm-tron-smart-contracts/hinkalhelper.md).

# HinkalHelper

**Overview**

`HinkalHelper` acts as the policy and preflight engine for Hinkal transactions. It centralizes:

* Relay whitelisting and fee policy (via `RelayStore`)
* Token registry and per-token limits (via `ERC20TokenRegistry`)
* Circuit public input construction (via `CircomDataBuilder`)
* EIP-712 validation for in-logic external call metadata
* Access token (allowlist) verification and minting

The helper is upgradeable separately from core state, allowing governance to evolve policy without changing state layout.

**Inheritance**

* `RelayStore` — whitelisted relays and fee calculations
* `ERC20TokenRegistry` — gas token list and per-token limits
* `CircomDataBuilder` — forms public inputs for circuits
* `HinkalInLogicMetadataParser` — decodes signed metadata
* `EIP712` — domain separator and typed-data hashing

**Key Storage**

* `address public hinkalAddress` — only this address may call certain functions
* `IAccessToken public accessToken` — access token registry
* `address public inLogicSigner` — signer authorized for EXECUTE metadata

***

#### Admin Functions

* `setAccessToken(address)` — update access token contract
* `setHinkalAddress(address)` — set the canonical Hinkal caller
* `setInLogicSigner(address)` — set expected signer for EXECUTE metadata
* `updateStakeCircuits(uint256 id, bool value)` — toggle stake-circuit IDs in `CircomDataBuilder` Plus the registry/relay admin functions inherited from parents.

***

#### Relay Policy

```solidity
function relayerIsValid(address relay) internal view
```

* If relay is non-zero: requires `tx.origin == relay` and `isRelayInList(relay)`. Rationale: ensures the relay who submits is the one being paid and is whitelisted.

```solidity
function checkRelayFeeParameters(CircomData circomData) internal view
```

* For non-wallet actions or Emporium action, `feeToken` must be a registered gas token.
* For any non-zero logic action, `feeToken` must be present in the tx token list.

***

#### Token Registry Policy

```solidity
function checkTokenRegistry(address[] erc20TokenAddresses, int256[] amountChanges)
    public view returns (bool limitHit)
```

* If registry disabled, returns false.
* Otherwise, checks each token’s absolute `amountChanges[i]` against configured `tokenLimit`.
* Returns true if any limit is exceeded — used to decide if access token checks/minting are required.

***

#### Dimension and Shape Validation

```solidity
function dimensionsCheck(CircomData circomData, Dimensions dimensions) internal pure
```

* Enforces equality of array lengths with `dimensions` for tokens, nullifiers per input, and outputs.
* Requires non-zero `extraRandomization` in `stealthAddressStructure`.
* Asserts `onChainCreation`, `slippageValues`, and `useApprovalUtxoData` lengths equal token count.
* If `hinkalLogicAction != 0`, requires `externalActionId == HINKAL_WALLET_ACTION_ID` (wallet flow).
* If action is not RELEASE\_BUFFER/EXECUTE, then `executeApprovalChanges` must be all zeros.

***

#### performHinkalChecks — The Preflight Gate

```solidity
function performHinkalChecks(CircomData circomData, Dimensions dimensions, address sender)
    external view returns (uint256[] inputForCircom)
```

Sequence:

1. Timestamp freshness check (commented for dev/forking convenience).
2. Sender/relay consistency:
   * Either relayed (nonzero relay, `originalSender == 0`) or direct (relay zero, `originalSender == sender`).
3. Calldata integrity: `CircomDataBuilder.getHashedCalldata(circomData) == circomData.calldataHash`.
4. Relay policy: `relayerIsValid(circomData.relay)` and `checkRelayFeeParameters`.
5. Dimensions and shape: `dimensionsCheck`.
6. Token registry and access token requirement:
   * If any token exceeds limit and no signature provided (`v == 0`): require `accessToken.checkForRootHash(rootHashAccessToken, tx.origin)`.
   * If signature provided: require `rootHashAccessToken == signatureData.accessKey`.
7. EXECUTE metadata validation: `checkInLogicMetadata` (signature + deadline + token set).
8. Return `formInputForCircom(circomData)` for proof verification.

Effect: This function is the canonical place where user intent, policy, and circuit shape are bound and validated before any value moves.

***

#### performSideEffects — Access Token Minting

```solidity
function performSideEffects(CircomData circomData) external onlyHinkal
```

* Calls `mintAccessTokenIfNecessary` which mints a token via `accessToken.addToken(signatureData)` when a signature is provided.

***

#### Integration Points

* Called by `Hinkal.transact` prior to proof verification.
* Provides `calculateRelayFee` and relay list from `RelayStore` for use in core flows.
* Supplies `isGasToken` and token limits via `ERC20TokenRegistry`.
* Builds the Groth16 public input vector consistent with the circuit.

***

#### Reverts and Errors

* "Unauthorized relay" / "Relay is not whitelisted"
* "invalid value for originalSender"
* "Calldata Hash Integrity Check Failed"
* "FeeToken should be gas token"
* "fee token should be included in erc20Token array"
* Dimension mismatches (token/nullifier/commitment counts)
* "Extra-randomization cannot be zero"
* "spend approvals should be zero" (when action not allowed to spend)
* "Wallet External Id should be choosen"
* "invalid inLogic Signature" / "deadline passed" / "missing token from parsedMetadata"
* Access token checks: "Access Token Root Hash is Incorrect" / "accessKey must be used"

***

#### Security Notes
