Skip to content

Add Hedera session intent#258

Open
tomrowbo wants to merge 5 commits into
tempoxyz:mainfrom
tomrowbo:add-hedera-session
Open

Add Hedera session intent#258
tomrowbo wants to merge 5 commits into
tempoxyz:mainfrom
tomrowbo:add-hedera-session

Conversation

@tomrowbo

Copy link
Copy Markdown
Contributor

Summary

Streaming payment channel intent for Hedera (draft-hedera-session-00). ERC-20 escrow with EIP-712 cumulative vouchers — N requests = 2 on-chain transactions.

Split from #251 (charge intent) per reviewer request.

Highlights

  • HederaStreamChannel.sol: ERC-20 payment channel escrow with HTS token association (associateSelf via precompile at 0x167)
  • EIP-712 vouchers: Voucher(bytes32 channelId, uint128 cumulativeAmount), domain "Hedera Stream Channel"
  • Full lifecycle: open, voucher, topUp, close, requestClose, withdraw
  • SSE transport: payment-need-voucher + payment-receipt events for metered streaming
  • 15-minute close grace period

Deployed contracts

Network Address Chain ID
Testnet 0x8Aaf...daE 296
Mainnet 0x8Aaf...daE 295

Both fully verified on Hashscan via Sourcify. USDC: Circle native (0.0.456858 mainnet, 0.0.5449 testnet).

Reference implementation

Checklist

  • Follows STYLE.md conventions
  • Uses method template structure
  • Security considerations: replay protection, front-running, close grace period
  • Depends on charge intent (Add Hedera charge intent #251) for shared Attribution memo format

tomrowbo and others added 4 commits April 28, 2026 19:19
First native Machine Payments Protocol method for Hedera.

Charge intent (draft-hedera-charge-00):
- Native Hedera TransferTransaction with Attribution memo
- Push mode (type="hash") + pull mode (type="transaction")
- Challenge-bound replay protection (same 32-byte memo as Tempo)
- Verification via Mirror Node REST API
- Splits (atomic multi-recipient, up to 9)

Session intent (draft-hedera-session-00):
- HederaStreamChannel.sol escrow (ERC-20 payment channels)
- EIP-712 cumulative voucher signatures
- Open, voucher, topUp, close, requestClose, withdraw
- SSE transport for metered streaming (LLM token billing)
- 15-minute close grace period

Reference implementation: https://github.com/tomrowbo/mppx-hedera
npm: mppx-hedera@0.2.1
Deployed contracts (both Sourcify-verified):
  Testnet: 0x401b6dc30221823361E4876f5C502e37249D84C3 (296)
  Mainnet: 0x401b6dc30221823361E4876f5C502e37249D84C3 (295)
Renamed subsection "Encoding" to "Memo Encoding" with explicit
anchor {#memo-encoding} to avoid collision with top-level
"Encoding Conventions" section {#encoding}.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@tomrowbo tomrowbo mentioned this pull request May 12, 2026
6 tasks
@tomrowbo tomrowbo force-pushed the add-hedera-session branch from 209ca89 to 7d9f033 Compare May 14, 2026 10:22

@brendanjryan brendanjryan left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes LGTM! Thank you 🙇

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@chopmob-cloud

Copy link
Copy Markdown

Operational notes from running multi-chain MPP-adjacent payment flows on Hedera in production (AlgoVoi gateway, all 7 mainnets + ARC testnet). The streaming-channel approach in this PR composes cleanly with the patterns we operate today, and there's one specific Hedera trade-off worth surfacing.

What we operate on Hedera today

AlgoVoi runs three Hedera flows in production:

  1. One-shot HBAR / USDC transfers — direct HTS-token send, single transaction
  2. Recurring authorities (Recurr Tier 2 pull-executor pattern) — customer signs an HTS Approve allowance once via Reown WalletConnect, AlgoVoi pulls on cycle until the allowance is exhausted or revoked
  3. MPP subscription intent (parallel to Subscriptions: Intent + Stripe and Tempo Implementations #230) — customer signs each renewal cycle separately, allowance-bounded per period

So we have the allowance-based and the per-cycle-signed patterns in production already. The streaming-channel approach in this PR sits naturally between them: one EIP-712 voucher per request, escrow-bound, with implicit settlement at channel close. Three distinct lifecycles for three distinct merchant needs.

On HederaStreamChannel.sol design

Reads clean against what we'd want operationally. Two notes from running adjacent Hedera flows in production:

associateSelf via precompile at 0x167 — strong yes. Per memory we hit a real merchant-onboarding silent-failure where customers tried to receive USDC without the token-association step having completed; the receipt-side check passed but the actual transfer reverted. Folding token association into the channel-open flow eliminates that whole class of bug. Worth noting in the spec text non-normatively that this is the recommended pattern; AP2/x402 onboarding flows elsewhere are still discovering this gap.

15-minute close grace period — sensible. Worth noting for implementors that the choice of grace window interacts with the consensus timestamp finality on Hedera. We use 5-second buffers for short-cycle subscription renewals and 30-second buffers for high-value one-shot transfers. 15 minutes for channel close is in the right band for streaming workloads where the receiver may want to batch settle, but the same window for sub-second streaming would create a UX expectation mismatch. The spec text correctly leaves this as the implementor's choice; just flagging that the trade-off is non-obvious for new implementors.

Composition with subscription intent (#230) and recurring authorities

The three patterns map cleanly onto the spec-evolution we're seeing across MPP:

Pattern Lifecycle When to use
Streaming channel (this PR) open → N vouchers → close Per-request metered billing; high-frequency micropayments; agent-bandwidth-as-a-service
Subscription intent (#230) activate → cycle → renew per period Fixed-amount-per-period; subscription services; SaaS billing
Recurring authority (Recurr Tier 2 pattern) sign allowance → pull on cycle until exhausted Standing-order pattern; allowance-bounded utility billing

These don't conflict; they cover different operational needs. A merchant offering an API service could legitimately use all three: streaming for usage-priced inference calls, subscription for the base tier, recurring authority for any add-on capacity prepaid in advance. The cross-method consistency is in the receipt envelope and the JCS canonicalisation rule — same shape regardless of which lifecycle generated the charge.

On EIP-712 voucher domain "Hedera Stream Channel"

Worth checking whether the domain string is rail-portable or Hedera-specific. We hit a real cross-chain pain point on the EIP-712 side: a domain string like "Hedera Stream Channel" is fine for Hedera-only deployments, but a multi-chain merchant offering streaming on Hedera AND Base would need two distinct domain strings to prevent cross-chain replay. Worth a spec note that domain MUST be chain-namespaced (perhaps "MPP Stream Channel - {chainId}" or similar) so implementors don't accidentally make vouchers replayable across chains they didn't intend.

Reference implementation alignment

Happy to coordinate with mppx-hedera on the AlgoVoi-side wallet integration — AlgoVoi's chrome extension wallet has Hedera WC support via Reown (post-2026-05-15 JWT-relay fix), so streaming-channel vouchers could be wallet-signed there too. If your reference implementation needs a chrome-extension-side wallet to test against, AlgoVoi v1.0.3 (released today; in chrome web store review) is ready.

PR reads ready for review from our side; happy to engage on the chain-namespaced domain question or the activation atomicity if useful.

@chopmob-cloud

Copy link
Copy Markdown

+1 on splitting session from charge. The cumulative-voucher pattern fits Hedera's HTS allowance economics well. A few operational notes from running Hedera in production (AlgoVoi gateway, HTS-Approve recurring authorities plus HashPack/Reown WalletConnect for end-user wallets):

  • Token association onboarding: silent-failure risk if the receiving account hasn't associated the HTS token before the first transfer. Worth having intent activation check association status (mirror-node accounts/{id}/tokens) and surface a typed error before voucher signing rather than after the first capture attempt.
  • Pubkey decoding: mirror-node returns ED25519 and ECDSA secp256k1 keys in different shapes. Verifiers that only handle ED25519 (the common default) silently reject ECDSA-keyed accounts. Our wallet_auth handles both via the key-type discriminator. Worth a note in the verifier obligation list so downstream verifier implementors don't trip on this.
  • WalletConnect path: Reown's HederaProvider works for both browser and mobile signing; CSP allowlist needs the mirror-node endpoints (we hit this during portal deploy and it surfaced as a silent connect-failure rather than a typed error).
  • Mirror-node eventual consistency: read paths can lag the consensus node by 2-5 seconds at moderate load. Voucher freshness checks should tolerate this or fall back to the consensus node directly.

Happy to dig into any of these if useful for the spec text.

@tomrowbo

Copy link
Copy Markdown
Contributor Author

Thanks for the detailed operational notes — really valuable context from production.

On the EIP-712 domain: cross-chain replay is already prevented — the domain separator includes both chainId and verifyingContract (the escrow address), so a voucher signed for Hedera testnet (296) can't be replayed on mainnet (295) or any other chain. The domain string itself doesn't need to be chain-namespaced since the EIP-712 spec handles this at the digest level. Happy to add a non-normative note clarifying this.

The token association point is a good one — associateSelf in the contract handles this for the escrow, and the open flow in the reference implementation verifies association before deposit. Worth calling out more explicitly in the spec.

Would be great to test against the AlgoVoi wallet — will reach out.

@chopmob-cloud

Copy link
Copy Markdown

Good catch on the EIP-712 point -- you are right that chainId + verifyingContract in the domain separator is doing the real work at the digest level. The note was more about auditability in production logs than any actual replay gap, so a non-normative clarifying sentence would cover it well.

Glad the association callout is useful. Worth surfacing early for any implementor who hits the silent failure path before the spec makes it explicit.

Looking forward to the wallet test -- happy to coordinate whenever works.

@tomrowbo

Copy link
Copy Markdown
Contributor Author

Add my telegram @tomrowbo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants