jcp-x402: demonstrate the settlement coupling in the runnable example #25
1 changed files with 37 additions and 2 deletions
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
use ed25519_dalek::SigningKey;
|
||||
use jcp_schema::{Did, Funds, Verdict};
|
||||
use jcp_x402::{ingest_requirements, Gated, X402Profile, X402Requirements};
|
||||
use jcp_x402::{ingest_requirements, Gated, X402Profile, X402Requirements, X402Settlement};
|
||||
use serde_json::json;
|
||||
|
||||
fn main() {
|
||||
|
|
@ -64,7 +64,42 @@ fn main() {
|
|||
let eurc = X402Requirements { asset: "EURC".into(), max_amount: 100, ..req.clone() };
|
||||
println!("charge in EURC (grant is USDC) → {}", verdict(&profile.authorize(&eurc, 1)));
|
||||
|
||||
// 6. Every decision sealed a JCR-1 receipt that verifies under the steward
|
||||
// 6. THE COUPLING. The host settles the authorized charge on chain and gets
|
||||
// back a transaction; the meter reports what the paid compute actually
|
||||
// consumed. Sealing them together produces the artifact neither side has:
|
||||
// the payment rail knows the transaction but not the energy, an energy
|
||||
// meter knows the joules but not the transaction.
|
||||
let settled = X402Settlement {
|
||||
transaction: Some("0xdeadbeefcafe".into()),
|
||||
network: "base".into(),
|
||||
payer: Some("0xAgentWallet".into()),
|
||||
};
|
||||
let measured_uj = 5_812; // what the meter read, not the 6000 µJ estimate
|
||||
let g = profile.seal_settlement(&req, &settled, measured_uj);
|
||||
println!("\nsettled {} → sealed {}", settled.transaction.as_deref().unwrap_or("-"), verdict(&g));
|
||||
|
||||
// A third party verifies the binding without trusting the gateway: it
|
||||
// recomputes the coupling id from the settlement record it holds and
|
||||
// checks it against the receipt's payload_hash (jcp/2, SPEC §8).
|
||||
let core = jcp_receipt::extract(&g.receipt, profile.steward(), &profile.steward_pubkey())
|
||||
.expect("settlement receipt verifies");
|
||||
let expected = settled.coupling_id(&req.resource, measured_uj).to_hex();
|
||||
println!(
|
||||
" coupling verified: {} (tx + {} µJ bound into payload_hash {}…)",
|
||||
core.payload_hash.as_deref() == Some(expected.as_str()),
|
||||
measured_uj,
|
||||
&expected[..16]
|
||||
);
|
||||
|
||||
// Re-pointing the receipt at a different transaction — or a different
|
||||
// energy figure — yields a different id, so the binding cannot be moved.
|
||||
let other = X402Settlement { transaction: Some("0xfeed".into()), ..settled.clone() };
|
||||
println!(
|
||||
" re-point to another tx → id matches: {}",
|
||||
core.payload_hash.as_deref() == Some(other.coupling_id(&req.resource, measured_uj).to_hex().as_str())
|
||||
);
|
||||
|
||||
// 7. Every decision sealed a JCR-1 receipt that verifies under the steward
|
||||
// key — a third party trusts the decision, not the gateway.
|
||||
let steward = profile.steward().to_string();
|
||||
let pk = profile.steward_pubkey();
|
||||
|
|
|
|||
Loading…
Reference in a new issue