feat: switch default facilitator to Obol-operated x402.gcp.obol.tech - #323

Closed
bussyjd wants to merge 2 commits into
mainfrom
feat/obol-facilitator-default
Closed

feat: switch default facilitator to Obol-operated x402.gcp.obol.tech#323
bussyjd wants to merge 2 commits into
mainfrom
feat/obol-facilitator-default

Conversation

@bussyjd

Copy link
Copy Markdown
Contributor

Summary

Replace third-party facilitator.x402.rs with Obol-operated x402.gcp.obol.tech. Introduces DefaultFacilitatorURL constant and updates all references.

Depends on companion infra PR adding Base Sepolia to the Obol facilitator.

Test plan

  • go test ./... passes
  • All test files updated to new URL

bussyjd added 2 commits April 8, 2026 17:31
Two fixes validated with real Base Sepolia x402 payments between
two DGX Spark nodes running Nemotron 120B inference.
1. **CA certificate bundle**: The x402-verifier runs in a distroless
container with no CA store. TLS verification of the public
facilitator (facilitator.x402.rs) fails with "x509: certificate
signed by unknown authority". Fix: `obol sell pricing` now reads
the host CA bundle and patches it into the `ca-certificates`
ConfigMap mounted by the verifier.
2. **Missing Description field**: The facilitator rejects verify
requests that lack a `description` field in PaymentRequirement
with "invalid_format". Fix: populate Description from the route
pattern when building the payment requirement.
## Validated testnet flow
### Alice (seller)
```
obolup.sh # bootstrap dependencies
obol stack init && obol stack up
obol model setup custom --name nemotron-120b \
--endpoint http://host.k3d.internal:8000/v1 \
--model "nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-NVFP4"
obol sell pricing --wallet 0xC0De...97E --chain base-sepolia
obol sell http nemotron \
--wallet 0xC0De...97E --chain base-sepolia \
--per-request 0.001 --namespace llm \
--upstream litellm --port 4000 \
--health-path /health/readiness \
--register --register-name "Nemotron 120B on DGX Spark"
obol tunnel restart
```
### Bob (buyer)
```
# 1. Discover
curl $TUNNEL/.well-known/agent-registration.json
# → name: "Nemotron 120B on DGX Spark", x402Support: true
# 2. Probe
curl -X POST $TUNNEL/services/nemotron/v1/chat/completions
# → 402: payTo=0xC0De...97E, amount=1000, network=base-sepolia
# 3. Sign EIP-712 TransferWithAuthorization + pay
python3 bob_buy.py
# → 200: "The meaning of life is to discover and pursue purpose"
```
### On-chain receipts (Base Sepolia)
| Tx | Description |
|----|-------------|
| 0xd769953b...c231ec0 | x402 settlement: Bob→Alice 0.001 USDC via ERC-3009 |
Balance change: Alice +0.001 USDC, Bob -0.001 USDC.
Facilitator: https://facilitator.x402.rs (real public settlement).
Replace the third-party facilitator.x402.rs with the Obol-operated
facilitator at x402.gcp.obol.tech. This gives us control over
uptime, chain support, and monitoring (Grafana dashboards already
deployed in obol-infrastructure).
Introduces DefaultFacilitatorURL constant in internal/x402 and
updates all references: CLI flag default, config loader, standalone
inference gateway, and deployment store.
Companion PR in obol-infrastructure adds Base Sepolia (84532) to
the facilitator's chain config alongside Base Mainnet (8453).
@bussyjd

Copy link
Copy Markdown
ContributorAuthor

Collapsed into #324 which is a superset of this PR (includes facilitator URL constant, CA bundle, and LiteLLM zero-downtime).

@bussyjdbussyjd closed this Apr 8, 2026
@OisinKyne
OisinKyne deleted the feat/obol-facilitator-default branch April 23, 2026 19:26
Sign up for freeto 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.

1 participant

@bussyjd
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat: switch default facilitator to Obol-operated x402.gcp.obol.tech - #323

Closed
bussyjd wants to merge 2 commits into
mainfrom
feat/obol-facilitator-default
Closed

feat: switch default facilitator to Obol-operated x402.gcp.obol.tech#323
bussyjd wants to merge 2 commits into
mainfrom
feat/obol-facilitator-default

Conversation

@bussyjd

Copy link
Copy Markdown
Contributor

Summary

Replace third-party facilitator.x402.rs with Obol-operated x402.gcp.obol.tech. Introduces DefaultFacilitatorURL constant and updates all references.

Depends on companion infra PR adding Base Sepolia to the Obol facilitator.

Test plan

  • go test ./... passes
  • All test files updated to new URL

bussyjd added 2 commits April 8, 2026 17:31
Two fixes validated with real Base Sepolia x402 payments between
two DGX Spark nodes running Nemotron 120B inference.
1. **CA certificate bundle**: The x402-verifier runs in a distroless
container with no CA store. TLS verification of the public
facilitator (facilitator.x402.rs) fails with "x509: certificate
signed by unknown authority". Fix: `obol sell pricing` now reads
the host CA bundle and patches it into the `ca-certificates`
ConfigMap mounted by the verifier.
2. **Missing Description field**: The facilitator rejects verify
requests that lack a `description` field in PaymentRequirement
with "invalid_format". Fix: populate Description from the route
pattern when building the payment requirement.
## Validated testnet flow
### Alice (seller)
```
obolup.sh # bootstrap dependencies
obol stack init && obol stack up
obol model setup custom --name nemotron-120b \
--endpoint http://host.k3d.internal:8000/v1 \
--model "nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-NVFP4"
obol sell pricing --wallet 0xC0De...97E --chain base-sepolia
obol sell http nemotron \
--wallet 0xC0De...97E --chain base-sepolia \
--per-request 0.001 --namespace llm \
--upstream litellm --port 4000 \
--health-path /health/readiness \
--register --register-name "Nemotron 120B on DGX Spark"
obol tunnel restart
```
### Bob (buyer)
```
# 1. Discover
curl $TUNNEL/.well-known/agent-registration.json
# → name: "Nemotron 120B on DGX Spark", x402Support: true
# 2. Probe
curl -X POST $TUNNEL/services/nemotron/v1/chat/completions
# → 402: payTo=0xC0De...97E, amount=1000, network=base-sepolia
# 3. Sign EIP-712 TransferWithAuthorization + pay
python3 bob_buy.py
# → 200: "The meaning of life is to discover and pursue purpose"
```
### On-chain receipts (Base Sepolia)
| Tx | Description |
|----|-------------|
| 0xd769953b...c231ec0 | x402 settlement: Bob→Alice 0.001 USDC via ERC-3009 |
Balance change: Alice +0.001 USDC, Bob -0.001 USDC.
Facilitator: https://facilitator.x402.rs (real public settlement).
Replace the third-party facilitator.x402.rs with the Obol-operated
facilitator at x402.gcp.obol.tech. This gives us control over
uptime, chain support, and monitoring (Grafana dashboards already
deployed in obol-infrastructure).
Introduces DefaultFacilitatorURL constant in internal/x402 and
updates all references: CLI flag default, config loader, standalone
inference gateway, and deployment store.
Companion PR in obol-infrastructure adds Base Sepolia (84532) to
the facilitator's chain config alongside Base Mainnet (8453).
@bussyjd

Copy link
Copy Markdown
ContributorAuthor

Collapsed into #324 which is a superset of this PR (includes facilitator URL constant, CA bundle, and LiteLLM zero-downtime).

@bussyjdbussyjd closed this Apr 8, 2026
@OisinKyne
OisinKyne deleted the feat/obol-facilitator-default branch April 23, 2026 19:26
Sign up for freeto 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.

1 participant

@bussyjd
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: switch default facilitator to Obol-operated x402.gcp.obol.tech - #323

Closed
bussyjd wants to merge 2 commits into
mainfrom
feat/obol-facilitator-default
Closed

feat: switch default facilitator to Obol-operated x402.gcp.obol.tech#323
bussyjd wants to merge 2 commits into
mainfrom
feat/obol-facilitator-default

Conversation

@bussyjd

Copy link
Copy Markdown
Contributor

Summary

Replace third-party facilitator.x402.rs with Obol-operated x402.gcp.obol.tech. Introduces DefaultFacilitatorURL constant and updates all references.

Depends on companion infra PR adding Base Sepolia to the Obol facilitator.

Test plan

  • go test ./... passes
  • All test files updated to new URL

bussyjd added 2 commits April 8, 2026 17:31
Two fixes validated with real Base Sepolia x402 payments between
two DGX Spark nodes running Nemotron 120B inference.
1. **CA certificate bundle**: The x402-verifier runs in a distroless
container with no CA store. TLS verification of the public
facilitator (facilitator.x402.rs) fails with "x509: certificate
signed by unknown authority". Fix: `obol sell pricing` now reads
the host CA bundle and patches it into the `ca-certificates`
ConfigMap mounted by the verifier.
2. **Missing Description field**: The facilitator rejects verify
requests that lack a `description` field in PaymentRequirement
with "invalid_format". Fix: populate Description from the route
pattern when building the payment requirement.
## Validated testnet flow
### Alice (seller)
```
obolup.sh # bootstrap dependencies
obol stack init && obol stack up
obol model setup custom --name nemotron-120b \
--endpoint http://host.k3d.internal:8000/v1 \
--model "nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-NVFP4"
obol sell pricing --wallet 0xC0De...97E --chain base-sepolia
obol sell http nemotron \
--wallet 0xC0De...97E --chain base-sepolia \
--per-request 0.001 --namespace llm \
--upstream litellm --port 4000 \
--health-path /health/readiness \
--register --register-name "Nemotron 120B on DGX Spark"
obol tunnel restart
```
### Bob (buyer)
```
# 1. Discover
curl $TUNNEL/.well-known/agent-registration.json
# → name: "Nemotron 120B on DGX Spark", x402Support: true
# 2. Probe
curl -X POST $TUNNEL/services/nemotron/v1/chat/completions
# → 402: payTo=0xC0De...97E, amount=1000, network=base-sepolia
# 3. Sign EIP-712 TransferWithAuthorization + pay
python3 bob_buy.py
# → 200: "The meaning of life is to discover and pursue purpose"
```
### On-chain receipts (Base Sepolia)
| Tx | Description |
|----|-------------|
| 0xd769953b...c231ec0 | x402 settlement: Bob→Alice 0.001 USDC via ERC-3009 |
Balance change: Alice +0.001 USDC, Bob -0.001 USDC.
Facilitator: https://facilitator.x402.rs (real public settlement).
Replace the third-party facilitator.x402.rs with the Obol-operated
facilitator at x402.gcp.obol.tech. This gives us control over
uptime, chain support, and monitoring (Grafana dashboards already
deployed in obol-infrastructure).
Introduces DefaultFacilitatorURL constant in internal/x402 and
updates all references: CLI flag default, config loader, standalone
inference gateway, and deployment store.
Companion PR in obol-infrastructure adds Base Sepolia (84532) to
the facilitator's chain config alongside Base Mainnet (8453).
@bussyjd

Copy link
Copy Markdown
ContributorAuthor

Collapsed into #324 which is a superset of this PR (includes facilitator URL constant, CA bundle, and LiteLLM zero-downtime).

@bussyjdbussyjd closed this Apr 8, 2026
@OisinKyne
OisinKyne deleted the feat/obol-facilitator-default branch April 23, 2026 19:26
Sign up for freeto 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.

1 participant

@bussyjd
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: switch default facilitator to Obol-operated x402.gcp.obol.tech - #323

Closed
bussyjd wants to merge 2 commits into
mainfrom
feat/obol-facilitator-default
Closed

feat: switch default facilitator to Obol-operated x402.gcp.obol.tech#323
bussyjd wants to merge 2 commits into
mainfrom
feat/obol-facilitator-default

Conversation

@bussyjd

Copy link
Copy Markdown
Contributor

Summary

Replace third-party facilitator.x402.rs with Obol-operated x402.gcp.obol.tech. Introduces DefaultFacilitatorURL constant and updates all references.

Depends on companion infra PR adding Base Sepolia to the Obol facilitator.

Test plan

  • go test ./... passes
  • All test files updated to new URL

bussyjd added 2 commits April 8, 2026 17:31
Two fixes validated with real Base Sepolia x402 payments between
two DGX Spark nodes running Nemotron 120B inference.
1. **CA certificate bundle**: The x402-verifier runs in a distroless
container with no CA store. TLS verification of the public
facilitator (facilitator.x402.rs) fails with "x509: certificate
signed by unknown authority". Fix: `obol sell pricing` now reads
the host CA bundle and patches it into the `ca-certificates`
ConfigMap mounted by the verifier.
2. **Missing Description field**: The facilitator rejects verify
requests that lack a `description` field in PaymentRequirement
with "invalid_format". Fix: populate Description from the route
pattern when building the payment requirement.
## Validated testnet flow
### Alice (seller)
```
obolup.sh # bootstrap dependencies
obol stack init && obol stack up
obol model setup custom --name nemotron-120b \
--endpoint http://host.k3d.internal:8000/v1 \
--model "nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-NVFP4"
obol sell pricing --wallet 0xC0De...97E --chain base-sepolia
obol sell http nemotron \
--wallet 0xC0De...97E --chain base-sepolia \
--per-request 0.001 --namespace llm \
--upstream litellm --port 4000 \
--health-path /health/readiness \
--register --register-name "Nemotron 120B on DGX Spark"
obol tunnel restart
```
### Bob (buyer)
```
# 1. Discover
curl $TUNNEL/.well-known/agent-registration.json
# → name: "Nemotron 120B on DGX Spark", x402Support: true
# 2. Probe
curl -X POST $TUNNEL/services/nemotron/v1/chat/completions
# → 402: payTo=0xC0De...97E, amount=1000, network=base-sepolia
# 3. Sign EIP-712 TransferWithAuthorization + pay
python3 bob_buy.py
# → 200: "The meaning of life is to discover and pursue purpose"
```
### On-chain receipts (Base Sepolia)
| Tx | Description |
|----|-------------|
| 0xd769953b...c231ec0 | x402 settlement: Bob→Alice 0.001 USDC via ERC-3009 |
Balance change: Alice +0.001 USDC, Bob -0.001 USDC.
Facilitator: https://facilitator.x402.rs (real public settlement).
Replace the third-party facilitator.x402.rs with the Obol-operated
facilitator at x402.gcp.obol.tech. This gives us control over
uptime, chain support, and monitoring (Grafana dashboards already
deployed in obol-infrastructure).
Introduces DefaultFacilitatorURL constant in internal/x402 and
updates all references: CLI flag default, config loader, standalone
inference gateway, and deployment store.
Companion PR in obol-infrastructure adds Base Sepolia (84532) to
the facilitator's chain config alongside Base Mainnet (8453).
@bussyjd

Copy link
Copy Markdown
ContributorAuthor

Collapsed into #324 which is a superset of this PR (includes facilitator URL constant, CA bundle, and LiteLLM zero-downtime).

@bussyjdbussyjd closed this Apr 8, 2026
@OisinKyne
OisinKyne deleted the feat/obol-facilitator-default branch April 23, 2026 19:26
Sign up for freeto 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.

1 participant

@bussyjd
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat: switch default facilitator to Obol-operated x402.gcp.obol.tech - #323

Closed
bussyjd wants to merge 2 commits into
mainfrom
feat/obol-facilitator-default
Closed

feat: switch default facilitator to Obol-operated x402.gcp.obol.tech#323
bussyjd wants to merge 2 commits into
mainfrom
feat/obol-facilitator-default

Conversation

@bussyjd

Copy link
Copy Markdown
Contributor

Summary

Replace third-party facilitator.x402.rs with Obol-operated x402.gcp.obol.tech. Introduces DefaultFacilitatorURL constant and updates all references.

Depends on companion infra PR adding Base Sepolia to the Obol facilitator.

Test plan

  • go test ./... passes
  • All test files updated to new URL

bussyjd added 2 commits April 8, 2026 17:31
Two fixes validated with real Base Sepolia x402 payments between
two DGX Spark nodes running Nemotron 120B inference.
1. **CA certificate bundle**: The x402-verifier runs in a distroless
container with no CA store. TLS verification of the public
facilitator (facilitator.x402.rs) fails with "x509: certificate
signed by unknown authority". Fix: `obol sell pricing` now reads
the host CA bundle and patches it into the `ca-certificates`
ConfigMap mounted by the verifier.
2. **Missing Description field**: The facilitator rejects verify
requests that lack a `description` field in PaymentRequirement
with "invalid_format". Fix: populate Description from the route
pattern when building the payment requirement.
## Validated testnet flow
### Alice (seller)
```
obolup.sh # bootstrap dependencies
obol stack init && obol stack up
obol model setup custom --name nemotron-120b \
--endpoint http://host.k3d.internal:8000/v1 \
--model "nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-NVFP4"
obol sell pricing --wallet 0xC0De...97E --chain base-sepolia
obol sell http nemotron \
--wallet 0xC0De...97E --chain base-sepolia \
--per-request 0.001 --namespace llm \
--upstream litellm --port 4000 \
--health-path /health/readiness \
--register --register-name "Nemotron 120B on DGX Spark"
obol tunnel restart
```
### Bob (buyer)
```
# 1. Discover
curl $TUNNEL/.well-known/agent-registration.json
# → name: "Nemotron 120B on DGX Spark", x402Support: true
# 2. Probe
curl -X POST $TUNNEL/services/nemotron/v1/chat/completions
# → 402: payTo=0xC0De...97E, amount=1000, network=base-sepolia
# 3. Sign EIP-712 TransferWithAuthorization + pay
python3 bob_buy.py
# → 200: "The meaning of life is to discover and pursue purpose"
```
### On-chain receipts (Base Sepolia)
| Tx | Description |
|----|-------------|
| 0xd769953b...c231ec0 | x402 settlement: Bob→Alice 0.001 USDC via ERC-3009 |
Balance change: Alice +0.001 USDC, Bob -0.001 USDC.
Facilitator: https://facilitator.x402.rs (real public settlement).
Replace the third-party facilitator.x402.rs with the Obol-operated
facilitator at x402.gcp.obol.tech. This gives us control over
uptime, chain support, and monitoring (Grafana dashboards already
deployed in obol-infrastructure).
Introduces DefaultFacilitatorURL constant in internal/x402 and
updates all references: CLI flag default, config loader, standalone
inference gateway, and deployment store.
Companion PR in obol-infrastructure adds Base Sepolia (84532) to
the facilitator's chain config alongside Base Mainnet (8453).
@bussyjd

Copy link
Copy Markdown
ContributorAuthor

Collapsed into #324 which is a superset of this PR (includes facilitator URL constant, CA bundle, and LiteLLM zero-downtime).

@bussyjdbussyjd closed this Apr 8, 2026
@OisinKyne
OisinKyne deleted the feat/obol-facilitator-default branch April 23, 2026 19:26
Sign up for freeto 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.

1 participant

@bussyjd
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: switch default facilitator to Obol-operated x402.gcp.obol.tech - #323

Closed
bussyjd wants to merge 2 commits into
mainfrom
feat/obol-facilitator-default
Closed

feat: switch default facilitator to Obol-operated x402.gcp.obol.tech#323
bussyjd wants to merge 2 commits into
mainfrom
feat/obol-facilitator-default

Conversation

@bussyjd

Copy link
Copy Markdown
Contributor

Summary

Replace third-party facilitator.x402.rs with Obol-operated x402.gcp.obol.tech. Introduces DefaultFacilitatorURL constant and updates all references.

Depends on companion infra PR adding Base Sepolia to the Obol facilitator.

Test plan

  • go test ./... passes
  • All test files updated to new URL

bussyjd added 2 commits April 8, 2026 17:31
Two fixes validated with real Base Sepolia x402 payments between
two DGX Spark nodes running Nemotron 120B inference.
1. **CA certificate bundle**: The x402-verifier runs in a distroless
container with no CA store. TLS verification of the public
facilitator (facilitator.x402.rs) fails with "x509: certificate
signed by unknown authority". Fix: `obol sell pricing` now reads
the host CA bundle and patches it into the `ca-certificates`
ConfigMap mounted by the verifier.
2. **Missing Description field**: The facilitator rejects verify
requests that lack a `description` field in PaymentRequirement
with "invalid_format". Fix: populate Description from the route
pattern when building the payment requirement.
## Validated testnet flow
### Alice (seller)
```
obolup.sh # bootstrap dependencies
obol stack init && obol stack up
obol model setup custom --name nemotron-120b \
--endpoint http://host.k3d.internal:8000/v1 \
--model "nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-NVFP4"
obol sell pricing --wallet 0xC0De...97E --chain base-sepolia
obol sell http nemotron \
--wallet 0xC0De...97E --chain base-sepolia \
--per-request 0.001 --namespace llm \
--upstream litellm --port 4000 \
--health-path /health/readiness \
--register --register-name "Nemotron 120B on DGX Spark"
obol tunnel restart
```
### Bob (buyer)
```
# 1. Discover
curl $TUNNEL/.well-known/agent-registration.json
# → name: "Nemotron 120B on DGX Spark", x402Support: true
# 2. Probe
curl -X POST $TUNNEL/services/nemotron/v1/chat/completions
# → 402: payTo=0xC0De...97E, amount=1000, network=base-sepolia
# 3. Sign EIP-712 TransferWithAuthorization + pay
python3 bob_buy.py
# → 200: "The meaning of life is to discover and pursue purpose"
```
### On-chain receipts (Base Sepolia)
| Tx | Description |
|----|-------------|
| 0xd769953b...c231ec0 | x402 settlement: Bob→Alice 0.001 USDC via ERC-3009 |
Balance change: Alice +0.001 USDC, Bob -0.001 USDC.
Facilitator: https://facilitator.x402.rs (real public settlement).
Replace the third-party facilitator.x402.rs with the Obol-operated
facilitator at x402.gcp.obol.tech. This gives us control over
uptime, chain support, and monitoring (Grafana dashboards already
deployed in obol-infrastructure).
Introduces DefaultFacilitatorURL constant in internal/x402 and
updates all references: CLI flag default, config loader, standalone
inference gateway, and deployment store.
Companion PR in obol-infrastructure adds Base Sepolia (84532) to
the facilitator's chain config alongside Base Mainnet (8453).
@bussyjd

Copy link
Copy Markdown
ContributorAuthor

Collapsed into #324 which is a superset of this PR (includes facilitator URL constant, CA bundle, and LiteLLM zero-downtime).

@bussyjdbussyjd closed this Apr 8, 2026
@OisinKyne
OisinKyne deleted the feat/obol-facilitator-default branch April 23, 2026 19:26
Sign up for freeto 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.

1 participant

@bussyjd
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: switch default facilitator to Obol-operated x402.gcp.obol.tech - #323

Closed
bussyjd wants to merge 2 commits into
mainfrom
feat/obol-facilitator-default
Closed

feat: switch default facilitator to Obol-operated x402.gcp.obol.tech#323
bussyjd wants to merge 2 commits into
mainfrom
feat/obol-facilitator-default

Conversation

@bussyjd

Copy link
Copy Markdown
Contributor

Summary

Replace third-party facilitator.x402.rs with Obol-operated x402.gcp.obol.tech. Introduces DefaultFacilitatorURL constant and updates all references.

Depends on companion infra PR adding Base Sepolia to the Obol facilitator.

Test plan

  • go test ./... passes
  • All test files updated to new URL

bussyjd added 2 commits April 8, 2026 17:31
Two fixes validated with real Base Sepolia x402 payments between
two DGX Spark nodes running Nemotron 120B inference.
1. **CA certificate bundle**: The x402-verifier runs in a distroless
container with no CA store. TLS verification of the public
facilitator (facilitator.x402.rs) fails with "x509: certificate
signed by unknown authority". Fix: `obol sell pricing` now reads
the host CA bundle and patches it into the `ca-certificates`
ConfigMap mounted by the verifier.
2. **Missing Description field**: The facilitator rejects verify
requests that lack a `description` field in PaymentRequirement
with "invalid_format". Fix: populate Description from the route
pattern when building the payment requirement.
## Validated testnet flow
### Alice (seller)
```
obolup.sh # bootstrap dependencies
obol stack init && obol stack up
obol model setup custom --name nemotron-120b \
--endpoint http://host.k3d.internal:8000/v1 \
--model "nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-NVFP4"
obol sell pricing --wallet 0xC0De...97E --chain base-sepolia
obol sell http nemotron \
--wallet 0xC0De...97E --chain base-sepolia \
--per-request 0.001 --namespace llm \
--upstream litellm --port 4000 \
--health-path /health/readiness \
--register --register-name "Nemotron 120B on DGX Spark"
obol tunnel restart
```
### Bob (buyer)
```
# 1. Discover
curl $TUNNEL/.well-known/agent-registration.json
# → name: "Nemotron 120B on DGX Spark", x402Support: true
# 2. Probe
curl -X POST $TUNNEL/services/nemotron/v1/chat/completions
# → 402: payTo=0xC0De...97E, amount=1000, network=base-sepolia
# 3. Sign EIP-712 TransferWithAuthorization + pay
python3 bob_buy.py
# → 200: "The meaning of life is to discover and pursue purpose"
```
### On-chain receipts (Base Sepolia)
| Tx | Description |
|----|-------------|
| 0xd769953b...c231ec0 | x402 settlement: Bob→Alice 0.001 USDC via ERC-3009 |
Balance change: Alice +0.001 USDC, Bob -0.001 USDC.
Facilitator: https://facilitator.x402.rs (real public settlement).
Replace the third-party facilitator.x402.rs with the Obol-operated
facilitator at x402.gcp.obol.tech. This gives us control over
uptime, chain support, and monitoring (Grafana dashboards already
deployed in obol-infrastructure).
Introduces DefaultFacilitatorURL constant in internal/x402 and
updates all references: CLI flag default, config loader, standalone
inference gateway, and deployment store.
Companion PR in obol-infrastructure adds Base Sepolia (84532) to
the facilitator's chain config alongside Base Mainnet (8453).
@bussyjd

Copy link
Copy Markdown
ContributorAuthor

Collapsed into #324 which is a superset of this PR (includes facilitator URL constant, CA bundle, and LiteLLM zero-downtime).

@bussyjdbussyjd closed this Apr 8, 2026
@OisinKyne
OisinKyne deleted the feat/obol-facilitator-default branch April 23, 2026 19:26
Sign up for freeto 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.

1 participant

@bussyjd
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat: switch default facilitator to Obol-operated x402.gcp.obol.tech - #323

Closed
bussyjd wants to merge 2 commits into
mainfrom
feat/obol-facilitator-default
Closed

feat: switch default facilitator to Obol-operated x402.gcp.obol.tech#323
bussyjd wants to merge 2 commits into
mainfrom
feat/obol-facilitator-default

Conversation

@bussyjd

Copy link
Copy Markdown
Contributor

Summary

Replace third-party facilitator.x402.rs with Obol-operated x402.gcp.obol.tech. Introduces DefaultFacilitatorURL constant and updates all references.

Depends on companion infra PR adding Base Sepolia to the Obol facilitator.

Test plan

  • go test ./... passes
  • All test files updated to new URL

bussyjd added 2 commits April 8, 2026 17:31
Two fixes validated with real Base Sepolia x402 payments between
two DGX Spark nodes running Nemotron 120B inference.
1. **CA certificate bundle**: The x402-verifier runs in a distroless
container with no CA store. TLS verification of the public
facilitator (facilitator.x402.rs) fails with "x509: certificate
signed by unknown authority". Fix: `obol sell pricing` now reads
the host CA bundle and patches it into the `ca-certificates`
ConfigMap mounted by the verifier.
2. **Missing Description field**: The facilitator rejects verify
requests that lack a `description` field in PaymentRequirement
with "invalid_format". Fix: populate Description from the route
pattern when building the payment requirement.
## Validated testnet flow
### Alice (seller)
```
obolup.sh # bootstrap dependencies
obol stack init && obol stack up
obol model setup custom --name nemotron-120b \
--endpoint http://host.k3d.internal:8000/v1 \
--model "nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-NVFP4"
obol sell pricing --wallet 0xC0De...97E --chain base-sepolia
obol sell http nemotron \
--wallet 0xC0De...97E --chain base-sepolia \
--per-request 0.001 --namespace llm \
--upstream litellm --port 4000 \
--health-path /health/readiness \
--register --register-name "Nemotron 120B on DGX Spark"
obol tunnel restart
```
### Bob (buyer)
```
# 1. Discover
curl $TUNNEL/.well-known/agent-registration.json
# → name: "Nemotron 120B on DGX Spark", x402Support: true
# 2. Probe
curl -X POST $TUNNEL/services/nemotron/v1/chat/completions
# → 402: payTo=0xC0De...97E, amount=1000, network=base-sepolia
# 3. Sign EIP-712 TransferWithAuthorization + pay
python3 bob_buy.py
# → 200: "The meaning of life is to discover and pursue purpose"
```
### On-chain receipts (Base Sepolia)
| Tx | Description |
|----|-------------|
| 0xd769953b...c231ec0 | x402 settlement: Bob→Alice 0.001 USDC via ERC-3009 |
Balance change: Alice +0.001 USDC, Bob -0.001 USDC.
Facilitator: https://facilitator.x402.rs (real public settlement).
Replace the third-party facilitator.x402.rs with the Obol-operated
facilitator at x402.gcp.obol.tech. This gives us control over
uptime, chain support, and monitoring (Grafana dashboards already
deployed in obol-infrastructure).
Introduces DefaultFacilitatorURL constant in internal/x402 and
updates all references: CLI flag default, config loader, standalone
inference gateway, and deployment store.
Companion PR in obol-infrastructure adds Base Sepolia (84532) to
the facilitator's chain config alongside Base Mainnet (8453).
@bussyjd

Copy link
Copy Markdown
ContributorAuthor

Collapsed into #324 which is a superset of this PR (includes facilitator URL constant, CA bundle, and LiteLLM zero-downtime).

@bussyjdbussyjd closed this Apr 8, 2026
@OisinKyne
OisinKyne deleted the feat/obol-facilitator-default branch April 23, 2026 19:26
Sign up for freeto 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.

1 participant

@bussyjd