-
Notifications
You must be signed in to change notification settings - Fork 1
Facilator Improvements #307
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,6 +15,7 @@ import { getSplitterCapabilities } from "../x402_splitter_supported.js"; | |
|
|
||
| describe("x402 Splitter /supported endpoint", () => { | ||
| const originalEnv = process.env.FACILITATOR_WALLET_PRIVATE_KEY; | ||
| const originalFixedFee = process.env.FIXED_FEE; | ||
|
|
||
| afterEach(() => { | ||
| // Restore original env | ||
|
|
@@ -23,6 +24,11 @@ describe("x402 Splitter /supported endpoint", () => { | |
| } else { | ||
| delete process.env.FACILITATOR_WALLET_PRIVATE_KEY; | ||
| } | ||
| if (originalFixedFee) { | ||
| process.env.FIXED_FEE = originalFixedFee; | ||
| } else { | ||
| delete process.env.FIXED_FEE; | ||
| } | ||
| }); | ||
|
|
||
| test("returns supported capabilities", () => { | ||
|
|
@@ -120,10 +126,21 @@ describe("x402 Splitter /supported endpoint", () => { | |
| }); | ||
| }); | ||
|
|
||
| test("extensions array is empty (no whitelist extension)", () => { | ||
| test("extensions includes facilitatorFees for fee-aware routing (#1016)", () => { | ||
| // FIXED_FEE is read at module-load time as a top-level const (default "10000"). | ||
| // This assertion relies on that default; afterEach restores FIXED_FEE to prevent leaks. | ||
| const capabilities = getSplitterCapabilities(); | ||
|
|
||
| expect(capabilities.extensions).toEqual([]); | ||
| expect(capabilities.extensions.length).toBeGreaterThan(0); | ||
| const feesExtension = capabilities.extensions.find((e) => e.name === "facilitatorFees"); | ||
| expect(feesExtension).toBeDefined(); | ||
| expect(feesExtension.version).toBe("1"); | ||
| expect(feesExtension.model).toBe("flat"); | ||
| expect(feesExtension.asset).toBe("USDC"); | ||
| expect(feesExtension.flatFee).toBe("10000"); | ||
| expect(feesExtension.decimals).toBe(6); | ||
| expect(feesExtension.collection).toBe("on_chain_split"); | ||
| expect(feesExtension.networks).toContain("eip155:11155420"); | ||
|
Comment on lines
129
to
143
|
||
| }); | ||
|
|
||
| test("signers is empty (payments signed by payers, not facilitator)", () => { | ||
|
|
@@ -134,10 +151,11 @@ describe("x402 Splitter /supported endpoint", () => { | |
| expect(capabilities.signers).toEqual({}); | ||
| }); | ||
|
|
||
| test("returns empty extensions (no recipient whitelist)", () => { | ||
| test("returns facilitatorFees extension (no recipient whitelist)", () => { | ||
| const capabilities = getSplitterCapabilities(); | ||
|
|
||
| expect(capabilities.extensions).toEqual([]); | ||
| // Has facilitatorFees but no whitelist | ||
| expect(capabilities.extensions.length).toBeGreaterThan(0); | ||
|
|
||
| // Explicitly verify no whitelist extension exists | ||
| const whitelistExtension = capabilities.extensions.find( | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -138,6 +138,25 @@ describe("x402 /supported endpoint", () => { | |
| expect(feeExtension.setup.spender).not.toBeNull(); | ||
| }); | ||
|
|
||
| test("includes facilitatorFees extension for fee-aware routing (#1016)", () => { | ||
| process.env.FACILITATOR_WALLET_PRIVATE_KEY = | ||
| "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"; | ||
|
|
||
| const capabilities = getSupportedCapabilities(); | ||
|
|
||
| const feesExtension = capabilities.extensions.find((e) => e.name === "facilitatorFees"); | ||
| expect(feesExtension).toBeDefined(); | ||
| expect(feesExtension.version).toBe("1"); | ||
| expect(feesExtension.model).toBe("flat"); | ||
| expect(feesExtension.asset).toBe("USDC"); | ||
| expect(feesExtension.flatFee).toBe("10000"); | ||
| expect(feesExtension.decimals).toBe(6); | ||
|
Comment on lines
+141
to
+153
|
||
| expect(feesExtension.networks).toContain("eip155:10"); | ||
| expect(feesExtension.networks).toContain("eip155:8453"); | ||
| expect(feesExtension.networks).toContain("eip155:11155420"); | ||
| expect(feesExtension.networks).toContain("eip155:84532"); | ||
| }); | ||
|
|
||
| test("omits facilitator_fee extension when private key is missing", () => { | ||
| delete process.env.FACILITATOR_WALLET_PRIVATE_KEY; | ||
| const capabilities = getSupportedCapabilities(); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -39,6 +39,7 @@ import { verifySplitterPayment } from "./x402_splitter_verify.js"; | |
| // Alias for backward compatibility | ||
| const SPLITTER_ABI = EIP3009SplitterV1ABI; | ||
| const getSplitterAddress = getEIP3009SplitterAddress; | ||
| const FIXED_FEE = process.env.FIXED_FEE || "10000"; // 0.01 USDC | ||
|
||
|
|
||
| const logger = pino({ level: process.env.LOG_LEVEL || "info" }); | ||
|
|
||
|
|
@@ -222,6 +223,17 @@ export async function settleSplitterPayment(paymentPayload, paymentRequirements) | |
| payer: buyer, | ||
| transaction: hash, | ||
| network, | ||
| // x402 Fee Disclosure receipt (coinbase/x402#1016) | ||
| extensions: { | ||
| facilitatorFees: { | ||
| info: { | ||
| version: "1", | ||
| facilitatorFeePaid: FIXED_FEE, | ||
| asset: `${network}/erc20:${usdcAddress}`, | ||
| model: "flat", | ||
| }, | ||
| }, | ||
| }, | ||
| }; | ||
| } else { | ||
| logger.warn({ hash, status: receipt.status }, "Transaction failed on-chain"); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These new assertions depend on the default
FACILITATOR_FEE_AMOUNTbeing 10000 viagetFeeAmount(). IfFACILITATOR_FEE_AMOUNTis set differently in the environment running tests, this becomes flaky. Prefer explicitly settingprocess.env.FACILITATOR_FEE_AMOUNTin the test setup (or mockinggetFeeAmount) before assertingfacilitatorFeePaid.