Skip to content

Add Aptos payment mechanism#966

Open
jtang17 wants to merge 10 commits intocoinbase:mainfrom
aptos-labs:aptos-mechanism
Open

Add Aptos payment mechanism#966
jtang17 wants to merge 10 commits intocoinbase:mainfrom
aptos-labs:aptos-mechanism

Conversation

@jtang17
Copy link
Contributor

@jtang17 jtang17 commented Jan 15, 2026

Description

  • Add @x402/aptos package with exact scheme support
  • Implement SchemeNetworkClient, SchemeNetworkFacilitator, SchemeNetworkServer
  • Support sponsored transactions via extra.sponsored: true
  • Use 0x1::primary_fungible_store::transfer for fungible asset transfers
  • Add BCS serialization utilities for transaction encoding
  • Include facilitator signer with fee payer support
  • Add unit tests (23 passing) for types, constants, and exports
  • Update spec to use sponsored: true instead of gasStation URL

Tests

Added tests for the aptos mechanisms package

For TypeScript: Run cd typescript/packages/mechanisms/aptos && pnpm test

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

@cb-heimdall
Copy link

cb-heimdall commented Jan 15, 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 0
Sum 1

@vercel
Copy link

vercel bot commented Jan 15, 2026

@jtang17 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 examples Changes to examples labels Jan 15, 2026
@github-actions github-actions bot added go and removed go labels Jan 21, 2026
@phdargen phdargen self-assigned this Jan 25, 2026
@phdargen
Copy link
Contributor

phdargen commented Jan 26, 2026

Cross-checking the verify implementation with the specs:

Steps to verify a payment for the `exact` scheme:
1. **Extract requirements**: Use `payload.accepted` to get the payment requirements being fulfilled.
2. Verify `x402Version` is `2`.
3. Verify the network matches the agreed upon chain (CAIP-2 format: `aptos:1` or `aptos:2`).
4. Deserialize the BCS-encoded transaction and verify the signature is valid.
5. Verify the transaction sender has sufficient balance of the `asset` to cover the required amount.
6. Verify the transaction contains a fungible asset transfer operation (e.g., `0x1::primary_fungible_store::transfer` or `0x1::fungible_asset::transfer`).
7. Verify the transfer is for the correct asset (matching `requirements.asset`).
8. Verify the transfer amount matches `requirements.amount`.
9. Verify the transfer recipient matches `requirements.payTo`.
10. Simulate the transaction using the Aptos REST API to ensure it would succeed and has not already been executed/committed to the chain.
11. Verify the transaction has not expired (check sequence number and expiration timestamp). Note: A buffer time should be considered to account for network propagation delays and processing time.

  • 2: Verify x402Version is 2 check is missing
  • 5: Balance check is missing. I suppose simulation would fail, but checking beforehand provides clearer error messages
  • 6: specs mentions two valid functions 0x1::primary_fungible_store::transfer or 0x1::fungible_asset::transfer, implementation only accepts the former
  • 11: Not checked

SVM has an additional security check to prevent the facilitator from signing away their own tokens, please review if this would also be needed in your case

// Verify that the facilitator's signers are not transferring their own funds
// SECURITY: Prevent facilitator from signing away their own tokens
const authorityAddress = parsedTransfer.accounts.authority.address.toString();
if (signerAddresses.includes(authorityAddress)) {
return {
isValid: false,
invalidReason: "invalid_exact_svm_payload_transaction_fee_payer_transferring_funds",
payer,
};
}

@phdargen
Copy link
Contributor

It would be great if you could add some integration tests as well, see eg https://github.com/coinbase/x402/blob/main/typescript/packages/mechanisms/evm/test/integrations/exact-evm.test.ts

@phdargen
Copy link
Contributor

Thanks a lot for the contribution @jtang17, this looks great!

I highlighted a few places above, where I think the implementation could be even more aligned with the existing evm/svm mechanisms. The verify implementation might also need some more hardening.

I would like to run some tests myself but I could't figure out how to get wAPT on testnet, could you please advice? Got at least some APT for the facilitator

@github-actions github-actions bot added the specs Spec changes or additions label Jan 27, 2026
@jtang17
Copy link
Contributor Author

jtang17 commented Jan 27, 2026

Thanks a lot for the contribution @jtang17, this looks great!

I highlighted a few places above, where I think the implementation could be even more aligned with the existing evm/svm mechanisms. The verify implementation might also need some more hardening.

I would like to run some tests myself but I could't figure out how to get wAPT on testnet, could you please advice? Got at least some APT for the facilitator

Thanks for the feedback. I've addressed the feedback and made the mechanism more consistent - I did also end up updating the v2 scheme for Aptos as part of this.

You can get testnet APT either https://aptos.dev/network/faucet or through an account on https://geomi.dev (https://geomi.dev/manage/faucet) and testnet USDC here: https://faucet.circle.com/

@jtang17 jtang17 force-pushed the aptos-mechanism branch 3 times, most recently from 2f38a3b to 15e1ebe Compare January 27, 2026 19:59
e2e/test.ts Outdated
Copy link
Contributor

Choose a reason for hiding this comment

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

Please add log( APTOS: ${networks.aptos.name} (${networks.aptos.caip2})); here

@phdargen
Copy link
Contributor

phdargen commented Jan 29, 2026

Thanks a lot for the quick update @jtang17, the changes look good and I ran the integration and e2e tests successfully!

Concerning the integration tests could you please add aptos here:
https://github.com/coinbase/x402/blob/main/typescript/package.json#L24C1-L25C1

Concerning the e2e tests, could you please complete them by adding aptos to hono/next servers and axios client?
Also please add aptos env vars to e2e/clients/fetch/.env-local etc

- **Sponsored Transactions**: Facilitators can pay gas fees on behalf of clients
- **Fungible Asset Transfers**: Uses Aptos's native `primary_fungible_store::transfer`
- **Network Support**: Mainnet (`aptos:1`) and Testnet (`aptos:2`)

Copy link
Contributor

Choose a reason for hiding this comment

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

Suggest to add link to faucets here

Comment on lines +184 to +193
const isPrimaryFungibleStore =
AccountAddress.ONE.equals(moduleAddress) &&
moduleName === "primary_fungible_store" &&
functionName === "transfer";

const isFungibleAsset =
AccountAddress.ONE.equals(moduleAddress) &&
moduleName === "fungible_asset" &&
functionName === "transfer";

Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry I am not that familiar with aptos, could you elaborate a bit whats the difference between these functions and why the implementation picks one over the other?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added a note about when primary_fungible_store::transfer would be used vs fungible_asset::transfer

@phdargen
Copy link
Contributor

phdargen commented Feb 3, 2026

I see you made some changes @jtang17, please ping me when its ready to review again

There seem to be some merge conflicts that still need to be resolved and changes in the go package that should be reverted

@jtang17
Copy link
Contributor Author

jtang17 commented Feb 3, 2026

I see you made some changes @jtang17, please ping me when its ready to review again

There seem to be some merge conflicts that still need to be resolved and changes in the go package that should be reverted

@phdargen - just rebased the dependency update and reverted go changes - PR should be ready for another review

@phdargen
Copy link
Contributor

phdargen commented Feb 3, 2026

Hey @jtang17, the go changes are still there and the workflow tests fail

import { registerExactEvmScheme } from "@x402/evm/exact/client";
import { registerExactSvmScheme } from "@x402/svm/exact/client";
import { registerExactAptosScheme } from "@x402/aptos/exact/client";
import { Account, Ed25519PrivateKey, PrivateKey, PrivateKeyVariants } from "@x402/aptos";
Copy link
Contributor

Choose a reason for hiding this comment

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

Please fix import

Suggested change
import { Account, Ed25519PrivateKey, PrivateKey, PrivateKeyVariants } from "@x402/aptos";
import { Account, Ed25519PrivateKey, PrivateKey, PrivateKeyVariants } from "@aptos-labs/ts-sdk";

and add "@aptos-labs/ts-sdk" to package.json

@phdargen
Copy link
Contributor

phdargen commented Feb 3, 2026

Please configure the test.config.json files for all servers/clients e2e tests and make all Aptos env vars optional in index.ts and test.config.json

@phdargen
Copy link
Contributor

phdargen commented Feb 3, 2026

Please make sure all integration tests pass, currently 3/9 fail

@phdargen phdargen mentioned this pull request Feb 3, 2026
4 tasks
@github-actions github-actions bot removed the go label Feb 3, 2026
@vercel
Copy link

vercel bot commented Feb 4, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
x402 Ready Ready Preview, Comment Feb 4, 2026 1:09am

Request Review

@phdargen
Copy link
Contributor

phdargen commented Feb 4, 2026

Hi @jtang17, could you please also add a publishing workflow for the new x402/aptos package following the evm reference here:
https://github.com/coinbase/x402/blob/main/.github/workflows/publish_npm_scoped_x402_evm.yml

Comment on lines 91 to 115
"/api/protected-aptos-proxy": {
accepts: {
payTo: APTOS_PAYEE_ADDRESS || "0x0",
scheme: "exact",
price: "$0.001",
network: APTOS_NETWORK,
},
extensions: {
...declareDiscoveryExtension({
output: {
example: {
message: "Protected endpoint accessed successfully",
timestamp: "2024-01-01T00:00:00Z",
},
schema: {
properties: {
message: { type: "string" },
timestamp: { type: "string" },
},
required: ["message", "timestamp"],
},
},
}),
},
},
Copy link
Contributor

Choose a reason for hiding this comment

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

Needs to be conditional here or e2e tests fail at runtime with RouteConfigurationError when no aptos env vars set. Same in express and hono

Suggested change
"/api/protected-aptos-proxy": {
accepts: {
payTo: APTOS_PAYEE_ADDRESS || "0x0",
scheme: "exact",
price: "$0.001",
network: APTOS_NETWORK,
},
extensions: {
...declareDiscoveryExtension({
output: {
example: {
message: "Protected endpoint accessed successfully",
timestamp: "2024-01-01T00:00:00Z",
},
schema: {
properties: {
message: { type: "string" },
timestamp: { type: "string" },
},
required: ["message", "timestamp"],
},
},
}),
},
},
...(APTOS_PAYEE_ADDRESS ? {
"/api/protected-aptos-proxy": {
accepts: {
payTo: APTOS_PAYEE_ADDRESS,
scheme: "exact",
price: "$0.001",
network: APTOS_NETWORK,
},
extensions: {
...declareDiscoveryExtension({
output: {
example: {
message: "Protected endpoint accessed successfully",
timestamp: "2024-01-01T00:00:00Z",
},
schema: {
properties: {
message: { type: "string" },
timestamp: { type: "string" },
},
required: ["message", "timestamp"],
},
},
}),
},
},
} : {}),

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated the hono, express, and next e2e to set these conditionally.

matcher: [
"/api/protected-proxy",
"/api/protected-svm-proxy",
...(APTOS_PAYEE_ADDRESS ? ["/api/protected-aptos-proxy"] : []),
Copy link
Contributor

Choose a reason for hiding this comment

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

This fails with

Next.js can't recognize the exported `config` field in route. `matcher` needs to be a static string or array of static strings or array of static objects.
120 | // Configure which paths the middleware should run on
121 | // Aptos path is only included if APTOS_PAYEE_ADDRESS is configured
> 122 | export const config = {
| ^^^^^^
123 | matcher: [
124 | "/api/protected-proxy",
125 | "/api/protected-svm-proxy",

I think here the route can be added unconditionally, please test

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated - it can be.

@github-actions github-actions bot added the ci label Feb 4, 2026
@jtang17
Copy link
Contributor Author

jtang17 commented Feb 4, 2026

@phdargen workflow has been added for the aptos package - e2e tests seem to be passing though with some bazaar discovery issues when you do not run the tests with all options enabled (I think unrelated to these changes)

@jtang17
Copy link
Contributor Author

jtang17 commented Feb 11, 2026

@phdargen - are there any remaining changes needed for this PR?

@erikreppel-cb
Copy link
Contributor

@jtang17 apologies, @phdargen is on vacation, mind resolving conflicts?

@jtang17
Copy link
Contributor Author

jtang17 commented Feb 13, 2026

@erikreppel-cb @phdargen - resolved the conflicts!

@phdargen
Copy link
Contributor

Hi @jtang17, my comments are all addressed and I successfully tested the integration + e2e tests last week.

@CarsonRoscoe will test the vercel deployment of the testnet facilitator before we get this in, thanks for your patience 🙏

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

Labels

ci examples Changes to examples sdk Changes to core v2 packages specs Spec changes or additions typescript website

Development

Successfully merging this pull request may close these issues.

4 participants