# $UP distribution and launch design recommendation

Prepared 25 September 2026. This is a design review, not a contract audit. No implementation, bytecode review, gas benchmark, or independent verification was performed.

**Recommendation.** Use sponsored batch push payouts for approximately 370 miners, directly from a constrained vault/distribution contract, with a fixed threshold of independent attestors authorizing each completed day's allocation. Keep fee harvesting separate from swaps; forward harvested fees to an immutable splitter that records independent withdrawal credits. Do not ship the current unrestricted distributor custody path, an ambiguous 7× release rule, or the fee policy until ETH handling and recycled emissions are specified. A permanently locked single range is possible, but cannot promise continuous liquidity or fee income.

**Evidence labels.** “Given” means supplied in the assignment and not independently established. “Verified” means supported by the linked primary source, not verified against deployed bytecode. “Calculation” is arithmetic from explicit assumptions. “Estimate” is a planning allowance, not measured gas or a live quote. “Recommendation/inference” is my judgment. Unanswered deployment questions appear at the end. Sources were accessed on the preparation date; source links to `main`/`master` are mutable.

**Network facts verified.** Robinhood's official page lists mainnet chain ID 4663 and ETH as the gas currency. Uniswap's official deployment table lists the supplied PoolManager, `0x8366a39CC670B4001A1121B8F6A443A643e40951`, for that network. This confirms published deployment information, not its runtime hash or the proposed pool configuration. [Robinhood network information](https://robinhood.com/us/en/support/articles/robinhood-chain-testnet/), [Uniswap v4 deployments](https://developers.uniswap.org/docs/protocols/v4/deployments).

**1. Distribution to miners**

Given: a daily budget, final task counts from one off-chain API, approximately 370 recipients, and no recipient gas. My choice is push delivery with the sponsor paying gas. Remove the transfer to an externally controlled distributor: attest to the allocation, then have the vault or its immutable payout contract transfer directly to the listed accounts. A public executor should be able to finish an already authorized allocation. Separating attestation from execution prevents loss of the gas-paying key from authorizing theft.

The proposed two-transaction `release(to=distributor)` then `BatchPay.pay()` leaves a custody gap: payment failure leaves funds in the distributor, and compromise permits omission or redirection. Atomic release-and-payment removes the temporal gap, but does not make maliciously supplied addresses or amounts honest. The destination constraints and authorization must apply inside the vault's only release path.

| Model | Estimated execution gas for 370 recipients | Recipient experience | Operational tradeoff |
| --- | --- | --- | --- |
| Sponsored batch push | About 4–7M on repeat days with nonzero recipient balances; 10–13M if all recipient balances start at zero. Budget modest additional authorization/bookkeeping overhead. | 0 signatures, 0 transactions initiated, 0 ETH required. Tokens arrive after settlement. | Typically 1 transaction if limits permit, or 4 chunks of at most 100 recipients. Sponsor pays and retries. |
| Daily Merkle claims | Root registration/funding roughly 60–150k; individual claims roughly 50–90k each, hence 18.5–33.3M if all 370 claim separately, plus registration. | Unsponsored: 370 transactions/day and every miner needs ETH. Sponsored permissionless claims: 0 recipient signatures or ETH; relayer executes up to 370 transactions, or batches them. | Saves transfers when few people claim; adds proof publication, claim tracking and relayer availability. Batched proofs share overhead and can approach push costs, but retain proof verification work. |
| Funded linear streams | Illustrative creation allowance 100–250k each: 37–92.5M for 370 new streams; withdrawals roughly 40–90k each: 14.8–33.3M per full withdrawal round. Reusable custom streams may be much cheaper. | A growing claimable balance is not necessarily spendable ERC-20 in the wallet. Withdrawals still need sponsorship. | Daily creation means 135,050 streams/year. Persistent rates avoid this but require up to 370 daily checkpoint/rate updates, funding and withdrawals. |

These are **engineering estimates for ordinary ERC-20 behavior**, excluding parent-chain data charges, deployments, unusual token logic, and particular streaming product fees. They are not Sablier or Robinhood benchmark results. Push ranges allow roughly 10–18k per repeat recipient or 26–34k per initially empty recipient, plus fixed work. Storage explains the difference: EIP-2200 prices zero-to-nonzero writes at 20,000 gas; EIP-2929 adds cold-access costs and changes reset pricing. Transfers also emit logs and perform arithmetic/calls. Emptying a wallet between payouts can recreate the expensive case every day. [EIP-2200](https://eips.ethereum.org/EIPS/eip-2200), [EIP-2929](https://eips.ethereum.org/EIPS/eip-2929).

**Concrete cost sensitivity, not live pricing:** at an assumed execution price of 0.01 gwei/gas, 4–7M gas costs 0.00004–0.00007 ETH/day; 10–13M costs 0.00010–0.00013 ETH. At an illustrative ETH price of $3,000 these are $0.12–$0.21 and $0.30–$0.39. Separate claims cost approximately $0.56–$1.00 for everyone; new streams plus one withdrawal round cost $1.55–$3.77. At 0.1 gwei multiply these by ten. **Add data charges to every figure.** Nitro pricing includes execution and parent-chain posting costs, affected by compression. Do not assume Arbitrum One's gas floor, limits or DA configuration applies here. Use actual calldata with `eth_estimateGas` and `NodeInterface.gasEstimateComponents` on Robinhood before choosing a batch size. [Arbitrum gas and fees](https://docs.arbitrum.io/how-arbitrum-works/deep-dives/gas-and-fees).

**Data calculation:** ABI arrays of 370 addresses and amounts contain 23,680 bytes of elements, before offsets and lengths. A padded binary Merkle tree needs nine sibling hashes per proof: 288 bytes. A conventional `(index,account,amount,proof)` claim with nine siblings is approximately 452 calldata bytes; 370 separate claims total 167,240 bytes before transaction envelopes. Proofs are relatively incompressible. Multiproofs and batching improve this; a 32-byte root alone is not the cost of getting everyone's tokens delivered.

A Merkle proof establishes inclusion in an authorized allocation, not truthful task performance. Uniswap's reference distributor permits anyone to submit a proof and always transfers to the leaf's account; thus gasless recipients do **not** require account abstraction or a signed meta-transaction. That reference uses an immutable single root; daily roots require additional epoch accounting. [Uniswap MerkleDistributor](https://raw.githubusercontent.com/Uniswap/merkle-distributor/master/contracts/MerkleDistributor.sol).

For this scale I would start with a threshold-signed full batch manifest and replay-safe chunks. Require the signed manifest to bind every destination and amount; a executor must not substitute a chunk. A daily Merkle root plus batched permissionless `claimFor` is a reasonable variant if independent fallback claims matter. Use chain ID, contract, epoch and allocation identity in authorization; unique leaf indices, a payout bitmap, an epoch total and reserved funding prevent replay and cross-epoch overspending. Publish the complete allocation and task snapshot, not merely the root. Let miners retain proofs. Keep unpaid obligations funded with no short claim expiry or owner sweep.

**UX timing assumptions:** with once-daily settlement, a completed task waits 0–24 hours until cutoff, averaging 12 hours if completion times are uniform, plus API processing and transaction inclusion. A 24-hour review window changes this to 24–48 hours, averaging 36. These are scheduling numbers, not a promise about chain finality. Four payout chunks mean four sponsor submissions, not four user actions.

Streaming is a poor fit for weights known only after the day ends. Streaming yesterday's earned allocation over the next 24 hours adds vesting delay; streaming today's forecast needs corrections when final weights change. Sablier Lockup, for example, locks funding and lets recipients withdraw amounts that become available over time. [Sablier Lockup overview](https://docs.sablier.com/concepts/lockup/overview). My inference: streaming becomes worthwhile only if continuous vesting is an intended product feature. It does not remove the task oracle or provide free transfers every second. No streaming deployment on Robinhood was established here.

**2. Distributor trust and damage limits**

**Calculation:** initially B = 3.8M UP/day, so 7B = 26.6M UP, 2.66% of the initial supply and about 3.89% of the 684M reserve. If the sole rule is “at most 7B withdrawn in each epoch” from a fully funded vault, an attacker can take 53.2M around adjacent daily boundaries and drain 684M in 26 epochs, all within the first 90-day band. A daily cap is neither a lifetime bound nor a seven-day rolling limit. A sustained compromised key can keep taking future allocations even when capped at B.

**Highest-value prerequisite:** enforce cumulative schedule maturity independently of the signer: base emissions paid plus reserved obligations must never exceed the sum of matured epoch budgets. Each completed epoch can be allocated only once; retries cannot reset its spending. Catch-up means paying specific unpaid historical epochs, not borrowing seven future days. If retaining a throughput cap, apply it in addition to maturity and document its interaction with backlog. Around halving, seven old daily budgets can total 26.6M while 7× the new budget is only 13.3M; a current-budget cap can delay legitimate arrears. These are design inferences from the supplied schedule.

My ranking of the three suggested measures, for an evolving miner population:

| Rank | Measure | Benefit against a compromised distributor | Added complexity and limitation |
| --- | --- | --- | --- |
| 1 | Fixed 2-of-3 independent allocation attestors | One stolen signing key cannot authorize a payout. Directly addresses the stated threat. | Daily coordination; shared infrastructure or blindly signing one API response defeats independence. Two lost/unavailable keys stop new allocations. |
| 2 | Deployment-fixed recipient allowlist | Prevents payment to arbitrary new addresses. Simple boundary if this really is a permanently closed cohort. | Cannot stop allocating 100% to one attacker-controlled allowed account, lying about weights, or omitting honest miners. Permanently excludes new agents and replacement wallets. |
| 3 | Merkle root plus 24-hour challenge window | Makes proposed allocations inspectable and gives time to act before release, **if** rejection is enforceable. | Extra latency, data availability, dispute state, monitoring and a resolver. A timer and root alone stop no attack. |

This ranks value per complexity, not absolute strength. For a permanently fixed, trustworthy cohort, the allowlist can be excellent. For the stated contributor network I would not freeze today's approximately 370 addresses without an explicit permanent-membership requirement. Hashing the list saves storage, but adds allowlist proofs to execution.

Use a narrowly scoped immutable threshold verifier for allocations if “no owner” is literal: fixed signers and threshold, no arbitrary-call authority, setters, upgrades or bypass modules. A conventional Safe has changeable owners/threshold and modules that can bypass normal signature checks; naming a Safe as distributor does not establish immutable attestation governance. [Safe account concepts](https://docs.safe.global/advanced/smart-account-concepts). A constrained Safe is an operational alternative only if that residual signer governance is accepted and disclosed. Neither option needs ownership of the token, hook or emission schedule. Fixed signer loss is an explicit availability tradeoff; ownerless does not mean oracleless.

**A workable challenge window needs a verdict rule.** On-chain evidence can demonstrate inconsistent totals or duplicate task identifiers only if those rules and source commitments are available to the verifier. It cannot decide whether an opaque API's claimed task happened. A public “challenge” that automatically freezes funds invites denial of service; a bonded challenge still needs objective adjudication or trusted judges. A fixed independent quorum could reject/re-attest disputed roots without owning the contracts, but remains a trusted adjudicator. Define deadlines, replacement of rejected proposals, no replacement after finalization, and behavior when quorum is lost. Without such a rule, use the delay for transparency and do not claim fraud resistance.

Operationally, publish signed task snapshots with cutoff time, stable task IDs, recipient mapping and deterministic rounding. Have attestors independently reconcile evidence before signing; independent keys do not fix a compromised shared API. Permissionless execution of approved allocations, external monitoring, offline signing keys and separate funded relayers reduce operational exposure without an owner. Recipient percentage caps can bound concentration only if consistent with legitimate proportional rewards; otherwise they change the economics and are bypassable through multiple identities.

**3. Fee routing and failure isolation**

**Recommendation:** harvest fees permissionlessly in a separate transaction, forward 100% of each harvested currency to one immutable splitter, and credit the five entitlements there. Withdrawals should be independent per beneficiary/currency. A failing beneficiary should leave its entitlement unpaid and retryable without blocking anyone else. Fix rounding/dust rules; account for received funds, allocated credits and withdrawals exactly. A separate contract adds a call and deployment surface, but separates fee accounting from swap execution.

Verified mechanism: v4's `modifyLiquidity` exposes accrued fees, and `take` transfers currency within an unlocked accounting session whose deltas must settle. A zero-liquidity-delta fee harvest can preserve the position's principal. Merely owning a position does not automatically transfer fees to a hook on every swap. [PoolManager source](https://raw.githubusercontent.com/Uniswap/v4-core/main/src/PoolManager.sol). Permit this fee-only operation while structurally forbidding principal removal; “never touches liquidity again” must mean never changes its amount/range, not never harvests fees.

| Design | If a beneficiary rejects native ETH | Consequence |
| --- | --- | --- |
| Hook pushes all five shares atomically during swaps | One reverting call rolls back the whole transaction. | Beneficiary can block trading. Reentrancy and external-call gas grief also enter the swap path. |
| Hook pushes shares only on a separate harvest | Revert rolls back harvest and all payments. | Swaps can continue, but fee distribution stalls globally. |
| Hook forwards to splitter, which immediately pushes all shares | Revert propagates through forwarding unless explicitly isolated. | Moving the code alone changes nothing; same global failure. |
| Separate harvest into splitter with independent credits/withdrawals | Only the attempted withdrawal fails; its credit remains. | Other withdrawals and swaps remain available. A broken splitter can still strand all future fees, so keep it minimal. |

For a conventional UP ERC-20 transfer, the receiving contract's `receive()` function is not called; balances change in the token contract. Therefore a reverting ETH receiver does not automatically block UP transfers. A separate recipient callback such as `deposit()` would create that dependency. v4's currency library uses a native ETH call for native transfers and invokes the token's transfer for ERC-20 transfers. [ERC-20 standard](https://eips.ethereum.org/EIPS/eip-20), [v4 Currency library](https://raw.githubusercontent.com/Uniswap/v4-core/main/src/types/Currency.sol). This conclusion assumes UP has no bespoke receiver hooks, blacklist or transfer restrictions.

**Self-destruction is chain-version dependent.** Under EIP-6780, an established contract executing `SELFDESTRUCT` normally keeps code and storage; deletion remains possible when created and destroyed in the same transaction. Thus “later self-destructed” normally does not mean “empty address” under that fork. Robinhood's active fork behavior was not independently checked. [EIP-6780](https://eips.ethereum.org/EIPS/eip-6780). If a recipient genuinely has no code, an ordinary ETH send or ERC-20 transfer can succeed but the funds may be unrecoverable. A pull entitlement may instead remain permanently unclaimed. Neither outcome should block other beneficiaries. Do not promise recovery with immutable destinations; permit recipient-authorized alternate destinations only if that rule is intentionally designed before deployment.

**The currency policy is currently incomplete.** LP fees accrue in swap input currency: ETH on UP buys, UP on UP sells, under ordinary accounting. Protocol fees may also apply; split actual realized LP fees, not a presumed 1% of every trade. [v4 Pool swap accounting](https://raw.githubusercontent.com/Uniswap/v4-core/main/src/libraries/Pool.sol).

Calculation: 1,000 UP of harvested fees means 350 UP burned, 350 to miners, 240 treasury, 50 creator, 10 third party. One ETH of fees instead means 0.35 ETH, 0.35 ETH, 0.24 ETH, 0.05 ETH and 0.01 ETH. ETH cannot be passed to UP's `burn()` as if it were UP. Transferring ETH to a dead address does not reduce UP supply.

My preferred policy, if the economics require UP burns and UP miner rewards, is to segregate the two 35% ETH credits for a separately specified conversion process. Do not auto-buy UP in the swap callback. A conversion needs enforceable price/slippage bounds and a credible price reference; the same thin launch pool's instantaneous spot price is inadequate. Buying from that pool also creates new fees and fails when there is no UP inventory. Until this conversion policy is resolved, leave ETH accrued and make no claim that it was burned or paid to miners. Alternatively amend the economics explicitly to distribute ETH to miners and burn only UP-denominated fees; that is a changed promise, not an implementation detail.

Fee UP returned to the vault also needs its own budget ledger. A fixed 684M base schedule cannot both remain its only payout entitlement and guarantee distribution of extra recycled fees. Preserve the base maturity invariant and define a separate fee-funded bonus allocation, its weights, availability date and custody. Otherwise returned fees accumulate without a route to miners, or provide a loophole for early base-reserve withdrawal. Recycling existing UP is not minting additional supply.

**4. Single-sided launch and permanent range**

Verified background: a concentrated position holds one asset outside its range, becomes active on reentry, and earns swap fees only while active. Crossing a range and later crossing back reverses its inventory conversion. [Uniswap v3 whitepaper, §§2–2.1](https://app.uniswap.org/whitepaper-v3.pdf). v4 retains concentrated liquidity. [Uniswap v4 architecture](https://developers.uniswap.org/docs/protocols/v4/concepts/architecture).

**Orientation matters.** With native ETH as currency0 and UP as currency1, the protocol quotes UP/ETH, the reciprocal of the human ETH-per-UP price. An UP-only position starts above its upper protocol tick, with the range below the initial protocol price. ETH buys move that protocol price downward into the range while raising ETH/UP. Reversing the currencies or confusing those two quotations can make the launch require ETH or place liquidity on the wrong side. Address ordering and the native-zero-address convention are explicit in the core. [PoolManager](https://raw.githubusercontent.com/Uniswap/v4-core/main/src/PoolManager.sol), [Currency library](https://raw.githubusercontent.com/Uniswap/v4-core/main/src/types/Currency.sol).

For the following **calculated illustration**, define human price P in ETH/UP, bounds a < b, initial principal Q = 316M UP, with P initially below a. Ignoring integer rounding and fees, concentrated-liquidity math yields:

- L = Q / (1/√a − 1/√b).
- At P within the range, remaining UP = L(1/√P − 1/√b), and ETH principal = L(√P − √a).
- Exhausting UP requires net ETH = Q√(ab); average sale price is √(ab), not the starting price.

These equations follow from the whitepaper's translated constant-product reserve equation; a and b here are human-price bounds, not protocol tick order. No actual launch bounds were provided.

Example: a = 10⁻⁸ and b = 4×10⁻⁸ ETH/UP. Selling all 316M UP takes 6.32 ETH of net principal input, or about 6.38384 ETH gross with a 1% input fee and no protocol fee. The first 10% of inventory, 31.6M UP, costs approximately 0.33263 ETH net or 0.33599 ETH gross, ending at P ≈ 1.10803a. The first 50% costs about 2.12795 ETH gross and reaches P ≈ 1.77778a. These are illustrative economics, not proposed prices.

**First-buyer sniping — inference.** A sufficiently funded first buyer can consume much or all of the cheapest inventory in one transaction. The 1% fee is a cost, not anti-sniping protection; even a fee-only round trip costs roughly 1.99%, potentially small compared with mispricing. Priority ordering and sandwiching around buyers remain concerns even if the chain's transaction visibility differs from Ethereum's public mempool. Per-wallet limits are Sybilable. If fair initial access is essential, use a separately designed batch auction or time-based launch mechanism, which changes the present static launch specification. Otherwise disclose that transaction order determines access to early prices.

**Range fully consumed — inference.** Above b in human-price terms, the position's principal is all ETH, apart from rounding dust, with no UP left to sell. Its liquidity amount has not vanished and remains locked, but further buyers cannot obtain additional UP from this sole range. Exact-input execution may be partial, and router minimum-output/exact-output checks may revert; do not assume all submitted input is traded. A reverse UP sale can reenter the range and restore inventory. Exhaustion is therefore reversible, not a permanent one-way token sale.

**Price back below the range — inference.** Sells through the whole range convert principal back to all UP and exhaust its ETH buying capacity. Below a, miners cannot use this range to sell additional UP for ETH. A locked position does not guarantee an ETH redemption floor. Fees already separated from principal are not a reserve supporting that floor. At launch there is likewise no ETH bid until buyers contribute ETH.

**Out-of-range fees and price gaps.** No new LP swap fees accrue to this position while inactive; previously earned fees remain harvestable, and fee growth resumes on reentry. An empty interval can be traversed by the swap algorithm without economic depth, subject to limits and gas; crossing it is not a purchase of inventory at the displayed empty-range price. The core's loop advances toward ticks/price limits and credits fee growth only with positive active liquidity. [Pool swap implementation](https://raw.githubusercontent.com/Uniswap/v4-core/main/src/libraries/Pool.sol). Inference: spot prices in these gaps are poor valuation signals, and an external market price does not update this pool until a transaction changes its state.

**Additional launch constraints — recommendations.** Initialize and seed atomically through a validated launch path; otherwise someone can initialize the intended pool at an unwanted price. Bind the hook to the exact PoolKey and allowed initialization parameters. Verify the currency order, decimals, tick spacing, tick alignment, rounded funding amount and actual first tradable price. The claimed “sole LP” condition also requires an enforced liquidity-addition policy: owning the initial position does not prevent others from adding to a permissionless pool, and cannot prevent creation of competing pools. Principal immobility requires absence of any removal/arbitrary-call/approval escape path; hook ownership alone proves nothing. Locking one range forever also precludes recentering or migration if markets move or infrastructure changes.

**5. What I would refuse to ship**

1. **An externally controlled distributor able to withdraw to itself or an arbitrary address**, particularly with only the stated 7× cap. Replace this with schedule-constrained, allocation-bound direct payouts and independent threshold attestation.
2. **A claim that a delayed Merkle root proves task truth**, without public evidence and an enforceable rejection process. Honest labeling of the off-chain oracle is necessary even with multisig approval.
3. **Beneficiary-dependent transfers in the swap path**, or an immutable fee pipeline without a defined ETH/burn policy and recycled-fee payout policy. These are availability and economic-specification defects.
4. **Promises of permanent tradability, continuous fee income, or fair launch access from a locked single range.** Either change the mechanism or state and accept the finite inventory, reversible conversion and ordering risks.
5. **The exact lifetime-sum assertion as written.** Let N = 3,800,000×10¹⁸. For integer right shifts, Σₖ≥0(N >> k) = 2N − popcount(N). Here popcount(N) = 28, so the 90-day-band schedule totals **683,999,999,999,999,999,999,997,480 base units**, which is **2,520 base units (2.52×10⁻¹⁵ UP) short of 684M UP**. The economic difference is negligible; the specification is not exact. Correct the statement or assign the dust deterministically. The last nonzero band is k = 81, and the budget becomes zero at epoch 7,380 (assuming epoch zero starts the schedule). Do not round in whole-token units by accident.

The proposed 1B initial allocation and fixed fee bps are design inputs, not evidence that code enforces them. All 1B must be created or assigned initially to seed both contracts; “no premine” should be defined as no discretionary/team initial allocation if that is what is meant. The 5% creator share and 1% third-party share are ongoing fee allocations and should remain plainly disclosed.

**Unanswered questions and limits before implementation.** What are the exact launch bounds, tick spacing, PoolKey, epoch origin and cutoff semantics? Does “release” already enforce cumulative maturity, and how are zero-task days, rounding, missed days and unclaimed allocations handled? Is membership open-ended? Who independently validates API records, and what is the immutable failure/recovery policy for unavailable signers? Which currency should miners receive from fee recycling? What enforceable conversion price source exists? Can fee recipients accept and recover both currencies? What are Robinhood's current transaction limits, DA pricing and EVM fork rules? Is “sole LP” intended as an enforceable restriction or only a launch condition?

No live gas quote, actual UP token address, deployment bytecode, proposed contracts, API schema or mainnet simulation was available in this review. The unavailable documentation URL for v3 was replaced with the successfully retrieved official whitepaper; no conclusion relies on failed retrievals. The research supports these design recommendations, not a security verdict.

**Local checks performed.** Independently recomputed the integer schedule, gas-cost sensitivity, calldata sizes and illustrative range math using Python's standard library; checked required artifact presence, UTF-8 readability, Markdown links and key report topics. No contracts were produced, no dependencies were installed, and no runtime/security tests were claimed. These checks are author checks, not independent review.
