arc-builder-kit 0.2.0__py3-none-any.whl
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.
- arc_builder_kit/__init__.py +4 -0
- arc_builder_kit/__main__.py +6 -0
- arc_builder_kit/_paths.py +47 -0
- arc_builder_kit/cli.py +277 -0
- arc_builder_kit/config/arc_testnet.facts.json +31 -0
- arc_builder_kit/doctor.py +936 -0
- arc_builder_kit/examples/agent-commerce-components/components.js +200 -0
- arc_builder_kit/examples/agent-commerce-components/index.html +120 -0
- arc_builder_kit/examples/agent-commerce-flows/flows.js +271 -0
- arc_builder_kit/examples/agent-commerce-flows/index.html +114 -0
- arc_builder_kit/examples/agent-commerce-live/commerce-live.js +190 -0
- arc_builder_kit/examples/agent-commerce-live/index.html +105 -0
- arc_builder_kit/examples/agent-commerce-review-packet/index.html +96 -0
- arc_builder_kit/examples/agent-commerce-review-packet/packet.js +125 -0
- arc_builder_kit/examples/agent-identity-profile-preview/identity.js +126 -0
- arc_builder_kit/examples/agent-identity-profile-preview/index.html +104 -0
- arc_builder_kit/examples/arc-agent-treasury-lab/index.html +152 -0
- arc_builder_kit/examples/arc-agent-treasury-lab/treasury.js +532 -0
- arc_builder_kit/examples/arc-testnet-operator-evidence/evidence.example.json +47 -0
- arc_builder_kit/examples/arc-testnet-wallet-send-gate/index.html +233 -0
- arc_builder_kit/examples/arc-testnet-wallet-send-gate/live-infrastructure-policy.example.json +59 -0
- arc_builder_kit/examples/arc-testnet-wallet-send-gate/wallet-send-gate.js +472 -0
- arc_builder_kit/examples/circle-wallet-integration/index.html +155 -0
- arc_builder_kit/examples/circle-wallet-integration/wallet-lab.js +91 -0
- arc_builder_kit/examples/job-escrow-simulator/index.html +121 -0
- arc_builder_kit/examples/job-escrow-simulator/simulator.js +162 -0
- arc_builder_kit/examples/payment-intent-demo/index.html +132 -0
- arc_builder_kit/examples/payment-intent-playground/index.html +301 -0
- arc_builder_kit/examples/payment-intent-playground/playground.js +835 -0
- arc_builder_kit/examples/payment-intent-receipt-matcher/index.html +157 -0
- arc_builder_kit/examples/payment-intent-receipt-matcher/matcher.js +877 -0
- arc_builder_kit/examples/receipt-verifier-playground/index.html +120 -0
- arc_builder_kit/examples/receipt-verifier-playground/verifier.js +226 -0
- arc_builder_kit/examples/receipt-viewer/index.html +138 -0
- arc_builder_kit/examples/receipt-viewer/receipt-viewer.js +472 -0
- arc_builder_kit/examples/transaction-status-playground/index.html +135 -0
- arc_builder_kit/examples/transaction-status-playground/status.js +518 -0
- arc_builder_kit/examples/x402-local-challenge-server/.env.example +25 -0
- arc_builder_kit/examples/x402-local-challenge-server/README.md +111 -0
- arc_builder_kit/examples/x402-local-challenge-server/server.py +711 -0
- arc_builder_kit/mcp_server.py +463 -0
- arc_builder_kit/release_packet.py +469 -0
- arc_builder_kit/templates/README.md +25 -0
- arc_builder_kit/templates/job-escrow-starter/README.md +25 -0
- arc_builder_kit/templates/job-escrow-starter/index.html +41 -0
- arc_builder_kit/templates/job-escrow-starter/index.js +14 -0
- arc_builder_kit/templates/payment-intent-starter/README.md +25 -0
- arc_builder_kit/templates/payment-intent-starter/index.html +42 -0
- arc_builder_kit/templates/payment-intent-starter/index.js +7 -0
- arc_builder_kit/templates/x402-agent-starter/README.md +29 -0
- arc_builder_kit/templates/x402-agent-starter/server.py +201 -0
- arc_builder_kit/validate_repo.py +2212 -0
- arc_builder_kit-0.2.0.dist-info/METADATA +543 -0
- arc_builder_kit-0.2.0.dist-info/RECORD +58 -0
- arc_builder_kit-0.2.0.dist-info/WHEEL +5 -0
- arc_builder_kit-0.2.0.dist-info/entry_points.txt +3 -0
- arc_builder_kit-0.2.0.dist-info/licenses/LICENSE +21 -0
- arc_builder_kit-0.2.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// Circle wallet integration lab — local-only preview, no network calls.
|
|
2
|
+
// This page does NOT connect to Circle, RPC, or any external service.
|
|
3
|
+
// Use the `circle` CLI for live operations.
|
|
4
|
+
|
|
5
|
+
const ARC_TESTNET_CHAIN_ID = 5042002;
|
|
6
|
+
const ARC_TESTNET_CHAIN_HEX = "0x4cef52";
|
|
7
|
+
const ARC_TESTNET_USDC = "0x3600000000000000000000000000000000000000";
|
|
8
|
+
const GATEWAY_DOMAIN_ARC = 26;
|
|
9
|
+
|
|
10
|
+
const circleWalletLab = {
|
|
11
|
+
// Static preview data — replace with CLI output when running locally.
|
|
12
|
+
walletAddress: "0x0cd9b933302d90bfe295471deac7f4eafd9ea401",
|
|
13
|
+
session: "testnet",
|
|
14
|
+
balances: {
|
|
15
|
+
usdcErc20: "19",
|
|
16
|
+
usdcNative: "19.99",
|
|
17
|
+
},
|
|
18
|
+
network: {
|
|
19
|
+
name: "Arc Testnet",
|
|
20
|
+
chainId: ARC_TESTNET_CHAIN_ID,
|
|
21
|
+
chainIdHex: ARC_TESTNET_CHAIN_HEX,
|
|
22
|
+
usdcContract: ARC_TESTNET_USDC,
|
|
23
|
+
gatewayDomain: GATEWAY_DOMAIN_ARC,
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
function shortAddr(addr) {
|
|
28
|
+
if (!addr || addr.length < 10) return addr;
|
|
29
|
+
return addr.slice(0, 6) + "…" + addr.slice(-4);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function renderStatus() {
|
|
33
|
+
const el = document.getElementById("wallet-status");
|
|
34
|
+
if (el) {
|
|
35
|
+
el.textContent = "Session: " + circleWalletLab.session + " (preview)";
|
|
36
|
+
}
|
|
37
|
+
const sessEl = document.getElementById("wallet-session");
|
|
38
|
+
if (sessEl) {
|
|
39
|
+
sessEl.textContent = circleWalletLab.session;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function renderAddress() {
|
|
44
|
+
const el = document.getElementById("wallet-address");
|
|
45
|
+
if (el) {
|
|
46
|
+
el.textContent = shortAddr(circleWalletLab.walletAddress);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function renderBalance() {
|
|
51
|
+
const erc20 = document.getElementById("wallet-balance-erc20");
|
|
52
|
+
if (erc20) {
|
|
53
|
+
erc20.textContent = circleWalletLab.balances.usdcErc20 + " USDC (6 dec)";
|
|
54
|
+
}
|
|
55
|
+
const native = document.getElementById("wallet-balance-native");
|
|
56
|
+
if (native) {
|
|
57
|
+
native.textContent = circleWalletLab.balances.usdcNative + " USDC (18 dec)";
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function renderAll() {
|
|
62
|
+
renderStatus();
|
|
63
|
+
renderAddress();
|
|
64
|
+
renderBalance();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
document.addEventListener("DOMContentLoaded", function () {
|
|
68
|
+
renderAll();
|
|
69
|
+
|
|
70
|
+
const refreshBtn = document.getElementById("refresh-preview");
|
|
71
|
+
if (refreshBtn) {
|
|
72
|
+
refreshBtn.addEventListener("click", function () {
|
|
73
|
+
renderAll();
|
|
74
|
+
refreshBtn.textContent = "Preview refreshed";
|
|
75
|
+
setTimeout(function () {
|
|
76
|
+
refreshBtn.textContent = "Refresh preview";
|
|
77
|
+
}, 1500);
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const cliBtn = document.getElementById("show-cli");
|
|
82
|
+
if (cliBtn) {
|
|
83
|
+
cliBtn.addEventListener("click", function () {
|
|
84
|
+
const out = document.getElementById("cli-output");
|
|
85
|
+
if (out) {
|
|
86
|
+
out.style.display = out.style.display === "none" ? "block" : "none";
|
|
87
|
+
cliBtn.textContent = out.style.display === "none" ? "Show CLI commands" : "Hide CLI commands";
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
});
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<meta name="description" content="Local-only ERC-8183-style job escrow simulator for Arc MCP Builder Assistant." />
|
|
7
|
+
<title>Job Escrow Simulator · Arc MCP Builder Assistant</title>
|
|
8
|
+
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; object-src 'none'; base-uri 'none'; form-action 'none'; upgrade-insecure-requests" />
|
|
9
|
+
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Cdefs%3E%3ClinearGradient id='g' x1='0' y1='0' x2='1' y2='1'%3E%3Cstop offset='0' stop-color='%232563eb'/%3E%3Cstop offset='1' stop-color='%2306b6d4'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='64' height='64' rx='16' fill='url(%23g)'/%3E%3Ctext x='50%25' y='55%25' text-anchor='middle' font-family='Inter,Arial,sans-serif' font-size='38' font-weight='900' fill='white'%3EA%3C/text%3E%3C/svg%3E" />
|
|
10
|
+
<style>
|
|
11
|
+
:root { color-scheme: dark; --bg: #080a12; --panel: rgba(255,255,255,.065); --line: rgba(255,255,255,.14); --text: #f7f3ff; --muted: #bfb6d9; --accent: #7cf7d4; --accent2: #b388ff; --warn: #ffd166; --good: #7cf7a8; }
|
|
12
|
+
* { box-sizing: border-box; }
|
|
13
|
+
html { scroll-behavior: smooth; }
|
|
14
|
+
body { margin: 0; min-height: 100vh; font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; color: var(--text); background: radial-gradient(circle at 20% 0%, rgba(124,247,212,.18), transparent 32rem), radial-gradient(circle at 82% 8%, rgba(179,136,255,.2), transparent 34rem), linear-gradient(180deg, #080a12 0%, #11152a 60%, #080a12 100%); line-height: 1.65; }
|
|
15
|
+
a { color: var(--accent); text-decoration: none; }
|
|
16
|
+
a:hover { text-decoration: underline; }
|
|
17
|
+
a:focus-visible, button:focus-visible, input:focus-visible, textarea:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; }
|
|
18
|
+
.skip-link { position: absolute; left: -9999px; top: 12px; z-index: 10; padding: 10px 14px; border-radius: 999px; background: var(--accent); color: #06110d; font-weight: 900; }
|
|
19
|
+
.skip-link:focus { left: 12px; }
|
|
20
|
+
.wrap { width: min(1120px, calc(100% - 32px)); margin: 0 auto; }
|
|
21
|
+
header { padding: 26px 0 10px; }
|
|
22
|
+
.topbar, .hero, .grid, .actions { display: flex; gap: 16px; }
|
|
23
|
+
.topbar { align-items: center; justify-content: space-between; flex-wrap: wrap; }
|
|
24
|
+
.brand { color: var(--text); font-weight: 950; letter-spacing: -.02em; }
|
|
25
|
+
nav { display: flex; gap: 10px; flex-wrap: wrap; }
|
|
26
|
+
nav a, button, .button { border: 1px solid var(--line); border-radius: 999px; background: rgba(255,255,255,.055); color: var(--text); padding: 10px 14px; font-weight: 850; cursor: pointer; }
|
|
27
|
+
button.primary, .button.primary { background: var(--accent); color: #07110f; border-color: transparent; }
|
|
28
|
+
button:disabled { cursor: not-allowed; opacity: .46; }
|
|
29
|
+
.hero { padding: 34px 0 22px; align-items: stretch; }
|
|
30
|
+
.hero > * { flex: 1; min-width: 0; }
|
|
31
|
+
.eyebrow { color: var(--accent); font-size: .78rem; font-weight: 950; text-transform: uppercase; letter-spacing: .16em; }
|
|
32
|
+
h1, h2, h3 { letter-spacing: -.035em; line-height: 1.08; }
|
|
33
|
+
h1 { margin: 12px 0 14px; font-size: clamp(2.1rem, 7vw, 4.9rem); }
|
|
34
|
+
h2 { margin-top: 0; font-size: clamp(1.4rem, 3vw, 2.2rem); }
|
|
35
|
+
p, li, label { color: var(--muted); }
|
|
36
|
+
.panel { border: 1px solid var(--line); border-radius: 28px; background: linear-gradient(180deg, rgba(255,255,255,.09), var(--panel)); box-shadow: 0 24px 80px rgba(0,0,0,.34); padding: clamp(20px, 4vw, 34px); }
|
|
37
|
+
.grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: start; padding-bottom: 72px; }
|
|
38
|
+
.grid > * { min-width: 0; }
|
|
39
|
+
.actions { flex-wrap: wrap; }
|
|
40
|
+
.field { display: grid; gap: 8px; margin-bottom: 14px; }
|
|
41
|
+
input, textarea { width: 100%; border: 1px solid var(--line); border-radius: 16px; background: rgba(0,0,0,.24); color: var(--text); padding: 12px 14px; font: inherit; }
|
|
42
|
+
textarea { min-height: 92px; resize: vertical; }
|
|
43
|
+
pre { white-space: pre-wrap; word-break: break-word; overflow-x: auto; padding: 18px; border-radius: 18px; border: 1px solid var(--line); background: rgba(0,0,0,.38); color: #eafff8; }
|
|
44
|
+
code { font-family: "SFMono-Regular", Consolas, "Liberation Mono", monospace; }
|
|
45
|
+
.status { display: inline-flex; align-items: center; gap: 8px; padding: 8px 12px; border-radius: 999px; border: 1px solid rgba(124,247,212,.3); color: var(--accent); background: rgba(124,247,212,.08); font-weight: 900; }
|
|
46
|
+
.timeline { list-style: none; padding: 0; display: grid; gap: 10px; }
|
|
47
|
+
.timeline li { border-left: 3px solid var(--line); padding-left: 12px; }
|
|
48
|
+
.timeline li.done { border-color: var(--good); color: var(--text); }
|
|
49
|
+
.warning { border-color: rgba(255,209,102,.38); background: rgba(255,209,102,.08); }
|
|
50
|
+
@media (max-width: 860px) { .hero, .grid { display: grid; grid-template-columns: 1fr; } nav { display: none; } }
|
|
51
|
+
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } *, *::before, *::after { animation: none !important; transition: none !important; } }
|
|
52
|
+
</style>
|
|
53
|
+
</head>
|
|
54
|
+
<body>
|
|
55
|
+
<a class="skip-link" href="#content">Skip to content</a>
|
|
56
|
+
<header class="wrap">
|
|
57
|
+
<div class="topbar">
|
|
58
|
+
<a class="brand" href="../../">Arc MCP Builder Assistant</a>
|
|
59
|
+
<nav aria-label="Simulator navigation">
|
|
60
|
+
<a href="../../">Home</a>
|
|
61
|
+
<a href="../../docs/view.html#job-escrow-demo.md">Escrow spec</a>
|
|
62
|
+
<a href="../../docs/view.html#arc-builder-readiness-checklist.md">Readiness checklist</a>
|
|
63
|
+
<a href="../payment-intent-playground/">Payment playground</a>
|
|
64
|
+
</nav>
|
|
65
|
+
</div>
|
|
66
|
+
</header>
|
|
67
|
+
<main id="content" class="wrap">
|
|
68
|
+
<section class="hero">
|
|
69
|
+
<div>
|
|
70
|
+
<p class="eyebrow">Local-only simulator · no wallet connection</p>
|
|
71
|
+
<h1>Job escrow flow without touching funds.</h1>
|
|
72
|
+
<p>This ERC-8183-style simulator shows how a user could post a job, fund escrow, receive agent output, request changes, reject, dispute, expire, cancel, or manually approve payout. It does not connect to a wallet, broadcast transactions, or talk to any backend.</p>
|
|
73
|
+
<p class="status" id="status-pill">Draft job</p>
|
|
74
|
+
</div>
|
|
75
|
+
<div class="panel warning">
|
|
76
|
+
<h2>Safety boundary</h2>
|
|
77
|
+
<ul>
|
|
78
|
+
<li>Human keeps approval control.</li>
|
|
79
|
+
<li>Escrow funding, change requests, and payout are simulated UI states.</li>
|
|
80
|
+
<li>Rejection, dispute, expiry, and cancellation are terminal local review states with no payout release.</li>
|
|
81
|
+
<li>No private keys, no custody, no mainnet, no autonomous spending.</li>
|
|
82
|
+
<li>Reviewer changes and disputes are simulated review notes; they do not message an agent, arbitrator, validator, wallet, or backend.</li>
|
|
83
|
+
<li>Use this before adding any real Arc Testnet transaction path.</li>
|
|
84
|
+
</ul>
|
|
85
|
+
</div>
|
|
86
|
+
</section>
|
|
87
|
+
<section class="grid">
|
|
88
|
+
<div class="panel">
|
|
89
|
+
<h2>Job details</h2>
|
|
90
|
+
<div class="field"><label for="job-title">Job title</label><input id="job-title" value="Summarize Arc agent docs" /></div>
|
|
91
|
+
<div class="field"><label for="budget">Budget, USDC</label><input id="budget" type="number" min="1" step="1" value="25" /></div>
|
|
92
|
+
<div class="field"><label for="agent">Agent</label><input id="agent" value="Research Agent" /></div>
|
|
93
|
+
<div class="field"><label for="deliverable">Expected deliverable</label><textarea id="deliverable">A concise build note with cited Arc docs, open questions, and next implementation tasks.</textarea></div>
|
|
94
|
+
<div class="field"><label for="revision-note">Reviewer change request / revision note</label><textarea id="revision-note">Add a risk section before payout approval.</textarea></div>
|
|
95
|
+
<div class="field"><label for="dispute-note">Reject / dispute / close note</label><textarea id="dispute-note">Output missed acceptance criteria; keep funds unreleased in the local simulation.</textarea></div>
|
|
96
|
+
<div class="actions">
|
|
97
|
+
<button class="primary" id="post-job">Post job</button>
|
|
98
|
+
<button id="accept-job" disabled>Agent accepts</button>
|
|
99
|
+
<button id="fund-escrow" disabled>Fund escrow</button>
|
|
100
|
+
<button id="submit-work" disabled>Submit work</button>
|
|
101
|
+
<button id="request-changes" disabled>Request changes</button>
|
|
102
|
+
<button id="revise-work" disabled>Revise work</button>
|
|
103
|
+
<button id="reject-work" disabled>Reject no payout</button>
|
|
104
|
+
<button id="open-dispute" disabled>Open dispute</button>
|
|
105
|
+
<button id="expire-job" disabled>Expire job</button>
|
|
106
|
+
<button id="cancel-job" disabled>Cancel job</button>
|
|
107
|
+
<button id="approve-payout" disabled>Approve payout</button>
|
|
108
|
+
<button id="reset-flow">Reset</button>
|
|
109
|
+
</div>
|
|
110
|
+
</div>
|
|
111
|
+
<div class="panel">
|
|
112
|
+
<h2>Reviewable escrow object</h2>
|
|
113
|
+
<pre id="escrow-json"></pre>
|
|
114
|
+
<h3>Event timeline</h3>
|
|
115
|
+
<ol class="timeline" id="timeline"></ol>
|
|
116
|
+
</div>
|
|
117
|
+
</section>
|
|
118
|
+
</main>
|
|
119
|
+
<script src="./simulator.js" defer></script>
|
|
120
|
+
</body>
|
|
121
|
+
</html>
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
const stateOrder = ['draft', 'posted', 'accepted_by_agent', 'escrow_funded_simulation', 'work_submitted', 'changes_requested', 'rejected_no_payout', 'disputed_manual_review', 'expired_no_payout', 'cancelled_no_payout', 'payout_approved_simulation'];
|
|
2
|
+
const statusLabels = {
|
|
3
|
+
draft: 'Draft job',
|
|
4
|
+
posted: 'Posted for agent review',
|
|
5
|
+
accepted_by_agent: 'Accepted by agent',
|
|
6
|
+
escrow_funded_simulation: 'Escrow funded simulation',
|
|
7
|
+
work_submitted: 'Work submitted for human review',
|
|
8
|
+
changes_requested: 'Changes requested',
|
|
9
|
+
rejected_no_payout: 'Rejected without payout',
|
|
10
|
+
disputed_manual_review: 'Disputed manual review',
|
|
11
|
+
expired_no_payout: 'Expired without payout',
|
|
12
|
+
cancelled_no_payout: 'Cancelled without payout',
|
|
13
|
+
payout_approved_simulation: 'Payout approved simulation',
|
|
14
|
+
};
|
|
15
|
+
const buttons = {
|
|
16
|
+
post: document.querySelector('#post-job'),
|
|
17
|
+
accept: document.querySelector('#accept-job'),
|
|
18
|
+
fund: document.querySelector('#fund-escrow'),
|
|
19
|
+
submit: document.querySelector('#submit-work'),
|
|
20
|
+
requestChanges: document.querySelector('#request-changes'),
|
|
21
|
+
revise: document.querySelector('#revise-work'),
|
|
22
|
+
reject: document.querySelector('#reject-work'),
|
|
23
|
+
dispute: document.querySelector('#open-dispute'),
|
|
24
|
+
expire: document.querySelector('#expire-job'),
|
|
25
|
+
cancel: document.querySelector('#cancel-job'),
|
|
26
|
+
approve: document.querySelector('#approve-payout'),
|
|
27
|
+
reset: document.querySelector('#reset-flow'),
|
|
28
|
+
};
|
|
29
|
+
const fields = {
|
|
30
|
+
title: document.querySelector('#job-title'),
|
|
31
|
+
budget: document.querySelector('#budget'),
|
|
32
|
+
agent: document.querySelector('#agent'),
|
|
33
|
+
deliverable: document.querySelector('#deliverable'),
|
|
34
|
+
revisionNote: document.querySelector('#revision-note'),
|
|
35
|
+
disputeNote: document.querySelector('#dispute-note'),
|
|
36
|
+
};
|
|
37
|
+
const statusPill = document.querySelector('#status-pill');
|
|
38
|
+
const jsonPanel = document.querySelector('#escrow-json');
|
|
39
|
+
const timeline = document.querySelector('#timeline');
|
|
40
|
+
let status = 'draft';
|
|
41
|
+
let events = [];
|
|
42
|
+
let changesRequestedCount = 0;
|
|
43
|
+
|
|
44
|
+
function nowIso() {
|
|
45
|
+
return new Date().toISOString();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function budgetIsValid(value) {
|
|
49
|
+
return /^(?:0|[1-9]\d*)(?:\.\d{1,2})?$/.test(String(value || '').trim())
|
|
50
|
+
&& Number(value) > 0;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function escrowObject() {
|
|
54
|
+
return {
|
|
55
|
+
schema: 'arc-mcp-builder-assistant.jobEscrow.simulation.v1',
|
|
56
|
+
status,
|
|
57
|
+
job: {
|
|
58
|
+
title: fields.title.value.trim(),
|
|
59
|
+
budget: budgetIsValid(fields.budget.value) ? Number(fields.budget.value).toFixed(2) : '0.00',
|
|
60
|
+
asset: 'USDC',
|
|
61
|
+
chain: 'Arc Testnet later; local simulation now',
|
|
62
|
+
expectedDeliverable: fields.deliverable.value.trim(),
|
|
63
|
+
},
|
|
64
|
+
parties: {
|
|
65
|
+
requester: 'human_reviewer',
|
|
66
|
+
agent: fields.agent.value.trim(),
|
|
67
|
+
escrow: 'simulated_local_object',
|
|
68
|
+
},
|
|
69
|
+
controls: {
|
|
70
|
+
walletConnected: false,
|
|
71
|
+
walletActionEnabled: false,
|
|
72
|
+
broadcastsTransactions: false,
|
|
73
|
+
transactionBroadcast: false,
|
|
74
|
+
talksToBackend: false,
|
|
75
|
+
signingEnabled: false,
|
|
76
|
+
humanApprovalRequired: true,
|
|
77
|
+
mainnetEnabled: false,
|
|
78
|
+
localOnly: true,
|
|
79
|
+
realEscrowContract: false,
|
|
80
|
+
payoutReleased: status === 'payout_approved_simulation' ? 'simulated_only' : false,
|
|
81
|
+
terminalNoPayoutStates: ['rejected_no_payout', 'disputed_manual_review', 'expired_no_payout', 'cancelled_no_payout'],
|
|
82
|
+
contactsArbitrator: false,
|
|
83
|
+
contactsValidator: false,
|
|
84
|
+
arcTestnetChainId: 5042002,
|
|
85
|
+
arcTestnetChainIdHex: '0x4cef52',
|
|
86
|
+
},
|
|
87
|
+
review: {
|
|
88
|
+
changesRequestedCount,
|
|
89
|
+
latestRevisionNote: fields.revisionNote.value.trim(),
|
|
90
|
+
latestCloseNote: fields.disputeNote.value.trim(),
|
|
91
|
+
terminalStateRequiresNewJob: ['rejected_no_payout', 'disputed_manual_review', 'expired_no_payout', 'cancelled_no_payout'].includes(status),
|
|
92
|
+
payoutRelease: 'simulated_only_after_human_approval',
|
|
93
|
+
agentOutputTrustedOnlyAfterReview: true,
|
|
94
|
+
},
|
|
95
|
+
events,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function addEvent(label) {
|
|
100
|
+
events = [...events, { at: nowIso(), label, status }];
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function setStatus(nextStatus, label) {
|
|
104
|
+
if (nextStatus === 'changes_requested') {
|
|
105
|
+
changesRequestedCount += 1;
|
|
106
|
+
}
|
|
107
|
+
status = nextStatus;
|
|
108
|
+
addEvent(label || statusLabels[nextStatus]);
|
|
109
|
+
render();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function render() {
|
|
113
|
+
const currentIndex = stateOrder.indexOf(status);
|
|
114
|
+
statusPill.textContent = statusLabels[status];
|
|
115
|
+
jsonPanel.textContent = JSON.stringify(escrowObject(), null, 2);
|
|
116
|
+
timeline.replaceChildren(...events.map((event) => {
|
|
117
|
+
const li = document.createElement('li');
|
|
118
|
+
li.className = stateOrder.indexOf(event.status) <= currentIndex ? 'done' : '';
|
|
119
|
+
li.textContent = `${event.label} · ${event.at}`;
|
|
120
|
+
return li;
|
|
121
|
+
}));
|
|
122
|
+
const termsFrozen = status !== 'draft';
|
|
123
|
+
for (const field of [fields.title, fields.budget, fields.agent, fields.deliverable]) {
|
|
124
|
+
field.disabled = termsFrozen;
|
|
125
|
+
}
|
|
126
|
+
buttons.post.disabled = status !== 'draft' || !budgetIsValid(fields.budget.value);
|
|
127
|
+
buttons.accept.disabled = status !== 'posted';
|
|
128
|
+
buttons.fund.disabled = status !== 'accepted_by_agent';
|
|
129
|
+
buttons.submit.disabled = status !== 'escrow_funded_simulation';
|
|
130
|
+
buttons.requestChanges.disabled = status !== 'work_submitted';
|
|
131
|
+
buttons.revise.disabled = status !== 'changes_requested';
|
|
132
|
+
buttons.reject.disabled = status !== 'work_submitted';
|
|
133
|
+
buttons.dispute.disabled = !['work_submitted', 'changes_requested'].includes(status);
|
|
134
|
+
buttons.expire.disabled = !['posted', 'accepted_by_agent', 'escrow_funded_simulation', 'changes_requested'].includes(status);
|
|
135
|
+
buttons.cancel.disabled = !['draft', 'posted', 'accepted_by_agent'].includes(status);
|
|
136
|
+
buttons.approve.disabled = status !== 'work_submitted';
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function reset() {
|
|
140
|
+
status = 'draft';
|
|
141
|
+
changesRequestedCount = 0;
|
|
142
|
+
fields.disputeNote.value = 'Output missed acceptance criteria; keep funds unreleased in the local simulation.';
|
|
143
|
+
events = [{ at: nowIso(), label: 'Draft created locally', status }];
|
|
144
|
+
render();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
buttons.post.addEventListener('click', () => setStatus('posted', 'Human posted the job for agent review'));
|
|
148
|
+
buttons.accept.addEventListener('click', () => setStatus('accepted_by_agent', 'Agent accepted the job terms'));
|
|
149
|
+
buttons.fund.addEventListener('click', () => setStatus('escrow_funded_simulation', 'Human simulated funding escrow'));
|
|
150
|
+
buttons.submit.addEventListener('click', () => setStatus('work_submitted', 'Agent submitted the deliverable for review'));
|
|
151
|
+
buttons.requestChanges.addEventListener('click', () => setStatus('changes_requested', 'Reviewer requested changes before payout approval'));
|
|
152
|
+
buttons.revise.addEventListener('click', () => setStatus('work_submitted', 'Agent resubmitted revised work for review'));
|
|
153
|
+
buttons.reject.addEventListener('click', () => setStatus('rejected_no_payout', 'Reviewer rejected the work; no payout released'));
|
|
154
|
+
buttons.dispute.addEventListener('click', () => setStatus('disputed_manual_review', 'Reviewer opened a manual dispute; no payout released'));
|
|
155
|
+
buttons.expire.addEventListener('click', () => setStatus('expired_no_payout', 'Job expired locally; no payout released'));
|
|
156
|
+
buttons.cancel.addEventListener('click', () => setStatus('cancelled_no_payout', 'Human cancelled the job locally; no payout released'));
|
|
157
|
+
buttons.approve.addEventListener('click', () => setStatus('payout_approved_simulation', 'Human approved simulated payout release'));
|
|
158
|
+
buttons.reset.addEventListener('click', reset);
|
|
159
|
+
for (const field of Object.values(fields)) {
|
|
160
|
+
field.addEventListener('input', render);
|
|
161
|
+
}
|
|
162
|
+
reset();
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>Arc Payment Intent Demo Mockup · Arc MCP Builder Assistant</title>
|
|
7
|
+
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Cdefs%3E%3ClinearGradient id='g' x1='0' y1='0' x2='1' y2='1'%3E%3Cstop offset='0' stop-color='%232563eb'/%3E%3Cstop offset='1' stop-color='%2306b6d4'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='64' height='64' rx='16' fill='url(%23g)'/%3E%3Ctext x='50%25' y='55%25' text-anchor='middle' font-family='Inter,Arial,sans-serif' font-size='38' font-weight='900' fill='white'%3EA%3C/text%3E%3C/svg%3E" />
|
|
8
|
+
<meta name="description" content="Static UI mockup of the Arc payment-intent demo: an AI agent prepares a USDC request and a human keeps approval control. Part of the Arc MCP Builder Assistant kit." />
|
|
9
|
+
<meta name="author" content="Arc MCP Builder Assistant contributors" />
|
|
10
|
+
<meta name="robots" content="index,follow" />
|
|
11
|
+
<meta name="theme-color" content="#05060a" />
|
|
12
|
+
<meta name="color-scheme" content="dark" />
|
|
13
|
+
<meta name="referrer" content="no-referrer" />
|
|
14
|
+
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; object-src 'none'; base-uri 'none'; form-action 'none'; upgrade-insecure-requests" />
|
|
15
|
+
<link rel="canonical" href="https://anstrays.github.io/arc-mcp-builder-assistant/examples/payment-intent-demo/" />
|
|
16
|
+
<meta property="og:title" content="Arc Payment Intent Demo Mockup" />
|
|
17
|
+
<meta property="og:description" content="Static UI mockup of an AI-prepared, human-approved USDC payment intent on Arc." />
|
|
18
|
+
<meta property="og:type" content="website" />
|
|
19
|
+
<style>
|
|
20
|
+
:root { color-scheme: dark; font-family: Inter, ui-sans-serif, system-ui, -apple-system, Segoe UI, sans-serif; }
|
|
21
|
+
body { margin: 0; min-height: 100vh; display: grid; place-items: center; background: radial-gradient(circle at top, #263bff 0, #080914 34%, #05060a 100%); color: #f7f7ff; padding: 32px 0; }
|
|
22
|
+
main { width: min(920px, calc(100vw - 32px)); display: grid; gap: 18px; }
|
|
23
|
+
a { color: inherit; }
|
|
24
|
+
a:focus-visible,
|
|
25
|
+
button:focus-visible {
|
|
26
|
+
outline: 2px solid #8ea2ff;
|
|
27
|
+
outline-offset: 3px;
|
|
28
|
+
border-radius: 8px;
|
|
29
|
+
}
|
|
30
|
+
.card { border: 1px solid rgba(255,255,255,.14); background: rgba(10, 12, 24, .78); border-radius: 24px; padding: 24px; box-shadow: 0 24px 80px rgba(0,0,0,.35); }
|
|
31
|
+
.eyebrow { color: #8ea2ff; text-transform: uppercase; letter-spacing: .16em; font-size: 12px; font-weight: 700; }
|
|
32
|
+
h1 { margin: 8px 0 10px; font-size: clamp(32px, 6vw, 64px); line-height: .95; }
|
|
33
|
+
p { color: #cbd2ff; line-height: 1.65; }
|
|
34
|
+
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 18px; }
|
|
35
|
+
.intent { display: grid; gap: 12px; }
|
|
36
|
+
.row { display: flex; justify-content: space-between; gap: 16px; padding: 12px 0; border-bottom: 1px solid rgba(255,255,255,.1); }
|
|
37
|
+
.label { color: #8e95bc; }
|
|
38
|
+
.value { font-weight: 700; text-align: right; }
|
|
39
|
+
button { border: 0; border-radius: 999px; padding: 14px 20px; font-weight: 800; cursor: default; background: #f7f7ff; color: #080914; }
|
|
40
|
+
button:disabled { opacity: .72; }
|
|
41
|
+
.secondary { background: rgba(255,255,255,.1); color: #f7f7ff; }
|
|
42
|
+
.actions { display: flex; flex-wrap: wrap; gap: 12px; }
|
|
43
|
+
.mini-list { margin: 12px 0 0; padding-left: 18px; color: #cbd2ff; line-height: 1.6; }
|
|
44
|
+
.status-log { display: grid; gap: 10px; margin-top: 14px; }
|
|
45
|
+
.status-log div { border: 1px solid rgba(255,255,255,.1); border-radius: 14px; padding: 12px; color: #cbd2ff; background: rgba(255,255,255,.045); }
|
|
46
|
+
.status-log strong { color: #f7f7ff; }
|
|
47
|
+
.json-preview { white-space: pre-wrap; overflow: auto; border: 1px solid rgba(255,255,255,.1); border-radius: 16px; padding: 14px; background: rgba(0,0,0,.24); color: #d9fffb; font-size: 13px; line-height: 1.55; }
|
|
48
|
+
.warning { border-color: rgba(94,234,212,.32); background: rgba(94,234,212,.08); }
|
|
49
|
+
.breadcrumb { margin: 0 0 4px; font-size: 13px; color: #8e95bc; }
|
|
50
|
+
.breadcrumb a { color: #cbd2ff; text-decoration: underline; text-underline-offset: 3px; }
|
|
51
|
+
@media (prefers-reduced-motion: reduce) {
|
|
52
|
+
* { animation-duration: 0s !important; transition: none !important; }
|
|
53
|
+
}
|
|
54
|
+
</style>
|
|
55
|
+
</head>
|
|
56
|
+
<body>
|
|
57
|
+
<main>
|
|
58
|
+
<p class="breadcrumb"><a href="../../index.html">← Back to Arc MCP Builder Assistant</a></p>
|
|
59
|
+
<section class="card" aria-labelledby="demo-title">
|
|
60
|
+
<div class="eyebrow">Arc Agent Commerce</div>
|
|
61
|
+
<h1 id="demo-title">Payment Intent Demo</h1>
|
|
62
|
+
<p>An AI agent prepares a USDC payment request. The human keeps approval control and approves manually. This is a safe first step toward agentic commerce on Arc.</p>
|
|
63
|
+
<p>This is a non-interactive mockup intended for review and feedback. It does not connect to a wallet, broadcast transactions, or talk to any backend. See <a href="../../docs/view.html#payment-intent-demo.md">docs/payment-intent-demo.md</a> for the spec.</p>
|
|
64
|
+
</section>
|
|
65
|
+
<section class="grid">
|
|
66
|
+
<article class="card" aria-labelledby="agent-title">
|
|
67
|
+
<div class="eyebrow">Agent</div>
|
|
68
|
+
<h2 id="agent-title">Research Agent</h2>
|
|
69
|
+
<p>Purpose: purchase a data/API task after user approval. Agent identity and testnet integration are intentionally mocked in this v0 UI.</p>
|
|
70
|
+
</article>
|
|
71
|
+
<article class="card intent" aria-labelledby="intent-title">
|
|
72
|
+
<div class="eyebrow">Payment Intent</div>
|
|
73
|
+
<h2 id="intent-title" class="sr-only" hidden>Pending payment intent</h2>
|
|
74
|
+
<div class="row"><span class="label">Asset</span><span class="value">USDC</span></div>
|
|
75
|
+
<div class="row"><span class="label">Amount</span><span class="value">5.00</span></div>
|
|
76
|
+
<div class="row"><span class="label">Recipient</span><span class="value">0xDemo…Arc</span></div>
|
|
77
|
+
<div class="row"><span class="label">Memo</span><span class="value">Research task #42</span></div>
|
|
78
|
+
<div class="row"><span class="label">Status</span><span class="value">Pending approval</span></div>
|
|
79
|
+
<div class="actions" aria-describedby="mock-controls-note">
|
|
80
|
+
<button type="button" disabled aria-label="Approve payment unavailable in static mockup; no transaction is sent">Approve payment</button>
|
|
81
|
+
<button type="button" disabled class="secondary" aria-label="Cancel payment unavailable in static mockup">Cancel</button>
|
|
82
|
+
</div>
|
|
83
|
+
<p id="mock-controls-note">Controls are intentionally disabled in this static mockup. A future testnet version must keep signing explicit and user-approved.</p>
|
|
84
|
+
</article>
|
|
85
|
+
</section>
|
|
86
|
+
<section class="grid" aria-label="Demo review details">
|
|
87
|
+
<article class="card warning" aria-labelledby="boundaries-title">
|
|
88
|
+
<div class="eyebrow">Trust boundaries</div>
|
|
89
|
+
<h2 id="boundaries-title">What the agent cannot do</h2>
|
|
90
|
+
<ul class="mini-list">
|
|
91
|
+
<li>Cannot spend funds or sign transactions.</li>
|
|
92
|
+
<li>Cannot change the recipient after human review starts.</li>
|
|
93
|
+
<li>Cannot hide amount, memo, expiry, or status fields.</li>
|
|
94
|
+
</ul>
|
|
95
|
+
</article>
|
|
96
|
+
<article class="card" aria-labelledby="timeline-title">
|
|
97
|
+
<div class="eyebrow">Execution timeline</div>
|
|
98
|
+
<h2 id="timeline-title">Review-first flow</h2>
|
|
99
|
+
<div class="status-log">
|
|
100
|
+
<div><strong>Prepared</strong> · Agent drafts the payment intent from docs-grounded context.</div>
|
|
101
|
+
<div><strong>Review</strong> · Human checks amount, recipient, memo, and purpose.</div>
|
|
102
|
+
<div><strong>Approve later</strong> · Wallet integration is a future testnet-only step.</div>
|
|
103
|
+
</div>
|
|
104
|
+
</article>
|
|
105
|
+
<article class="card" aria-labelledby="json-title">
|
|
106
|
+
<div class="eyebrow">Reviewable JSON</div>
|
|
107
|
+
<h2 id="json-title">Intent object</h2>
|
|
108
|
+
<pre class="json-preview" aria-label="Static payment intent JSON">{
|
|
109
|
+
"agent": "Research Agent",
|
|
110
|
+
"recipient": "0xDemo...Arc",
|
|
111
|
+
"asset": "USDC",
|
|
112
|
+
"amount": "5.00",
|
|
113
|
+
"memo": "Research task #42",
|
|
114
|
+
"expiry": "2030-05-30T00:00:00Z",
|
|
115
|
+
"status": "pending_human_approval"
|
|
116
|
+
}</pre>
|
|
117
|
+
<p>Future versions should let the user inspect this object before any wallet prompt appears.</p>
|
|
118
|
+
</article>
|
|
119
|
+
<article class="card" aria-labelledby="next-title">
|
|
120
|
+
<div class="eyebrow">Next prototype</div>
|
|
121
|
+
<h2 id="next-title">From mockup to playground</h2>
|
|
122
|
+
<ul class="mini-list">
|
|
123
|
+
<li>Add editable fields for agent, recipient, amount, memo, and expiry.</li>
|
|
124
|
+
<li>Show live JSON and local-only status transitions.</li>
|
|
125
|
+
<li>Use the <a href="../../docs/view.html#arc-builder-readiness-checklist.md">builder readiness checklist</a> before testnet integration.</li>
|
|
126
|
+
<li>Extend the pattern into the <a href="../../docs/view.html#job-escrow-demo.md">job escrow demo</a>.</li>
|
|
127
|
+
</ul>
|
|
128
|
+
</article>
|
|
129
|
+
</section>
|
|
130
|
+
</main>
|
|
131
|
+
</body>
|
|
132
|
+
</html>
|