Skip to content

feat(hedera): add initial @x402/hedera package#1360

Open
piotrswierzy wants to merge 12 commits intox402-foundation:mainfrom
blockydevs:feat/hedera
Open

feat(hedera): add initial @x402/hedera package#1360
piotrswierzy wants to merge 12 commits intox402-foundation:mainfrom
blockydevs:feat/hedera

Conversation

@piotrswierzy
Copy link
Copy Markdown
Contributor

@piotrswierzy piotrswierzy commented Feb 26, 2026

add initial @x402/hedera package with exact payment scheme support

  • Introduced the @x402/hedera package implementing the x402 v2 exact payment scheme for Hedera.
  • Added client, server, and facilitator implementations along with necessary utilities and types.
  • Included configuration files for ESLint, Prettier, and Vitest.
  • Created documentation in README and CHANGELOG for package usage and features.
  • Established a .prettierignore file to exclude specific directories and file types from formatting checks.

Description

Tests

Checklist

  • I have formatted and linted my code
  • All new and existing tests pass
  • My commits are signed (required for merge) -- you may need to rebase if you initially pushed unsigned commits
  • I added a changelog fragment for user-facing changes (docs-only changes can skip)

@cb-heimdall
Copy link
Copy Markdown

cb-heimdall commented Feb 26, 2026

🟡 Heimdall Review Status

Requirement Status More Info
Reviews 🟡 0/1
Denominator calculation
Show calculation
1 if user is bot 0
1 if user is external 0
2 if repo is sensitive 0
From .codeflow.yml 1
Additional review requirements
Show calculation
Max 0
0
From CODEOWNERS 0
Global minimum 0
Max 1
1
1 if commit is unverified 1
Sum 2

@vercel
Copy link
Copy Markdown

vercel bot commented Feb 26, 2026

@piotrswierzy is attempting to deploy a commit to the Coinbase Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions github-actions bot added typescript sdk Changes to core v2 packages labels Feb 26, 2026
@piotrswierzy piotrswierzy changed the title feat(hedera): add initial @x402/hedera package with exact payment sch… feat(hedera): add initial @x402/hedera package Feb 26, 2026
@github-actions github-actions bot added the examples Changes to examples label Mar 3, 2026
@cb-heimdall
Copy link
Copy Markdown

Review Error for skurzyp-blockydevs @ 2026-03-12 14:43:04 UTC
User failed mfa authentication, either user does not exist or public email is not set on your github profile. \ see go/mfa-help

if (requirementsValidation !== null) {
return requirementsValidation;
}
const feePayer = requirements.extra.feePayer as string;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I don't like this casting. Maybe we should extend PaymentRequirements with own type and guards to be sure that extra.feePayer exist?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

SVM does it the same way

@cb-heimdall
Copy link
Copy Markdown

Review Error for kierzniak @ 2026-03-16 11:45:39 UTC
User failed mfa authentication, either user does not exist or public email is not set on your github profile. \ see go/mfa-help

@piotrswierzy piotrswierzy marked this pull request as ready for review March 18, 2026 13:18
@phdargen phdargen self-assigned this Mar 19, 2026
@phdargen
Copy link
Copy Markdown
Contributor

Thanks a lot for the contribution @piotrswierzy, I'll begin reviewing shortly.

A few initial comments:

@piotrswierzy
Copy link
Copy Markdown
Contributor Author

@phdargen
Let me know if there is anything else I can do, to support you in the review process.


Example client demonstrating how to use `@x402/fetch` to make HTTP requests to endpoints protected by the x402 payment protocol.

```typescript
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

please revert changes in this file, seems unrelated


Example client demonstrating how to use `@x402/axios` to make HTTP requests to endpoints protected by the x402 payment protocol.

```typescript
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

please revert

@@ -0,0 +1,358 @@
import { beforeEach, describe, expect, it } from "vitest";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

In the TS package root package.json please add hedera integration test here:
"test:integration": "pnpm --filter @x402/core --filter @x402/evm --filter @x402/svm --filter @x402/aptos --filter @x402/stellar test:integration",

Comment on lines 53 to 54
price: string | { amount: string; asset: string; extra?: Record<string, unknown> };
network: `${string}:${string}`;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
price: string | { amount: string; asset: string; extra?: Record<string, unknown> };
network: `${string}:${string}`;
price: Price;
network: Network;

with import type { Network, Price } from "@x402/core/types";

@@ -1,4 +1,5 @@
EVM_ADDRESS=
SVM_ADDRESS=
HEDERA_ADDRESS=
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Took me a while to get the examples/e2e tests running, they fail when using an address like
HEDERA_ADDRESS=0x3f376c1e06b5495f2a015975671cc53f61e8e351

This address was accepted by the faucet (https://portal.hedera.com/faucet), so seems to be a valid address. I created it with PrivateKey.generateECDSA() from @hiero-ledger/sdk

I then had claude write me a script to fetch the accountId from the API
https://testnet.mirrornode.hedera.com/api/v1/accounts/ (any easier, more straightforward way to setup the accounts?)

With this the examples/e2e tests ran successfully
HEDERA_ADDRESS=0.0.8450511

Is HEDERA_ADDRESS supposed to accept both formats? Or just account ids? Then env vars should be renamed to HEDERA_ACCOUNT_ID

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please also put a link to the faucet in the appropriate READMEs

@phdargen
Copy link
Copy Markdown
Contributor

phdargen commented Apr 1, 2026

There have been some changes to the e2e route structure, see https://github.com/coinbase/x402/pull/1779.
Could you please rebase against main and align your e2e tests?

Please also add e2e tests for the remaining server packages hono/next/fastify

}

tx.setTransactionId(TransactionId.generate(AccountId.fromString(feePayer)));
tx.setTransactionMemo(`x402:${Date.now().toString(36)}`);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

A transaction memo isnt mentioned in the specs, is this needed? Does it incur any additional tx costs? Should there be any constraints enforced by the facilitator on memo format and size?

payer: "",
};
}
const inspectedValidation = this.validateInspectedTransaction(inspected);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think we should check the client set txFee here and reject if above a reasonable threshold, similar to SVM. Otherwise malicious client could set it arbitrarily large and grief the facilitator

if (payToValidation !== null) {
return payToValidation;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Could we add tx simulation here or at least a balance check to protect the server from doing work for invalid requests?

* @param transactionId - Hedera transaction id
* @returns Failed verify response or null
*/
private async validateReplay(transactionId: string): Promise<VerifyResponse | null> {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Not sure about this replay protection mechanism.

Could you please elaborate why this is needed in the first place? Is this security critical or an optimization?

If a client sends the exact same tx multiple times, and the tx hasn't reached a confirmed state onchain yet, would settle return success for all even though only one actually settles and client pays only once?

If that's the case, could we align the implementation with the in-memory cache introduced for SVM in
https://github.com/coinbase/x402/pull/1468?

If a client sends a request and tx confirms onchain, then sends a request with exact same payload again, would settle fail? If we add simulation to verify would it fail for the duplicate tx? If so, do we still need the replay mechanism?

* @param network - Hedera network
* @returns AssetAmount in configured default HTS token
*/
private defaultMoneyConversion(amount: number, network: Network): AssetAmount {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

could we define any default stablecoin for the moneyParser here as for all the other networks?

@phdargen
Copy link
Copy Markdown
Contributor

phdargen commented Apr 1, 2026

Hi @piotrswierzy, nice work! Made a first pass through the code and manually tested the examples/e2e tests, please find a few comments/suggestions above

…eme support- Introduced the @x402/hedera package implementing the x402 v2 exact payment scheme for Hedera.- Added client, server, and facilitator implementations along with necessary utilities and types.- Included configuration files for ESLint, Prettier, and Vitest.- Created documentation in README and CHANGELOG for package usage and features.- Established a .prettierignore file to exclude specific directories and file types from formatting checks.

Signed-off-by: Piotr Swierzy <piotr.swierzy@blockydevs.com>
- Introduced a new .env.test file for configuring ECDSA keys required for live integration tests.
- Updated README to include instructions for setting up the environment and running integration tests.
- Modified the createClientHederaSigner function to accept PrivateKey objects instead of strings for better type safety.
- Enhanced error handling in ExactHederaScheme to manage unsupported network values and unexpected HBAR transfers.

Signed-off-by: Piotr Swierzy <piotr.swierzy@blockydevs.com>
…d clean up unused dependencies

Signed-off-by: Piotr Swierzy <piotr.swierzy@blockydevs.com>
…ilitators- Added support for Hedera payments in advanced clients (axios, fetch, advanced).- Updated environment variables to include HEDERA_ACCOUNT_ID, HEDERA_PRIVATE_KEY, and HEDERA_NETWORK.- Implemented Hedera signing and transaction handling in all relevant files.- Enhanced README documentation to reflect new Hedera configurations and requirements.This update allows users to interact with the Hedera network alongside existing EVM and SVM functionalities.

Signed-off-by: Piotr Swierzy <piotr.swierzy@blockydevs.com>
…ross all relevant files

- Updated imports in various client and facilitator files to use @hiero-ledger/sdk instead of @hashgraph/sdk.
- Adjusted README documentation to reflect the new SDK usage.
- Removed obsolete .env.test file related to Hedera integration tests.
- Updated pnpm-lock.yaml to reflect the new dependency version for @hiero-ledger/sdk.

This change enhances compatibility and aligns with the latest SDK updates.

Signed-off-by: Piotr Swierzy <piotr.swierzy@blockydevs.com>
…ted pnpm-lock.yaml to reflect the new versioning for axios and @hiero-ledger/sdk.- Replaced instances of @hashgraph/sdk with @hiero-ledger/sdk in package.json files across clients and facilitators.- Enhanced network handling in the Hedera signer and utility functions to assert supported networks.- Refactored code to improve clarity and maintainability, including the removal of unused functions.This update ensures better compatibility with the latest SDK and improves the overall robustness of the Hedera integration.

Signed-off-by: Piotr Swierzy <piotr.swierzy@blockydevs.com>
…essary line breaks in imports within , , and .- Added a newline at the end of to comply with formatting standards.

Signed-off-by: Piotr Swierzy <piotr.swierzy@blockydevs.com>
…f to comply with formatting standards.

Signed-off-by: Piotr Swierzy <piotr.swierzy@blockydevs.com>
…age- Removed unnecessary imports from utils.ts.- Updated parameter naming in createPaymentPayload method for clarity.Signed-off-by: Piotr Swierzy <piotr.swierzy@blockydevs.com>

Signed-off-by: Piotr Swierzy <piotr.swierzy@blockydevs.com>
…payment capabilities across various components including clients, facilitators, and servers.- Updated environment variables and configurations to include Hedera account and private key.- Enhanced README and documentation to reflect new Hedera protocol support.- Modified test configurations to include Hedera endpoints and payment requirements.This update expands the multi-chain support of the application, allowing for seamless integration with the Hedera network.

Signed-off-by: Piotr Swierzy <piotr.swierzy@blockydevs.com>
      Expand Hedera e2e test coverage to Hono and Next.js servers, aligning
      with the new /exact/{chain} route naming convention from x402-foundation#1779.

      - Hono: add ExactHederaScheme import, env vars, registration, guard,
        middleware config, route handler, and test.config.json endpoint
      - Next.js: add proxy route (/api/exact/hedera), withX402 wrapper route,
        scheme registration in proxy.ts, and test.config.json endpoints
      - Update package.json dependencies for both servers
      - Update .env-local templates with HEDERA_PAYEE_ADDRESS

Signed-off-by: Piotr Swierzy <piotr.swierzy@blockydevs.com>
   - Revert unrelated README changes in axios/fetch client examples
   - Add @x402/hedera to root test:integration filter
   - Use imported Network/Price types in server example instead of inline
   - Rename HEDERA_ADDRESS to HEDERA_ACCOUNT_ID for clarity, add faucet link
   - Add USDC as default stablecoin for Hedera money conversion
     (testnet: 0.0.429274, mainnet: 0.0.456858, 6 decimals)

Signed-off-by: Piotr Swierzy <piotr.swierzy@blockydevs.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

examples Changes to examples sdk Changes to core v2 packages typescript

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants