HinkalInLogic

Overview

HinkalInLogic and HinkalInLogicBase implement the execution-layer logic that Hinkal.sol delegates to. They manage:

  • Approval UTXOs lifecycle (creation, modification, spending)

  • External protocol execution with precise allowance/balance accounting

  • Proofless deposit flow (token/NFT collection and UTXO formation)

Files

  • contracts/HinkalInLogicBase.sol — core logic and helpers

  • contracts/HinkalInLogic.sol — concrete implementation (external actions, proofless deposit)


Storage

  • mapping(address => ApprovedUtxo[]) approvedUtxos — per interaction/externalAddress approval notes

Approval UTXOs represent token-specific allowances scoped by an inHinkalAddress (a stealth/view context). They enable privacy-preserving approvals that can later be spent during operations.


Logic Actions (driven by CircomData.hinkalLogicArgs.hinkalLogicAction)

  1. ONLY_APPROVAL (1)

    • Sends flat fee to relay and returns immediately. Used to publish approvals without execution.

  2. EXECUTE (2)

    • Full external call flow: spend approvals, perform external call atomically, pay relay, reconcile balances/allowances, mint UTXOs.

Entry point:

function inHinkalTransact(CircomData circomData, int256[] approvalChangesPerToken)
    external payable returns (UTXO[] utxoSet)

Routes to one of: ONLY_APPROVAL, or EXECUTE via inHinkalExecutionFlow (reverts on unknown action).


Approvals: Create/Modify/Spend

handleApprovalUtxos

function handleApprovalUtxos(CircomData circomData) public returns (int256[] result)
  • Iterates UseApprovalUTXOData[] per token index to apply per-externalAddress approval deltas.

  • For each tuple (externalAddress, token, inHinkalAddress, approvalChange):

    • If an approval note exists, update or remove when new amount hits zero.

    • If not found, append a new approval UTXO (only when approvalChange >= 0).

    • Always adjust aggregate ERC20 allowance via approveMore to reflect the net change.

  • Emits NewApprovedUtxo(externalAddress, tokenAddress, approvalChange, inHinkalAddress) per token.


EXECUTE Path: inHinkalExecutionFlow

function inHinkalExecutionFlow(CircomData circomData) internal returns (UTXO[] utxoSet)
  1. Spend approvals: spendApprovedUtxos(circomData)

    • Validates the user owns matching approval UTXOs for tokens being spent.

    • Decrements or removes approval notes according to executeApprovalChanges.

    • Tracks any tokens that must remain balance-stable (unspent set).

  2. Snapshot balances/allowances: before execution

  3. Safety checks:

    • erc20SafetyCheck blocks dangerous ERC20 methods in metadata selectors (approve, mint, transferFrom, etc.).

    • Parse externalActionMetadata and compute ethAmount to attach when the proof indicates ETH spend.

    • Enforce signature/deadline via helper (see HinkalHelper.checkInLogicMetadata).

  4. External call: (success, returnData) = externalAddress.call{value: ethAmount}(callData)

    • Bubble up revert reasons if present; else use a generic error.

  5. Relay payment: send flat fee in feeToken if configured.

  6. Snapshot balances/allowances: after execution

  7. UTXO formation and allowance reconciliation:

    • formUtxosAndCheckSpendings compares pre/post balances and allowances:

      • Positive balance deltas mint UTXOs for that token.

      • Negative balance deltas must match allowance spend (plus relay fee when feeToken matches), else revert.

      • If aggregate allowance spend exceeds intended individual spend, approveMore restores the difference, ensuring aggregate == sum(individual).

    • Emits NewApprovedUtxo reflecting the final per-token execution change.

  8. Unspent-invariant: tokens identified as unspent must have identical balances before and after.

Outcome: returns UTXO[] to be turned into commitments by Hinkal.sol.


External Actions (HinkalInLogic.sol)

function handleRunExternalAction(CircomData circomData, int256[] approvalChangesPerToken)
    external returns (UTXO[])
  • Computes deltaAmountChanges[i] = calculateDeltaAmount(...) per token.

  • For negative deltas, transfers tokens/NFTs to externalAddress pre-call.

  • Invokes IExternalActionV2(externalAddress).runAction(circomData, deltaAmountChanges) which returns UTXO[] created during the action.

This path is used by Hinkal._internalRunExternalAction to integrate with DeFi targets in a privacy-preserving, atomic way.


Proofless Deposit (HinkalInLogic.sol)

function handleProoflessDeposit(address[] erc20Addresses, uint256[] amounts, uint256[] tokenIds, StealthAddressStructure[] stealthAddressStructures)
    public payable returns (UTXO[] utxoArray)
  • Groups identical (token, tokenId) pairs with calcTokenChangesForProoflessDeposit and accumulates amounts (rejects duplicate NFTs).

  • Pulls funds from msg.sender via handleTransfersFromProoflessDeposit and asserts balanceAfter - balanceBefore == amount per token.

  • Forms UTXOs one-to-one with user inputs using handleUtxoCreationEach, setting timeStamp to block.timestamp.

Used by Hinkal.prooflessDeposit to create on-chain commitments without a ZK proof.


Safety and Helpers

  • erc20SafetyCheck: blacklist of ERC20 methods (approve/mint/transferFrom, etc.) disallowed in external calls via metadata selector checks.

  • isERC20: coarse detection to apply safety checks only when necessary.

  • calculateBalances/calculateAllowances: snapshot helpers.

  • approveMore: adjusts aggregate ERC20 allowances to match individual approval changes exactly.


Events

  • NewApprovedUtxo(address approveTo, address tokenAddress, int256 amount, uint256 inHinkalAddress)

These events allow indexers and frontends to reconstruct approval states independently of private commitments.


Reverts and Invariants

  • inHinkalTransact: "msg.value non allowed for inHinkalTransactions"

  • spendApprovedUtxos: ownership and exact-spend assertions; "you cannot spend something you do not own"

  • inHinkalExecutionFlow:

    • External call bubble-up or "Hinkal: External call failed"

    • Unspent equality: "array's must be equal"

    • Allowance/balance match: "balance and allowance Dif mismatch"

  • Approvals: guard against negative creation or out-of-range indices

  • Proofless deposit: length checks, duplicate NFT protection, and exact transfer assertions


Integration Surface with Hinkal.sol

  • Hinkal._inHinkalTransact delegates to inHinkalTransact

  • Hinkal._internalRunExternalAction delegates to handleRunExternalAction

  • Hinkal._handleApprovalUtxos delegates to handleApprovalUtxos

  • Hinkal.prooflessDeposit delegates to handleProoflessDeposit

This separation keeps Hinkal orchestration minimal while letting HinkalInLogic focus on evolving execution semantics.

Last updated