Search projects, hackathons, sponsors and tech

    ← All projects

    tokenize-it

    Tokenized ESOPs on Hedera: borrow against vested equity without selling it or leaving your wallet.

    Demo

    About

    tokenize-it puts employee stock options on-chain on Hedera, then lets employees do two things that are close to impossible today: borrow against equity they have already earned without selling it, and get paid in the same stablecoin they borrow in. THE PROBLEM Employee stock options are one of the most widely held private-market assets, and one of the worst served. A grant is a PDF, vesting lives in a spreadsheet, and an employee holding vested options in a private company usually can't sell them and can't borrow against them. The wealth is real but locked. WHAT IT DOES 1. Issuance and lifecycle, enforced by the token itself. Options are issued as a compliant security token using Hedera's Asset Tokenization Studio (ERC-1400 / ERC-3643). KYC and an issuer allowlist are enforced by the token, so a transfer to anyone who hasn't been onboarded simply fails. Our vesting contract places the whole grant in the employee's wallet up front, with each vesting tranche locked until its date. Once a date passes, anyone can release it, so vesting never depends on a trusted operator. HR can suspend an employee (vesting continues, transfers pause) or terminate them as a good or bad leaver: vested options stay theirs, and unvested ones can be clawed back into the option pool. 2. Due process for leavers. A termination opens a dispute window before any clawback can happen. The employee can contest it in one click, at no cost. The ruling comes from an arbiter that the contract requires to be a multisig, and whoever made the termination is barred from judging the appeal. Every decision records the deciding address on-chain. 3. Borrowing without giving up custody. An employee pledges vested options to the lending pool as an ERC-1400 hold over their own balance, not a transfer. The shares never leave their wallet; the pool holds zero shares while a loan is open, which anyone can check on-chain. The issuer keeps freeze and clawback rights over pledged equity. The pool lends stablecoin at up to 25% of the collateral's value. If a loan goes bad, liquidation executes the hold through the token's full compliance checks, takes only what is owed, and returns the rest. On testnet it seized 2,174 of 5,000 pledged shares and returned the other 2,826. 4. Payroll in stablecoin, from a treasury nobody controls alone. Salary is paid from a Privy server wallet that can only act with a 2-of-2 quorum of officer keys. A Privy policy limits it to sending to the payroll contract and the stablecoin, so a compromised payroll wallet cannot touch the cap table. The payroll contract only pays employees on the issuer's allowlist. Paying wages in the same stablecoin the pool lends is what makes "borrow against your equity, repay from your salary" work in practice. 5. A web2 experience. Employees sign in with an email and Privy creates a wallet for them. They never install anything, see a seed phrase, or hold HBAR: a relayer pays every network fee, and pledges and repayments are authorised with EIP-712 and EIP-2612 signatures. HR uses their own wallet in the issuer console, so every administrative decision is attributable to a person. HOW IT'S BUILT Hedera testnet; the Asset Tokenization Studio for the security token; four Solidity contracts of our own (ESOPVestingController, ESOPLendingPool, EsopNavOracle, PayrollDisburser); a Next.js app with employee and issuer views; Privy for embedded wallets, server wallets, key quorums and policies; Chainlink's USDC/USD feed on Hedera for the stablecoin price; and a mirror-node indexer for the cap table. 165 tests pass, and every contract is deployed to Hedera testnet and verified on Sourcify/HashScan. Live at https://tokenize-it-git-main-balaji-shetty-pachais-projects.vercel.app/ WHAT'S STILL A STAND-IN - A private company's share price has no public source. The share price feed has Chainlink's interface but is published by a valuation agent from an appraisal; every update is attributed and capped at a 30% move. The stablecoin price feed is a real Chainlink feed. - The stablecoin is a testnet stand-in, and the arbiter is a stand-in multisig. Production would use real USDC and a Safe. - Hedera's scheduled-transaction service (HIP-1215) isn't usable on testnet yet, so automatic vesting runs on a keeper. Because releasing a vested tranche is open to anyone, vesting is correct either way.

    How it's made

    ARCHITECTURE tokenize-it is four Solidity contracts sitting on top of Hedera's Asset Tokenization Studio (ATS), plus one Next.js app that serves two audiences: employees at / and the issuer at /issuer. Everything runs on Hedera testnet. - The ESOP token is an ATS security token: an EIP-2535 diamond (~100 facets) created through ATS's pre-deployed factory. We didn't write a token; we got KYC, an allowlist, freezes, forced transfers, and ERC-1400 locks and holds for free, and designed around those primitives. - ESOPVestingController places a whole grant in the employee's wallet up front and locks each tranche until its vest date. Release is permissionless. Clawback force-releases unvested locks and moves them back into the option pool, rather than burning them, so the hard supply cap never runs out of headroom. - ESOPLendingPool takes collateral as an ERC-1400 hold over the borrower's own balance, with the pool named as escrow. pledgeAndBorrow places the signed hold and opens the loan in a single transaction, so a failure can't leave shares held against a loan that never opened. Liquidation executes the hold through the token's full compliance stack, which meant onboarding the pool itself as a KYC'd, allowlisted institutional holder. - EsopNavOracle speaks Chainlink's AggregatorV3 interface but is published by a valuation agent, with each update attributed and capped at a 30% move. PayrollDisburser pays salary on an accrue-then-withdraw basis, and only to addresses on the ESOP token's allowlist. - The web app uses Next.js 16, React 19 and viem. Its API routes act as a relayer that pays every network fee, so employees never hold HBAR. There is one ABI definition for the whole app, after two copies drifted apart and silently broke the console. - A small indexer builds the cap table from the Hedera mirror node, paging by timestamp. PARTNER TECHNOLOGIES AND WHAT THEY GAVE US - Hedera and ATS: the lending design only works because ERC-1400 holds exist. The collateral never moves, so the lender never takes custody and the issuer keeps clawback and freeze authority over pledged equity. The pool's ESOP balance is provably zero while a loan is open (npm run proof:no-custody). Every contract is verified exact_match on Sourcify, which HashScan reads. - Privy: on the employee side, embedded wallets with email login, and server-side token verification that resolves the wallet address itself, so a client can never claim someone else's equity. On the payroll side, a server wallet owned by a 2-of-2 key quorum of P-256 officer keys, plus a policy that only allows sends to the payroll contract and the stablecoin on chain 296. We tested both by trying to break them: one signature is refused with a 401, and a request to the equity token carrying a full quorum is refused with policy_violation. That policy is what makes the treasury structurally unable to touch the cap table. - Chainlink: the stablecoin price comes from the live USDC/USD feed on Hedera testnet. Because our share-price oracle speaks the same interface, an issuer that later lists can swap in a real feed without touching the pool. THE HACKY AND NOTABLE BITS - Hedera charges gas used, not gas offered. We measured it: the same mint at a 120k limit and a 900k limit cost an identical 0.03710687 HBAR. Meanwhile the estimator is not a safe bound: calls ran out of gas at 99.2% and 99.86% of the estimate, with empty revert data, while the same call simulated fine. So every write uses a generous explicit limit, which costs nothing extra. - Hashio's RPC drops revert data, so failures arrive with no reason attached. Where we could, we check preconditions directly instead of decoding errors. For example, before funding a grant we check whether its tranche dates have already passed, because ATS refuses to lock tokens until a date that has gone by. - With ATS's protected partitions, employees can't transfer directly at all. Every pledge is an EIP-712-signed hold relayed by a backend that holds the partition's participant role. ATS's EIP-712 domain version isn't "1" but the token's config version, so we read it from the chain at runtime. Repayment uses an EIP-2612 permit, so a borrower with no gas can still repay. - ATS trap: freezing an address in whitelist mode removes it from the control list, while isFrozen() reads a different counter and reports false. So the app works out suspension from allowlist status plus grant status. - Hold IDs must come from the event, not the hold count: the count drops when a hold is released while IDs keep climbing, and the two silently diverged. - Hedera's Schedule Service (HIP-1215) lives at 0x16b with no bytecode, so eth_getCode says it doesn't exist; you have to probe it by calling it. On testnet, scheduleCall returns INVALID_CONTRACT_ID for every target, from a wallet and from contract code alike, while hasScheduleCapacity answers true. We built the scheduler anyway, then made a keeper the tier that actually runs. Because release is permissionless, vesting was never wrong without automation, only less automatic. - The first transfer to an unused Hedera address creates a "hollow account", and that ran a plain HBAR transfer out of gas at 200k. - A 37-tranche grant costs about 15.7M gas, over Hedera's 15M per-transaction ceiling, so funding is batched and resumable. - ATS isn't vendored in the repo. A setup script clones it at a pinned commit, and a sync script runs our 165 tests inside ATS's own Hardhat project to reuse its deployment fixtures. One flag in those fixtures is the difference between a 45-second suite and a 36-minute one. - We measured before optimising. OpenZeppelin's ReentrancyGuard saved 17,160 gas per call over our hand-rolled guard, so we switched. Hand-writing unchecked { ++i } saved a flat 44 gas on solc 0.8.28, because the compiler already does it, so we didn't.