Skip to content

Commit d2e46de

Browse files
authored
Bind claim delivery observation to mission beneficiary (#2)
* Bind claim delivery observations to wallet * Document wallet-bound production release
1 parent be10d16 commit d2e46de

7 files changed

Lines changed: 59 additions & 25 deletions

File tree

‎README.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,16 +106,16 @@ See
106106

107107
- Public application: `https://commit-protocol.vercel.app`
108108
- Deployed application source commit:
109-
`d25e689b0d5c681755751da257700f0d3f7974d1`
109+
`53fb52f2d8d7c5a3636810501b740d859d5a2c14`
110110
- Deployed application source tree:
111-
`5553aa58ab006c85000c5a2b106988da2b61f002`
111+
`91c5f458dd77f7d38f0c8107f00eb15a74c3ce37`
112112
- Vercel production deployment:
113-
`dpl_Cwh63QydtcGyVD9MeZ7jrSo3A1QE`
113+
`dpl_BvXSZgubPSzs3Z9cyck6eY5dzvDt`
114114
- Served coordinator: `0xEE21cCFF8f3755487f774BFd5Da9Ff51D5688581`
115115
- Production smoke checks: `/`, `/app`, `/verify`, health, typed index lookup,
116116
typed transaction lookup, security headers, and browser verification action:
117117
**passed**
118-
- GitHub Actions `Verification` run `35140950751`: **passed**
118+
- GitHub Actions `Verification` run `35142284628`: **passed**
119119

120120
The complete production release record is in
121121
[`docs/PRODUCTION_RELEASE_2026-09-16.md`](./docs/PRODUCTION_RELEASE_2026-09-16.md).

‎components/application/claim-mission-flow.tsx‎

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@ import {
99
ShieldCheck,
1010
WalletCards,
1111
} from "lucide-react";
12-
import {
13-
useState,
14-
} from "react";
12+
import { useState } from "react";
1513
import {
1614
formatGenAmount,
1715
trackCommitTransaction,
@@ -97,6 +95,13 @@ export function ClaimMissionFlow({
9795
setDeliveryBusy,
9896
] = useState(false);
9997

98+
const activeClaimRecord =
99+
claimRecord !== null
100+
&& claimRecord.missionId === missionId
101+
&& claimRecord.beneficiary.toLowerCase() === wallet.address.toLowerCase()
102+
? claimRecord
103+
: null;
104+
100105
function resetReview() {
101106
setQuote(null);
102107
setProgress(null);
@@ -152,6 +157,8 @@ export function ClaimMissionFlow({
152157
txId,
153158
});
154159
setClaimRecord({
160+
missionId: quote.snapshot.mission.missionId,
161+
beneficiary: quote.snapshot.beneficiary,
155162
transactionId: txId,
156163
amount: quote.snapshot.missionClaimable,
157164
});
@@ -209,7 +216,7 @@ export function ClaimMissionFlow({
209216

210217
async function refreshDelivery() {
211218
if (
212-
claimRecord === null
219+
activeClaimRecord === null
213220
|| deliveryBusy
214221
) {
215222
return;
@@ -221,17 +228,17 @@ export function ClaimMissionFlow({
221228
setDelivery(
222229
await observeExternalDelivery(
223230
wallet.client,
224-
claimRecord.transactionId,
231+
activeClaimRecord.transactionId,
225232
{
226233
recipient: wallet.address,
227-
amount: claimRecord.amount,
234+
amount: activeClaimRecord.amount,
228235
},
229236
),
230237
);
231238
} catch (caught: unknown) {
232239
setDelivery(
233240
unverifiedExternalDelivery(
234-
claimRecord.transactionId,
241+
activeClaimRecord.transactionId,
235242
caught instanceof Error
236243
? caught.message
237244
: "The delivery observation could not be completed. No delivery outcome is claimed.",
@@ -515,7 +522,7 @@ export function ClaimMissionFlow({
515522
</div>
516523
) : null}
517524

518-
{claimRecord !== null ? (
525+
{activeClaimRecord !== null ? (
519526
<div className="claim-delivery">
520527
<div className="claim-delivery-heading">
521528
<div>
@@ -552,7 +559,7 @@ export function ClaimMissionFlow({
552559
<dl>
553560
<div>
554561
<dt>Parent claim</dt>
555-
<dd>{claimRecord.transactionId}</dd>
562+
<dd>{activeClaimRecord.transactionId}</dd>
556563
</div>
557564
<div>
558565
<dt>Triggered child</dt>

‎docs/AGENT_TANK_SUBMISSION.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,14 @@ uses the SDK's authoritative eligibility, charge, and appeal operations.
2424
- Public app: `https://commit-protocol.vercel.app`
2525
- GitHub: `https://github.com/Manablaq/commit-protocol`
2626
- Production source commit:
27-
`d25e689b0d5c681755751da257700f0d3f7974d1`
27+
`53fb52f2d8d7c5a3636810501b740d859d5a2c14`
2828
- Production source tree:
29-
`5553aa58ab006c85000c5a2b106988da2b61f002`
29+
`91c5f458dd77f7d38f0c8107f00eb15a74c3ce37`
3030
- Vercel production deployment:
31-
`dpl_Cwh63QydtcGyVD9MeZ7jrSo3A1QE`
31+
`dpl_BvXSZgubPSzs3Z9cyck6eY5dzvDt`
3232
- Served coordinator:
3333
`0xEE21cCFF8f3755487f774BFd5Da9Ff51D5688581`
34-
- GitHub Actions `Verification` run: `35140950751` — all jobs passed
34+
- GitHub Actions `Verification` run: `35142284628` — all jobs passed
3535

3636
Production smoke checks and the exact served-bundle binding are recorded in
3737
[`PRODUCTION_RELEASE_2026-09-16.md`](./PRODUCTION_RELEASE_2026-09-16.md).

‎docs/EXTERNAL_DELIVERY_OBSERVATION.md‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,11 @@ and the finalized execution result is `FINISHED_WITH_ERROR`.
3434
| `UNVERIFIED` | No child ID, malformed/ambiguous child set, unreadable child, mismatched recipient/value, unknown result, or RPC failure. | Show that delivery is unresolved; do not infer success or terminal non-delivery. |
3535

3636
The UI exposes an explicit `Observe child transaction` action and keeps the
37-
parent claim ID plus exact amount in beneficiary-scoped browser storage. This
38-
allows re-observation after navigation without a page reload or a new write.
37+
parent claim ID, exact mission ID, beneficiary, and amount in beneficiary-scoped
38+
browser storage. This allows re-observation after navigation without a page
39+
reload or a new write. A record is shown only when both the mission and the
40+
connected beneficiary match; switching wallets cannot surface another wallet's
41+
claim observation.
3942
Browser storage is only a convenience cache; it is not trusted contract state.
4043

4144
## What this intentionally does not claim

‎docs/PRODUCTION_RELEASE_2026-09-16.md‎

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,17 @@ canonical Vercel alias and the exact Studio Next coordinator it targets.
66
## Release identity
77

88
- Repository: `https://github.com/Manablaq/commit-protocol`
9-
- Deployed application source commit: `d25e689b0d5c681755751da257700f0d3f7974d1`
10-
- Deployed application source tree: `5553aa58ab006c85000c5a2b106988da2b61f002`
9+
- Deployed application source commit: `53fb52f2d8d7c5a3636810501b740d859d5a2c14`
10+
- Deployed application source tree: `91c5f458dd77f7d38f0c8107f00eb15a74c3ce37`
1111
- Public application: `https://commit-protocol.vercel.app`
1212
- Vercel project: `mr-albert-s-projects/commitprotocol-genlayer`
13-
- Vercel production deployment: `dpl_Cwh63QydtcGyVD9MeZ7jrSo3A1QE`
13+
- Vercel production deployment: `dpl_BvXSZgubPSzs3Z9cyck6eY5dzvDt`
1414
- Deployment state: `READY` / `PRODUCTION`
1515

1616
The source commit and tree above are the exact release built and published by
1717
the recorded Vercel deployment. The deployment includes the narrow-viewport
18-
overflow fix certified by the browser E2E gate.
18+
overflow fix and wallet-bound claim-observation fix certified by the browser
19+
E2E gate and regression suite.
1920

2021
## Served contract binding
2122

@@ -51,7 +52,7 @@ Read-only checks against `https://commit-protocol.vercel.app` passed:
5152
client-side error
5253
- deployed JavaScript bundle contains the certified coordinator anchor and the
5354
strict `EXTERNAL MESSAGE OBSERVATION` claim surface
54-
- GitHub Actions `Verification` run `35140950751` for the repository release:
55+
- GitHub Actions `Verification` run `35142284628` for the application release:
5556
completed successfully across Python, Direct Runtime, and frontend jobs
5657

5758
The verification API remains read-only. It does not reconstruct chain truth or

‎lib/genlayer-delivery.ts‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ export type ExternalDeliveryExpectation = {
5252
};
5353

5454
export type PersistedClaimTransaction = {
55+
missionId: string;
56+
beneficiary: `0x${string}`;
5557
transactionId: TransactionHash;
5658
amount: bigint;
5759
};
@@ -356,7 +358,12 @@ export function readPersistedClaimTransaction(
356358
const record = candidate as Record<string, unknown>;
357359

358360
if (
359-
typeof record.transactionId !== "string"
361+
typeof record.missionId !== "string"
362+
|| typeof record.beneficiary !== "string"
363+
|| !/^0x[0-9a-fA-F]{40}$/.test(record.beneficiary)
364+
|| record.missionId !== missionId
365+
|| record.beneficiary.toLowerCase() !== beneficiary.toLowerCase()
366+
|| typeof record.transactionId !== "string"
360367
|| !isTransactionHash(record.transactionId)
361368
|| typeof record.amount !== "string"
362369
|| !/^[1-9][0-9]*$/.test(record.amount)
@@ -365,6 +372,8 @@ export function readPersistedClaimTransaction(
365372
}
366373

367374
return {
375+
missionId: record.missionId,
376+
beneficiary: record.beneficiary as `0x${string}`,
368377
transactionId: record.transactionId,
369378
amount: BigInt(record.amount),
370379
};
@@ -387,6 +396,8 @@ export function persistClaimTransaction(
387396
window.localStorage.setItem(
388397
claimTransactionStorageKey(missionId, beneficiary),
389398
JSON.stringify({
399+
missionId,
400+
beneficiary: beneficiary.toLowerCase(),
390401
transactionId,
391402
amount: amount.toString(),
392403
}),

‎tests/frontend/genlayer-delivery.test.ts‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,18 @@ describe(
211211
expect(
212212
readPersistedClaimTransaction(missionId, RECIPIENT)?.amount,
213213
).toBe(AMOUNT);
214+
expect(
215+
readPersistedClaimTransaction(
216+
"different-mission",
217+
RECIPIENT,
218+
),
219+
).toBeNull();
220+
expect(
221+
readPersistedClaimTransaction(
222+
missionId,
223+
OTHER_RECIPIENT,
224+
),
225+
).toBeNull();
214226
window.localStorage.setItem(
215227
claimTransactionStorageKey(missionId, RECIPIENT),
216228
"not-a-hash",

0 commit comments

Comments
 (0)