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

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.

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

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

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.


In-Logic Metadata Validation (EXECUTE)

function checkInLogicMetadata(CircomData circomData) internal view
  • Only for action EXECUTE (3):

    • Parses metadata, checks EIP-1271/EOA signature with inLogicSigner over a typed hash of (deadline, tokens[], externalAddress, externalCallData).

    • Requires deadline >= block.timestamp.

    • Ensures every signed token is present in circomData.erc20TokenAddresses.

function calculateInLogicHash(CircomData circomData, ParsedInLogicMetadata parsed)
    internal view returns (bytes32)
  • EIP-712 domain: HinkalHelper, version 1.0.0.

  • Encoding binds call intent to the current externalAddress and token set.


performHinkalChecks — The Preflight Gate

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

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

  • EIP-712 binding of EXECUTE intent prevents replay across addresses or altered call data.

  • Relay control plus registry policy ensure gas economics are enforced out-of-circuit.

  • All checks are read-only and must pass before proof verification and state mutations in Hinkal.sol.

Last updated