sincor-x402 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,251 @@
1
+ Metadata-Version: 2.4
2
+ Name: sincor-x402
3
+ Version: 0.1.0
4
+ Summary: Verified x402 + MCP wrapper: escrowed, SIGIL-committed settlement for x402 endpoints and MCP tools (reference implementation — see README honesty notes)
5
+ Author: SINCOR Business Solutions
6
+ License: Apache-2.0
7
+ Project-URL: Homepage, https://getsincor.com
8
+ Project-URL: Repository, https://github.com/OrderofChaos33/SINCOR2
9
+ Project-URL: AgentCard, https://getsincor.com/.well-known/agent-card.json
10
+ Keywords: x402,mcp,escrow,agent-payments,base
11
+ Requires-Python: >=3.10
12
+ Description-Content-Type: text/markdown
13
+ Provides-Extra: fastapi
14
+ Requires-Dist: fastapi>=0.110; extra == "fastapi"
15
+ Provides-Extra: hub
16
+ Requires-Dist: web3>=6.15; extra == "hub"
17
+ Requires-Dist: eth-account>=0.11; extra == "hub"
18
+ Requires-Dist: eth-utils>=4; extra == "hub"
19
+ Provides-Extra: dev
20
+ Requires-Dist: pytest>=8; extra == "dev"
21
+ Requires-Dist: web3>=6.15; extra == "dev"
22
+ Requires-Dist: eth-account>=0.11; extra == "dev"
23
+ Requires-Dist: eth-utils>=4; extra == "dev"
24
+ Requires-Dist: eth-tester>=0.13; extra == "dev"
25
+ Requires-Dist: py-solc-x>=1.1; extra == "dev"
26
+
27
+ # sincor-x402 — Verified x402 + MCP wrapper
28
+
29
+ **"Pay-and-pray" is the gap.** Coinbase's x402 lets an agent pay USDC to an
30
+ endpoint up front — with no escrow, no committed spec, and no guarantee the
31
+ seller won't return garbage or time out after taking the funds. `sincor-x402`
32
+ wraps any x402 endpoint or MCP tool in the missing piece:
33
+
34
+ ```
35
+ request → HTTP 402 (escrow terms + committed spec hash)
36
+ → payment verified → funds held in escrow
37
+ → work executes (timeout-bounded)
38
+ → result verified against the committed spec (SIGIL-style commitment)
39
+ → SEAL release on pass · refund on fail or timeout
40
+ ```
41
+
42
+ ## Honesty first — what is real and what is not
43
+
44
+ * **Live on getsincor.com today:** CNP task bidding/auctions, pool
45
+ settlement, and KYA, plus the platform's own x402 seller/buyer code this
46
+ package's wire shapes are modelled on.
47
+ * **Integration-pilot framing:** SEAL (EIP-712 settlement) and SIGIL
48
+ (verification) are the platform concepts this wrapper's interfaces are
49
+ shaped around. This package implements them as **pluggable interfaces
50
+ with labelled local reference implementations** (`LocalReferencePlatform`,
51
+ `LocalFacilitator`, `ReferenceVerifier`). They do NOT talk to a live
52
+ SIGIL service or a production escrow endpoint — none is wired yet.
53
+ * **No SINCOR escrow contract is deployed on Base mainnet.** Nothing in
54
+ this package moves real funds. Do not represent it otherwise.
55
+
56
+ ## Networks & constants
57
+
58
+ * **Base mainnet:** chain ID **8453**
59
+ * **Base Sepolia:** chain ID **84532** — testnet rehearsal only
60
+ * **USDC on Base:** `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913`
61
+ * **Live agent card:** https://getsincor.com/.well-known/agent-card.json
62
+
63
+ Nothing in this package is deployed on either network — these are the
64
+ chain IDs and contract constants the wire shapes and the Hub engine are
65
+ written against, not live deployments.
66
+
67
+ ## Install
68
+
69
+ ```bash
70
+ pip install sincor-x402 # core: zero dependencies, stdlib only
71
+ pip install "sincor-x402[fastapi]" # + the FastAPI adapter
72
+ ```
73
+
74
+ ## Server: wrap an endpoint (2 lines)
75
+
76
+ ```python
77
+ from sincor_x402 import VerifiedEndpoint, PaymentRequirement
78
+ endpoint = VerifiedEndpoint(summarize, requirement=REQ, spec={"required_keys": ["summary"]})
79
+ ```
80
+
81
+ `REQ` is your price/terms (`PaymentRequirement(scheme="exact", network="base",
82
+ max_amount_required="10000", asset=<USDC on Base>, pay_to=<your address>,
83
+ max_timeout_seconds=60)`). Feed requests to `endpoint.handle(headers=..., kwargs=...)`:
84
+ no payment header → a 402 challenge carrying your `accepts[]` + escrow terms;
85
+ a paid request runs the full escrow → execute → verify → release/refund loop.
86
+
87
+ With FastAPI (`sincor-x402[fastapi]`):
88
+
89
+ ```python
90
+ from sincor_x402.fastapi_adapter import sincor_verified
91
+ @app.post("/summarize")
92
+ @sincor_verified(requirement=REQ, spec={"required_keys": ["summary"]})
93
+ def summarize(payload: dict): ...
94
+ ```
95
+
96
+ ## MCP: wrap a tool (2 lines)
97
+
98
+ ```python
99
+ from sincor_x402 import verified_tool
100
+ @verified_tool(requirement=REQ, spec={"required_keys": ["answer"]})
101
+ def lookup(symbol: str): ...
102
+ ```
103
+
104
+ No MCP SDK is imported or required: the wrapped tool exposes
105
+ `tool_definition()` (an MCP `tools/list`-shaped descriptor) and
106
+ `call_paid(payment_header=..., **kwargs)` for your host's `tools/call`
107
+ handler, plus a best-effort `register(server)` for FastMCP-style hosts.
108
+
109
+ ## Buyer: pay a wrapped endpoint — exactly once per instruction
110
+
111
+ ```python
112
+ from sincor_x402 import VerifiedBuyer
113
+ buyer = VerifiedBuyer(wallet_address, signer_fn) # signer is injected; keys never enter this package
114
+ out = buyer.fetch(url, instruction_id="job-123", body={"q": "..."})
115
+ ```
116
+
117
+ * **Instruction-scoped idempotency:** `instruction_id` is your unit of work.
118
+ Re-calling `fetch` with the same id and the same request returns the
119
+ recorded outcome and **never signs a second payment** — a historical x402
120
+ retry bug produced 40 payments for one request; the journal + same-payload
121
+ resend design here makes that impossible (covered by a 40× retry-storm test).
122
+ Reusing an id with a *different* request raises `IdempotencyConflict`.
123
+ * **Per-payee velocity cap:** distinct instructions to one `payTo` are
124
+ capped by count and total amount per sliding window (`VelocityCap`),
125
+ checked **before** signing, so a capped attempt creates no payment.
126
+ * **No blind retries:** an ambiguous paid response raises `AmbiguousPayment`
127
+ and locks the instruction rather than risking a double-pay.
128
+ * **Per-call cap:** challenges above `max_payment_usd` are refused unsigned.
129
+
130
+ ## Server safety: the accepts[] hedge
131
+
132
+ A client echoes the terms it "accepted" inside its payment payload — and a
133
+ buggy or malicious client can rewrite them (lower price, swapped `payTo`).
134
+ This server **never trusts the client's copy**: it matches the claim against
135
+ its own retained `accepts[]` entry on scheme, network, amount, asset,
136
+ payTo, and timeout, rejects mismatches before the facilitator is touched,
137
+ and passes **its own** `PaymentRequirement` object to the facilitator.
138
+ Price-rewrite and payTo-swap attacks have dedicated negative tests.
139
+
140
+ ## Hub settlement engine (`sincor_x402.hub_engine`)
141
+
142
+ A client for the **SincorSettlementHub** contract interface from the
143
+ 2026-11-11 spec drop — the on-chain counterpart to the wrapper above.
144
+ Requires the `hub` extra: `pip install "sincor-x402[hub]"`.
145
+
146
+ * **Buyer side:** `create_buyer_seal_header(...)` signs an EIP-712 SEAL
147
+ envelope (`SealAuthorization` under domain `SINCOR_SEAL` / `"1"`, nonce
148
+ read fresh from the Hub's `nonces(buyer)`) and returns it as a base64
149
+ X-PAYMENT header, scheme `sincor-seal-v1`. The buyer's key stays with
150
+ the injected signer callable; the package never holds keys.
151
+ * **Settler side:** `verify_and_settle(...)` runs the package's
152
+ `Verifier` seam against the committed spec first, then submits
153
+ `verifyAndSettleSeal` through an injected relayer signer and parses the
154
+ `SealSettled` event (gross / net payout / protocol fee).
155
+ * **SIGIL canon on this path:** `keccak256(taskId ‖ canonical-JSON
156
+ output)` — the EVM-native hash, matching the Hub's own typehashes.
157
+
158
+ ### Status: the Hub is NOT deployed
159
+
160
+ The Hub contract exists today only as an unverified spec-drop draft;
161
+ **deploying it is a founder gate** and nothing here deploys anything. The
162
+ engine is proven end-to-end against a *local* test chain
163
+ (`tests/test_hub_engine.py`): a vendored test copy of the Hub + mock USDC
164
+ on eth-tester, Python-signed SEALs settling through the real Solidity
165
+ `ecrecover` path.
166
+
167
+ ### Setup step buyers must not skip: the USDC allowance
168
+
169
+ The SEAL signature alone moves **nothing** — the Hub pulls funds with
170
+ ERC-20 `transferFrom` at settlement time, and nothing is escrowed at
171
+ authorization time. Before a buyer's first settlement, the buyer must
172
+ `approve` the Hub on the USDC contract for at least the seal amount. The
173
+ engine preflights this and raises `AllowanceInsufficient` naming the exact
174
+ approval step instead of letting the settlement revert on-chain.
175
+
176
+ ### Trust model — stated plainly
177
+
178
+ The Hub **does not verify work output**: it records whatever
179
+ `sigilCommitment` the submitter hands it, and never checks the delivered
180
+ output against the seal's `expectedSchemaHash` on-chain. On-chain
181
+ `isTaskVerified` therefore proves only that a settlement was recorded
182
+ with that commitment. The enforcement layer is this engine, off-chain:
183
+ it recomputes the SIGIL commitment from the delivered result, requires
184
+ the seal's `expectedSchemaHash` to equal the committed spec hash, runs
185
+ the `Verifier`, and **refuses to submit when verification fails — the Hub
186
+ is never called**. Anyone submitting directly to the Hub bypasses that
187
+ enforcement; the Hub alone is not a verification system.
188
+
189
+ ### Fee canon
190
+
191
+ The locked SINCOR platform fee is **5% (500 bps)**. The spec-drop draft
192
+ hardcodes 100 bps — a known defect. The vendored test copy under
193
+ `tests/fixtures/` sets `protocolFeeBps = 500` (change recorded in its
194
+ header), and the chain tests assert the canon split on-chain: provider
195
+ 95% / treasury 5%.
196
+
197
+ Lower effective rates exist only as negotiated enterprise/volume
198
+ arrangements applied at the platform layer — never as a different code
199
+ or docs default. The default in this package's code, tests, and docs is
200
+ 500 bps.
201
+
202
+ ## Plugging in real SIGIL / SEAL / facilitator services
203
+
204
+ Three protocols, three seams — implement one method each and pass the
205
+ object in (`verifier=`, `platform=`, `facilitator=`):
206
+
207
+ * `Verifier.verify(*, spec, spec_hash, result)` — judge a delivered result
208
+ against the spec committed before payment; fail closed if
209
+ `sha256(spec) != spec_hash`. A SIGIL service client drops in here.
210
+ * `PlatformClient.open_escrow / release / refund` — the SEAL settlement
211
+ surface. `LocalReferencePlatform` is an in-memory ledger with
212
+ settle-exactly-once semantics; a production client implements the same
213
+ protocol against the real platform when its endpoint ships.
214
+ * `FacilitatorClient.verify_and_hold(*, payment_payload, requirement)` —
215
+ x402 facilitator verification (e.g. Coinbase CDP). `LocalFacilitator`
216
+ checks structure only; it does not verify EIP-712 signatures or touch a
217
+ chain, and is labelled accordingly.
218
+
219
+ ## Tests
220
+
221
+ ```bash
222
+ pip install pytest && python -m pytest # 46 tests, no network
223
+ ```
224
+
225
+ Full loop with mocked platform + mocked facilitator: good result →
226
+ release; garbage → refund; timeout → refund; exception → refund; 40× retry
227
+ storms → exactly one payment; accepts[] rewrite attacks → rejected. Plus
228
+ the Hub engine's cross-implementation suite (needs the `dev` extra:
229
+ web3 + eth-tester + py-solc-x): Python-signed SEALs settling through the
230
+ compiled Solidity Hub on a local chain — canon 95/5 fee split,
231
+ `isTaskVerified`, and the Hub's own reverts (wrong signer →
232
+ `InvalidSealSignature`, expired → `SealExpired`, replay → `InvalidNonce`),
233
+ with the engine-refusal and allowance-preflight paths proven to never
234
+ reach the chain.
235
+
236
+ ## PyPI publish checklist (founder gate — do NOT publish without sign-off)
237
+
238
+ - [ ] Founder approves publishing under the `sincor-x402` name
239
+ - [ ] Confirm PyPI name availability / claim the name (and `sincor-mcp` if used)
240
+ - [ ] Bump `version` in `pyproject.toml`; tag the release commit
241
+ - [ ] `python -m build` → inspect sdist + wheel contents (no stray files)
242
+ - [ ] Upload to TestPyPI first; install from TestPyPI in a clean venv; run tests
243
+ - [ ] Verify README renders on the PyPI project page (honesty section intact)
244
+ - [ ] Publish to PyPI via a project-scoped API token stored in the vault —
245
+ never a password, never a token in the repo
246
+ - [ ] Post-publish: `pip install sincor-x402` in a clean venv and smoke-test
247
+ the 2-line server + MCP examples from this README
248
+
249
+ ## License
250
+
251
+ Apache-2.0 (declared in `pyproject.toml`).
@@ -0,0 +1,225 @@
1
+ # sincor-x402 — Verified x402 + MCP wrapper
2
+
3
+ **"Pay-and-pray" is the gap.** Coinbase's x402 lets an agent pay USDC to an
4
+ endpoint up front — with no escrow, no committed spec, and no guarantee the
5
+ seller won't return garbage or time out after taking the funds. `sincor-x402`
6
+ wraps any x402 endpoint or MCP tool in the missing piece:
7
+
8
+ ```
9
+ request → HTTP 402 (escrow terms + committed spec hash)
10
+ → payment verified → funds held in escrow
11
+ → work executes (timeout-bounded)
12
+ → result verified against the committed spec (SIGIL-style commitment)
13
+ → SEAL release on pass · refund on fail or timeout
14
+ ```
15
+
16
+ ## Honesty first — what is real and what is not
17
+
18
+ * **Live on getsincor.com today:** CNP task bidding/auctions, pool
19
+ settlement, and KYA, plus the platform's own x402 seller/buyer code this
20
+ package's wire shapes are modelled on.
21
+ * **Integration-pilot framing:** SEAL (EIP-712 settlement) and SIGIL
22
+ (verification) are the platform concepts this wrapper's interfaces are
23
+ shaped around. This package implements them as **pluggable interfaces
24
+ with labelled local reference implementations** (`LocalReferencePlatform`,
25
+ `LocalFacilitator`, `ReferenceVerifier`). They do NOT talk to a live
26
+ SIGIL service or a production escrow endpoint — none is wired yet.
27
+ * **No SINCOR escrow contract is deployed on Base mainnet.** Nothing in
28
+ this package moves real funds. Do not represent it otherwise.
29
+
30
+ ## Networks & constants
31
+
32
+ * **Base mainnet:** chain ID **8453**
33
+ * **Base Sepolia:** chain ID **84532** — testnet rehearsal only
34
+ * **USDC on Base:** `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913`
35
+ * **Live agent card:** https://getsincor.com/.well-known/agent-card.json
36
+
37
+ Nothing in this package is deployed on either network — these are the
38
+ chain IDs and contract constants the wire shapes and the Hub engine are
39
+ written against, not live deployments.
40
+
41
+ ## Install
42
+
43
+ ```bash
44
+ pip install sincor-x402 # core: zero dependencies, stdlib only
45
+ pip install "sincor-x402[fastapi]" # + the FastAPI adapter
46
+ ```
47
+
48
+ ## Server: wrap an endpoint (2 lines)
49
+
50
+ ```python
51
+ from sincor_x402 import VerifiedEndpoint, PaymentRequirement
52
+ endpoint = VerifiedEndpoint(summarize, requirement=REQ, spec={"required_keys": ["summary"]})
53
+ ```
54
+
55
+ `REQ` is your price/terms (`PaymentRequirement(scheme="exact", network="base",
56
+ max_amount_required="10000", asset=<USDC on Base>, pay_to=<your address>,
57
+ max_timeout_seconds=60)`). Feed requests to `endpoint.handle(headers=..., kwargs=...)`:
58
+ no payment header → a 402 challenge carrying your `accepts[]` + escrow terms;
59
+ a paid request runs the full escrow → execute → verify → release/refund loop.
60
+
61
+ With FastAPI (`sincor-x402[fastapi]`):
62
+
63
+ ```python
64
+ from sincor_x402.fastapi_adapter import sincor_verified
65
+ @app.post("/summarize")
66
+ @sincor_verified(requirement=REQ, spec={"required_keys": ["summary"]})
67
+ def summarize(payload: dict): ...
68
+ ```
69
+
70
+ ## MCP: wrap a tool (2 lines)
71
+
72
+ ```python
73
+ from sincor_x402 import verified_tool
74
+ @verified_tool(requirement=REQ, spec={"required_keys": ["answer"]})
75
+ def lookup(symbol: str): ...
76
+ ```
77
+
78
+ No MCP SDK is imported or required: the wrapped tool exposes
79
+ `tool_definition()` (an MCP `tools/list`-shaped descriptor) and
80
+ `call_paid(payment_header=..., **kwargs)` for your host's `tools/call`
81
+ handler, plus a best-effort `register(server)` for FastMCP-style hosts.
82
+
83
+ ## Buyer: pay a wrapped endpoint — exactly once per instruction
84
+
85
+ ```python
86
+ from sincor_x402 import VerifiedBuyer
87
+ buyer = VerifiedBuyer(wallet_address, signer_fn) # signer is injected; keys never enter this package
88
+ out = buyer.fetch(url, instruction_id="job-123", body={"q": "..."})
89
+ ```
90
+
91
+ * **Instruction-scoped idempotency:** `instruction_id` is your unit of work.
92
+ Re-calling `fetch` with the same id and the same request returns the
93
+ recorded outcome and **never signs a second payment** — a historical x402
94
+ retry bug produced 40 payments for one request; the journal + same-payload
95
+ resend design here makes that impossible (covered by a 40× retry-storm test).
96
+ Reusing an id with a *different* request raises `IdempotencyConflict`.
97
+ * **Per-payee velocity cap:** distinct instructions to one `payTo` are
98
+ capped by count and total amount per sliding window (`VelocityCap`),
99
+ checked **before** signing, so a capped attempt creates no payment.
100
+ * **No blind retries:** an ambiguous paid response raises `AmbiguousPayment`
101
+ and locks the instruction rather than risking a double-pay.
102
+ * **Per-call cap:** challenges above `max_payment_usd` are refused unsigned.
103
+
104
+ ## Server safety: the accepts[] hedge
105
+
106
+ A client echoes the terms it "accepted" inside its payment payload — and a
107
+ buggy or malicious client can rewrite them (lower price, swapped `payTo`).
108
+ This server **never trusts the client's copy**: it matches the claim against
109
+ its own retained `accepts[]` entry on scheme, network, amount, asset,
110
+ payTo, and timeout, rejects mismatches before the facilitator is touched,
111
+ and passes **its own** `PaymentRequirement` object to the facilitator.
112
+ Price-rewrite and payTo-swap attacks have dedicated negative tests.
113
+
114
+ ## Hub settlement engine (`sincor_x402.hub_engine`)
115
+
116
+ A client for the **SincorSettlementHub** contract interface from the
117
+ 2026-11-11 spec drop — the on-chain counterpart to the wrapper above.
118
+ Requires the `hub` extra: `pip install "sincor-x402[hub]"`.
119
+
120
+ * **Buyer side:** `create_buyer_seal_header(...)` signs an EIP-712 SEAL
121
+ envelope (`SealAuthorization` under domain `SINCOR_SEAL` / `"1"`, nonce
122
+ read fresh from the Hub's `nonces(buyer)`) and returns it as a base64
123
+ X-PAYMENT header, scheme `sincor-seal-v1`. The buyer's key stays with
124
+ the injected signer callable; the package never holds keys.
125
+ * **Settler side:** `verify_and_settle(...)` runs the package's
126
+ `Verifier` seam against the committed spec first, then submits
127
+ `verifyAndSettleSeal` through an injected relayer signer and parses the
128
+ `SealSettled` event (gross / net payout / protocol fee).
129
+ * **SIGIL canon on this path:** `keccak256(taskId ‖ canonical-JSON
130
+ output)` — the EVM-native hash, matching the Hub's own typehashes.
131
+
132
+ ### Status: the Hub is NOT deployed
133
+
134
+ The Hub contract exists today only as an unverified spec-drop draft;
135
+ **deploying it is a founder gate** and nothing here deploys anything. The
136
+ engine is proven end-to-end against a *local* test chain
137
+ (`tests/test_hub_engine.py`): a vendored test copy of the Hub + mock USDC
138
+ on eth-tester, Python-signed SEALs settling through the real Solidity
139
+ `ecrecover` path.
140
+
141
+ ### Setup step buyers must not skip: the USDC allowance
142
+
143
+ The SEAL signature alone moves **nothing** — the Hub pulls funds with
144
+ ERC-20 `transferFrom` at settlement time, and nothing is escrowed at
145
+ authorization time. Before a buyer's first settlement, the buyer must
146
+ `approve` the Hub on the USDC contract for at least the seal amount. The
147
+ engine preflights this and raises `AllowanceInsufficient` naming the exact
148
+ approval step instead of letting the settlement revert on-chain.
149
+
150
+ ### Trust model — stated plainly
151
+
152
+ The Hub **does not verify work output**: it records whatever
153
+ `sigilCommitment` the submitter hands it, and never checks the delivered
154
+ output against the seal's `expectedSchemaHash` on-chain. On-chain
155
+ `isTaskVerified` therefore proves only that a settlement was recorded
156
+ with that commitment. The enforcement layer is this engine, off-chain:
157
+ it recomputes the SIGIL commitment from the delivered result, requires
158
+ the seal's `expectedSchemaHash` to equal the committed spec hash, runs
159
+ the `Verifier`, and **refuses to submit when verification fails — the Hub
160
+ is never called**. Anyone submitting directly to the Hub bypasses that
161
+ enforcement; the Hub alone is not a verification system.
162
+
163
+ ### Fee canon
164
+
165
+ The locked SINCOR platform fee is **5% (500 bps)**. The spec-drop draft
166
+ hardcodes 100 bps — a known defect. The vendored test copy under
167
+ `tests/fixtures/` sets `protocolFeeBps = 500` (change recorded in its
168
+ header), and the chain tests assert the canon split on-chain: provider
169
+ 95% / treasury 5%.
170
+
171
+ Lower effective rates exist only as negotiated enterprise/volume
172
+ arrangements applied at the platform layer — never as a different code
173
+ or docs default. The default in this package's code, tests, and docs is
174
+ 500 bps.
175
+
176
+ ## Plugging in real SIGIL / SEAL / facilitator services
177
+
178
+ Three protocols, three seams — implement one method each and pass the
179
+ object in (`verifier=`, `platform=`, `facilitator=`):
180
+
181
+ * `Verifier.verify(*, spec, spec_hash, result)` — judge a delivered result
182
+ against the spec committed before payment; fail closed if
183
+ `sha256(spec) != spec_hash`. A SIGIL service client drops in here.
184
+ * `PlatformClient.open_escrow / release / refund` — the SEAL settlement
185
+ surface. `LocalReferencePlatform` is an in-memory ledger with
186
+ settle-exactly-once semantics; a production client implements the same
187
+ protocol against the real platform when its endpoint ships.
188
+ * `FacilitatorClient.verify_and_hold(*, payment_payload, requirement)` —
189
+ x402 facilitator verification (e.g. Coinbase CDP). `LocalFacilitator`
190
+ checks structure only; it does not verify EIP-712 signatures or touch a
191
+ chain, and is labelled accordingly.
192
+
193
+ ## Tests
194
+
195
+ ```bash
196
+ pip install pytest && python -m pytest # 46 tests, no network
197
+ ```
198
+
199
+ Full loop with mocked platform + mocked facilitator: good result →
200
+ release; garbage → refund; timeout → refund; exception → refund; 40× retry
201
+ storms → exactly one payment; accepts[] rewrite attacks → rejected. Plus
202
+ the Hub engine's cross-implementation suite (needs the `dev` extra:
203
+ web3 + eth-tester + py-solc-x): Python-signed SEALs settling through the
204
+ compiled Solidity Hub on a local chain — canon 95/5 fee split,
205
+ `isTaskVerified`, and the Hub's own reverts (wrong signer →
206
+ `InvalidSealSignature`, expired → `SealExpired`, replay → `InvalidNonce`),
207
+ with the engine-refusal and allowance-preflight paths proven to never
208
+ reach the chain.
209
+
210
+ ## PyPI publish checklist (founder gate — do NOT publish without sign-off)
211
+
212
+ - [ ] Founder approves publishing under the `sincor-x402` name
213
+ - [ ] Confirm PyPI name availability / claim the name (and `sincor-mcp` if used)
214
+ - [ ] Bump `version` in `pyproject.toml`; tag the release commit
215
+ - [ ] `python -m build` → inspect sdist + wheel contents (no stray files)
216
+ - [ ] Upload to TestPyPI first; install from TestPyPI in a clean venv; run tests
217
+ - [ ] Verify README renders on the PyPI project page (honesty section intact)
218
+ - [ ] Publish to PyPI via a project-scoped API token stored in the vault —
219
+ never a password, never a token in the repo
220
+ - [ ] Post-publish: `pip install sincor-x402` in a clean venv and smoke-test
221
+ the 2-line server + MCP examples from this README
222
+
223
+ ## License
224
+
225
+ Apache-2.0 (declared in `pyproject.toml`).
@@ -0,0 +1,32 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "sincor-x402"
7
+ version = "0.1.0"
8
+ description = "Verified x402 + MCP wrapper: escrowed, SIGIL-committed settlement for x402 endpoints and MCP tools (reference implementation — see README honesty notes)"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = { text = "Apache-2.0" }
12
+ authors = [{ name = "SINCOR Business Solutions" }]
13
+ keywords = ["x402", "mcp", "escrow", "agent-payments", "base"]
14
+ dependencies = []
15
+
16
+ [project.urls]
17
+ Homepage = "https://getsincor.com"
18
+ Repository = "https://github.com/OrderofChaos33/SINCOR2"
19
+ AgentCard = "https://getsincor.com/.well-known/agent-card.json"
20
+
21
+ [project.optional-dependencies]
22
+ fastapi = ["fastapi>=0.110"]
23
+ hub = ["web3>=6.15", "eth-account>=0.11", "eth-utils>=4"]
24
+ dev = ["pytest>=8", "web3>=6.15", "eth-account>=0.11", "eth-utils>=4",
25
+ "eth-tester>=0.13", "py-solc-x>=1.1"]
26
+
27
+ [tool.setuptools.packages.find]
28
+ where = ["src"]
29
+
30
+ [tool.pytest.ini_options]
31
+ testpaths = ["tests"]
32
+ pythonpath = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,42 @@
1
+ """sincor-x402 — Verified x402 + MCP wrapper (reference implementation).
2
+
3
+ Turns a plain function, FastAPI endpoint, or MCP tool into an escrowed,
4
+ SIGIL-committed, SEAL-settled paid call: 402 → escrow → verify → release,
5
+ refund on fail/timeout. See README.md for the honesty notes: escrow here
6
+ runs through a pluggable PlatformClient whose only implementation in this
7
+ package is a labelled local reference; no Base-mainnet contract is
8
+ deployed by this package.
9
+ """
10
+ from .buyer import VerifiedBuyer, VelocityCap
11
+ from .errors import (AcceptsMismatch, AllowanceInsufficient, AmbiguousPayment,
12
+ EscrowTimeout, IdempotencyConflict, MalformedChallenge,
13
+ PaymentCapExceeded, SettlementReverted, SincorX402Error,
14
+ UnsupportedPayment, VelocityCapExceeded, VerificationFailed)
15
+ from .facilitator import FacilitatorClient, FacilitatorResult, LocalFacilitator
16
+ from .hub_engine import (SEAL_SCHEME, HubSettlementEngine,
17
+ HubSettlementReceipt, SealEnvelope,
18
+ compute_sigil_commitment, to_bytes32)
19
+ from .mcp_adapter import VerifiedTool, verified_tool
20
+ from .platform import EscrowRecord, LocalReferencePlatform, PlatformClient
21
+ from .server import HandlerResponse, VerifiedEndpoint, verified_function
22
+ from .types import (USDC_BASE_ADDRESS, EscrowTerms, PaymentRequirement,
23
+ sha256_hex)
24
+ from .verifier import ReferenceVerifier, VerificationResult, Verifier
25
+
26
+ __version__ = "0.1.0"
27
+
28
+ __all__ = [
29
+ "VerifiedEndpoint", "verified_function", "HandlerResponse",
30
+ "VerifiedTool", "verified_tool",
31
+ "VerifiedBuyer", "VelocityCap",
32
+ "PaymentRequirement", "EscrowTerms", "USDC_BASE_ADDRESS", "sha256_hex",
33
+ "PlatformClient", "LocalReferencePlatform", "EscrowRecord",
34
+ "FacilitatorClient", "LocalFacilitator", "FacilitatorResult",
35
+ "Verifier", "ReferenceVerifier", "VerificationResult",
36
+ "HubSettlementEngine", "HubSettlementReceipt", "SealEnvelope",
37
+ "SEAL_SCHEME", "compute_sigil_commitment", "to_bytes32",
38
+ "SincorX402Error", "PaymentCapExceeded", "UnsupportedPayment",
39
+ "MalformedChallenge", "AmbiguousPayment", "IdempotencyConflict",
40
+ "VelocityCapExceeded", "AcceptsMismatch", "VerificationFailed",
41
+ "EscrowTimeout", "AllowanceInsufficient", "SettlementReverted",
42
+ ]