Skip to content

Commit de2b972

Browse files
committed
merge: PR #609 — obol sell mcp (paid MCP tool over x402)
2 parents 9a902f0 + 1e981d3 commit de2b972

24 files changed

Lines changed: 521 additions & 22 deletions

cmd/obol/sell.go

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import (
3737
"github.com/ObolNetwork/obol-stack/internal/ui"
3838
"github.com/ObolNetwork/obol-stack/internal/validate"
3939
x402verifier "github.com/ObolNetwork/obol-stack/internal/x402"
40+
"github.com/ObolNetwork/obol-stack/internal/x402mcp"
4041
"github.com/ethereum/go-ethereum/common"
4142
"github.com/urfave/cli/v3"
4243
"gopkg.in/yaml.v3"
@@ -49,6 +50,7 @@ func sellCommand(cfg *config.Config) *cli.Command {
4950
Commands: []*cli.Command{
5051
sellInferenceCommand(cfg),
5152
sellHTTPCommand(cfg),
53+
sellMCPCommand(cfg),
5254
sellAgentCommand(cfg),
5355
sellDemoCommand(cfg),
5456
sellListCommand(cfg),
@@ -531,6 +533,131 @@ Examples:
531533
// sell http — create a ServiceOffer CRD for any HTTP service
532534
// ---------------------------------------------------------------------------
533535

536+
func sellMCPCommand(cfg *config.Config) *cli.Command {
537+
_ = cfg
538+
return &cli.Command{
539+
Name: "mcp",
540+
Usage: "Sell a paid MCP tool over x402 (in-band _meta payment)",
541+
ArgsUsage: "[name]",
542+
Description: `Runs a local x402-paid MCP (Model Context Protocol) server in the
543+
foreground. The paid tool forwards the buyer's JSON arguments to a backend HTTP
544+
service, injecting the seller's own credential (an API key the buyer never
545+
sees), so any credentialed real-world service can be resold to agents per call.
546+
Buyers (e.g. hermes-agent's pay_mcp plugin) settle in-band via the MCP request
547+
_meta["x402/payment"] field, per specs/transports-v2/mcp.md. The wrapper runs
548+
verify -> execute -> settle inside the tool call, so a caller is never charged
549+
for a failed tool. This is the application-layer counterpart to the HTTP-402
550+
ForwardAuth gate used by 'obol sell inference' / 'obol sell http'.
551+
552+
Connect a buyer at http://localhost:<port>/mcp (streamable HTTP).
553+
554+
Examples:
555+
# Front a weather API as a paid MCP tool (the canonical x402 paid-MCP shape):
556+
obol sell mcp weather --pay-to 0x... --price 0.001 --chain base-sepolia \
557+
--tool-name get_weather \
558+
--description 'Current weather for a city. Args: {city}' \
559+
--upstream https://your-weather-service/current
560+
561+
# Any JSON HTTP service works the same way; pass the backend's auth header if
562+
# it needs one (set server-side, never sent to buyers):
563+
obol sell mcp my-tool --pay-to 0x... --price 0.005 --tool-name call \
564+
--upstream https://api.example.com/do --upstream-header 'X-Api-Key: <key>'`,
565+
Flags: []cli.Flag{
566+
payToFlag("Payment recipient address"),
567+
&cli.StringFlag{
568+
Name: "chain",
569+
Usage: "Payment chain (base, base-sepolia, ethereum, polygon)",
570+
Value: "base-sepolia",
571+
},
572+
&cli.StringFlag{
573+
Name: "price",
574+
Usage: "Per-call price, USD-denominated (e.g. 0.001)",
575+
Value: "0.001",
576+
},
577+
&cli.StringFlag{
578+
Name: "tool-name",
579+
Usage: "Name of the paid MCP tool",
580+
Value: "call",
581+
},
582+
&cli.StringFlag{
583+
Name: "description",
584+
Usage: "Human-readable description of the paid tool",
585+
},
586+
&cli.IntFlag{
587+
Name: "port",
588+
Usage: "Port to serve the MCP server on",
589+
Value: 4022,
590+
},
591+
&cli.StringFlag{
592+
Name: "upstream",
593+
Usage: "Backend HTTP service URL the paid tool POSTs the buyer's JSON args to (e.g. a weather/data API)",
594+
},
595+
&cli.StringSliceFlag{
596+
Name: "upstream-header",
597+
Usage: "Optional auth header for the backend, set server-side and never sent to buyers (repeatable, \"Key: Value\", e.g. \"X-Api-Key: <key>\")",
598+
},
599+
&cli.StringFlag{
600+
Name: "facilitator",
601+
Usage: "x402 facilitator URL (verify/settle)",
602+
},
603+
},
604+
Action: func(ctx context.Context, cmd *cli.Command) error {
605+
u := getUI(cmd)
606+
607+
payTo := cmd.String("pay-to")
608+
if payTo == "" {
609+
return errors.New("--pay-to is required")
610+
}
611+
name := cmd.Args().First()
612+
if name == "" {
613+
name = "obol-mcp"
614+
}
615+
facilitator := cmd.String("facilitator")
616+
if facilitator == "" {
617+
facilitator = x402verifier.DefaultFacilitatorURL
618+
}
619+
620+
headers, err := parseUpstreamHeaders(cmd.StringSlice("upstream-header"))
621+
if err != nil {
622+
return err
623+
}
624+
625+
u.Infof("Starting paid MCP server %q on port %d (Ctrl-C to stop)", name, cmd.Int("port"))
626+
return x402mcp.Serve(ctx, x402mcp.Options{
627+
Name: name,
628+
ToolName: cmd.String("tool-name"),
629+
Description: cmd.String("description"),
630+
Port: cmd.Int("port"),
631+
PayTo: payTo,
632+
Price: cmd.String("price"),
633+
Chain: cmd.String("chain"),
634+
FacilitatorURL: facilitator,
635+
Upstream: cmd.String("upstream"),
636+
UpstreamHeaders: headers,
637+
})
638+
},
639+
}
640+
}
641+
642+
// parseUpstreamHeaders turns repeatable "Key: Value" --upstream-header flags
643+
// into a header map injected on upstream calls (the seller's credential).
644+
func parseUpstreamHeaders(pairs []string) (map[string]string, error) {
645+
if len(pairs) == 0 {
646+
return nil, nil
647+
}
648+
headers := make(map[string]string, len(pairs))
649+
for _, p := range pairs {
650+
k, v, ok := strings.Cut(p, ":")
651+
k = strings.TrimSpace(k)
652+
v = strings.TrimSpace(v)
653+
if !ok || k == "" {
654+
return nil, fmt.Errorf("invalid --upstream-header %q: want \"Key: Value\"", p)
655+
}
656+
headers[k] = v
657+
}
658+
return headers, nil
659+
}
660+
534661
func sellHTTPCommand(cfg *config.Config) *cli.Command {
535662
return &cli.Command{
536663
Name: "http",

cmd/obol/sell_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,28 @@ func newTestConfig(t *testing.T) *config.Config {
147147
// Tests
148148
// ─────────────────────────────────────────────────────────────────────────────
149149

150+
func TestParseUpstreamHeaders(t *testing.T) {
151+
t.Run("parses Key: Value pairs and trims", func(t *testing.T) {
152+
got, err := parseUpstreamHeaders([]string{"X-Api-Key: abc", "X-Region:eu"})
153+
if err != nil {
154+
t.Fatalf("unexpected error: %v", err)
155+
}
156+
if got["X-Api-Key"] != "abc" || got["X-Region"] != "eu" {
157+
t.Errorf("got %v", got)
158+
}
159+
})
160+
t.Run("nil for no flags", func(t *testing.T) {
161+
if got, err := parseUpstreamHeaders(nil); err != nil || got != nil {
162+
t.Errorf("got %v, %v; want nil, nil", got, err)
163+
}
164+
})
165+
t.Run("rejects malformed pair", func(t *testing.T) {
166+
if _, err := parseUpstreamHeaders([]string{"no-colon"}); err == nil {
167+
t.Error("expected error for header without a colon")
168+
}
169+
})
170+
}
171+
150172
func TestSellCommand_Structure(t *testing.T) {
151173
cfg := newTestConfig(t)
152174
cmd := sellCommand(cfg)

go.mod

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ go 1.25.1
44

55
require (
66
github.com/charmbracelet/lipgloss v1.1.0
7-
github.com/coinbase/x402/go v0.0.0-20260331075907-bff876de232a
87
github.com/cucumber/godog v0.15.1
98
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0
109
github.com/dustinkirkland/golang-petname v0.0.0-20240428194347-eebcea082ee0
@@ -15,13 +14,15 @@ require (
1514
github.com/hf/nitrite v0.0.0-20241225144000-c2d5d3c4f303
1615
github.com/hf/nsm v0.0.0-20220930140112-cd181bd646b9
1716
github.com/mattn/go-isatty v0.0.20
17+
github.com/modelcontextprotocol/go-sdk v1.3.0
1818
github.com/prometheus/client_golang v1.19.1
1919
github.com/prometheus/client_model v0.6.1
2020
github.com/prometheus/common v0.55.0
2121
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2
2222
github.com/shopspring/decimal v1.3.1
2323
github.com/urfave/cli/v2 v2.27.5
2424
github.com/urfave/cli/v3 v3.6.2
25+
github.com/x402-foundation/x402/go v0.0.0-20260529172747-45d81d46e5bd
2526
golang.org/x/crypto v0.46.0
2627
golang.org/x/net v0.48.0
2728
golang.org/x/sys v0.39.0
@@ -70,6 +71,7 @@ require (
7071
github.com/google/gnostic-models v0.7.0 // indirect
7172
github.com/google/go-cmp v0.7.0 // indirect
7273
github.com/google/go-configfs-tsm v0.2.2 // indirect
74+
github.com/google/jsonschema-go v0.4.2 // indirect
7375
github.com/google/logger v1.1.1 // indirect
7476
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
7577
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
@@ -102,6 +104,7 @@ require (
102104
github.com/x448/float16 v0.8.4 // indirect
103105
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
104106
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
107+
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
105108
go.uber.org/multierr v1.11.0 // indirect
106109
go.yaml.in/yaml/v2 v2.4.3 // indirect
107110
go.yaml.in/yaml/v3 v3.0.4 // indirect

go.sum

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,6 @@ github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwP
4040
github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
4141
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo=
4242
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ=
43-
github.com/coinbase/x402/go v0.0.0-20260331075907-bff876de232a h1:L8ZxbOqBxB7LYXdypWYA7Qq0iQtFaS6PCwjnhij4Oks=
44-
github.com/coinbase/x402/go v0.0.0-20260331075907-bff876de232a/go.mod h1:8xt63HO8mECoUwoI8E9xOjPiOzgFUvUx+Svrok+Wkss=
4543
github.com/consensys/gnark-crypto v0.19.2 h1:qrEAIXq3T4egxqiliFFoNrepkIWVEeIYwt3UL0fvS80=
4644
github.com/consensys/gnark-crypto v0.19.2/go.mod h1:rT23F0XSZqE0mUA0+pRtnL56IbPxs6gp4CeRsBk4XS0=
4745
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
@@ -129,6 +127,8 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
129127
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
130128
github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI=
131129
github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
130+
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
131+
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
132132
github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
133133
github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
134134
github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo=
@@ -144,6 +144,8 @@ github.com/google/go-tdx-guest v0.3.1/go.mod h1:/rc3d7rnPykOPuY8U9saMyEps0PZDThL
144144
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
145145
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
146146
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
147+
github.com/google/jsonschema-go v0.4.2 h1:tmrUohrwoLZZS/P3x7ex0WAVknEkBZM46iALbcqoRA8=
148+
github.com/google/jsonschema-go v0.4.2/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE=
147149
github.com/google/logger v1.1.1 h1:+6Z2geNxc9G+4D4oDO9njjjn2d0wN5d7uOo0vOIW1NQ=
148150
github.com/google/logger v1.1.1/go.mod h1:BkeJZ+1FhQ+/d087r4dzojEg1u2ZX+ZqG1jTUrLM+zQ=
149151
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
@@ -226,6 +228,8 @@ github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxd
226228
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
227229
github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A=
228230
github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4=
231+
github.com/modelcontextprotocol/go-sdk v1.3.0 h1:gMfZkv3DzQF5q/DcQePo5rahEY+sguyPfXDfNBcT0Zs=
232+
github.com/modelcontextprotocol/go-sdk v1.3.0/go.mod h1:AnQ//Qc6+4nIyyrB4cxBU7UW9VibK4iOZBeyP/rF1IE=
229233
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
230234
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
231235
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -320,12 +324,22 @@ github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w=
320324
github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ=
321325
github.com/urfave/cli/v3 v3.6.2 h1:lQuqiPrZ1cIz8hz+HcrG0TNZFxU70dPZ3Yl+pSrH9A8=
322326
github.com/urfave/cli/v3 v3.6.2/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso=
327+
github.com/x402-foundation/x402/go v0.0.0-20260529172747-45d81d46e5bd h1:Bb+VbLsDEQ7g69MZNfUkOva2qKuB5TCSgGXXOPTB0Qw=
328+
github.com/x402-foundation/x402/go v0.0.0-20260529172747-45d81d46e5bd/go.mod h1:58Cdk20g83eAI3QvxAiQJze7qWUgkjCj9uZlPb4M4HM=
323329
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
324330
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
331+
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
332+
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
333+
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
334+
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
335+
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
336+
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
325337
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
326338
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
327339
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
328340
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
341+
github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
342+
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
329343
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
330344
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
331345
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=

internal/inference/gateway.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import (
1616
"github.com/ObolNetwork/obol-stack/internal/enclave"
1717
"github.com/ObolNetwork/obol-stack/internal/tee"
1818
x402pkg "github.com/ObolNetwork/obol-stack/internal/x402"
19-
x402types "github.com/coinbase/x402/go/types"
19+
x402types "github.com/x402-foundation/x402/go/types"
2020
)
2121

2222
// GatewayConfig holds configuration for the x402 inference gateway.

internal/inference/gateway_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111
"testing"
1212

1313
x402pkg "github.com/ObolNetwork/obol-stack/internal/x402"
14-
x402types "github.com/coinbase/x402/go/types"
14+
x402types "github.com/x402-foundation/x402/go/types"
1515
)
1616

1717
// ── Mock facilitator ──────────────────────────────────────────────────────────

internal/serviceoffercontroller/openapi_components.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ package serviceoffercontroller
77
// Two principles:
88
//
99
// 1. x402 components mirror the canonical Coinbase types/v2 wire format
10-
// (github.com/coinbase/x402/go/types). Field names, optionality, and
10+
// (github.com/x402-foundation/x402/go/types). Field names, optionality, and
1111
// X402Version=2 must stay in sync with that upstream — internal/x402
1212
// re-exports the same structs and lockstep is enforced by 402 smoke
1313
// tests, not by a generator. Update both together when the spec moves.

internal/x402/agent_extras_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import (
44
"reflect"
55
"testing"
66

7-
x402types "github.com/coinbase/x402/go/types"
7+
x402types "github.com/x402-foundation/x402/go/types"
88
)
99

1010
func TestMergeAgentExtras_Noop_NonAgentRule(t *testing.T) {

internal/x402/buyer/config.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import (
1515
"path/filepath"
1616
"strings"
1717

18-
x402types "github.com/coinbase/x402/go/types"
18+
x402types "github.com/x402-foundation/x402/go/types"
1919
)
2020

2121
// Config is the top-level sidecar configuration, loaded from a JSON file

internal/x402/buyer/encoding.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"encoding/json"
66
"fmt"
77

8-
x402types "github.com/coinbase/x402/go/types"
8+
x402types "github.com/x402-foundation/x402/go/types"
99
)
1010

1111
// EncodePayment converts a v2 PaymentPayload to a base64-encoded JSON string

0 commit comments

Comments
 (0)