@bloxchain/contracts 1.0.0-alpha.19 → 1.0.0-alpha.20

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.
@@ -32,13 +32,36 @@ import "./interface/ISecureOwnable.sol";
32
32
  * (a broadcaster update may still be pending). A new broadcaster-update request is allowed only
33
33
  * when neither type has a pending request.
34
34
  *
35
+ * **Ownership transfer vs recovery (threat model):**
36
+ * - `transferOwnershipRequest` snapshots `getRecovery()` into the pending tx `executionParams`. On execution,
37
+ * `executeTransferOwnership` receives that snapshotted address as the new owner. Rotating recovery after
38
+ * the request does **not** rewrite the pending payload; the beneficiary remains the recovery address
39
+ * at request time.
40
+ * - `transferOwnershipDelayedApproval` authorizes the **current** owner or **current** recovery (`getRecovery()`
41
+ * at approval time). It does **not** require the approver to match the snapshotted beneficiary. Integrators
42
+ * must treat approval as consent to execute the **stored** transfer, not “transfer to whoever is recovery now.”
43
+ * - `transferOwnershipCancellation` allows only the **current** recovery to cancel. If owner and broadcaster
44
+ * rotate recovery via `updateRecoveryRequestAndApprove` while a transfer is pending, the **previous**
45
+ * recovery loses cancel rights immediately; the pending tx still targets the old address until approved,
46
+ * cancelled by the new recovery, or superseded operationally.
47
+ * - Recovery and timelock updates use a request-and-approve meta-tx path without an additional timelock and
48
+ * are **not** blocked when an ownership transfer is pending (unlike broadcaster update requests). This is
49
+ * intentional: fast recovery rotation when owner and broadcaster still cooperate; operators who need a
50
+ * strict “recovery cannot change during pending ownership transfer” invariant must enforce it off-chain or
51
+ * extend this contract.
52
+ *
35
53
  * This contract focuses purely on security logic while leveraging the BaseStateMachine
36
54
  * for transaction management, meta-transactions, and state machine operations.
37
55
  */
38
56
  abstract contract SecureOwnable is BaseStateMachine, ISecureOwnable {
39
57
  using SharedValidation for *;
40
58
 
41
- /// @dev Tracks pending secure txs by type. Upgrading from legacy `_hasOpenRequest` / `_pendingBits` requires no pending requests.
59
+ /// @dev Lane flags for **delayed** ownership-transfer and broadcaster-update requests only (`transferOwnershipRequest`,
60
+ /// `updateBroadcasterRequest`). Recovery and timelock updates use `_requestAndApproveTransaction` and do **not**
61
+ /// read or write these booleans. Each flag is set only after a successful `_requestTransaction` in that same tx;
62
+ /// clearing happens only in `_completeApprove` / `_completeCancel` in the **same** transaction as a successful
63
+ /// `_approveTransaction` / `_cancelTransaction`, so a revert unwinds engine state and flag writes together.
64
+ /// @dev Upgrading from legacy `_hasOpenRequest` / `_pendingBits` requires no pending requests.
42
65
  bool private _hasOpenOwnershipRequest;
43
66
  bool private _hasOpenBroadcasterRequest;
44
67
 
@@ -81,7 +104,9 @@ abstract contract SecureOwnable is BaseStateMachine, ISecureOwnable {
81
104
 
82
105
  // Ownership Management
83
106
  /**
84
- * @dev Requests a transfer of ownership
107
+ * @dev Requests a time-delayed transfer of the OWNER role to the **recovery address at request time**.
108
+ * @notice Encodes `getRecovery()` into `executionParams`; that address becomes the new owner on successful
109
+ * execution. Changing recovery later does not update this pending record.
85
110
  * @return txId The transaction ID (use getTransaction(txId) for full record)
86
111
  */
87
112
  function transferOwnershipRequest() public returns (uint256 txId) {
@@ -104,7 +129,9 @@ abstract contract SecureOwnable is BaseStateMachine, ISecureOwnable {
104
129
  }
105
130
 
106
131
  /**
107
- * @dev Approves a pending ownership transfer transaction after the release time
132
+ * @dev Approves a pending ownership transfer after `releaseTime` (timelock on the direct path).
133
+ * @notice Callable by **current** owner or **current** recovery. Execution still transfers ownership to
134
+ * the address snapshotted at request time, which may differ from `getRecovery()` at approval time.
108
135
  * @param txId The transaction ID
109
136
  * @return The transaction ID
110
137
  */
@@ -124,7 +151,9 @@ abstract contract SecureOwnable is BaseStateMachine, ISecureOwnable {
124
151
  }
125
152
 
126
153
  /**
127
- * @dev Cancels a pending ownership transfer transaction
154
+ * @dev Cancels a pending ownership transfer transaction.
155
+ * @notice Only the **current** `getRecovery()` may cancel. After a recovery rotation, the prior recovery
156
+ * address can no longer cancel.
128
157
  * @param txId The transaction ID
129
158
  * @return The transaction ID
130
159
  */
@@ -219,7 +248,9 @@ abstract contract SecureOwnable is BaseStateMachine, ISecureOwnable {
219
248
  // Recovery Management
220
249
 
221
250
  /**
222
- * @dev Requests and approves a recovery address update using a meta-transaction
251
+ * @dev Requests and approves a recovery address update using a meta-transaction (owner signs, broadcaster submits).
252
+ * @notice Does **not** revert when an ownership transfer is pending. A pending transfer continues to target
253
+ * the recovery address snapshotted at its request until executed or cancelled by **current** recovery.
223
254
  * @param metaTx The meta-transaction
224
255
  * @return The transaction ID
225
256
  */
@@ -248,8 +279,9 @@ abstract contract SecureOwnable is BaseStateMachine, ISecureOwnable {
248
279
 
249
280
  // Execution Functions
250
281
  /**
251
- * @dev External function that can only be called by the contract itself to execute ownership transfer
252
- * @param newOwner The new owner address
282
+ * @dev External function that can only be called by the contract itself to execute ownership transfer.
283
+ * @param newOwner The new owner; for the OWNERSHIP_TRANSFER flow this is the recovery address encoded at
284
+ * request time (see `transferOwnershipRequest`), not necessarily `getRecovery()` at execution time.
253
285
  */
254
286
  function executeTransferOwnership(address newOwner) external {
255
287
  _validateExecuteBySelf();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bloxchain/contracts",
3
- "version": "1.0.0-alpha.19",
3
+ "version": "1.0.0-alpha.20",
4
4
  "description": "Library engine for building enterprise grade decentralized permissioned applications",
5
5
  "files": [
6
6
  "core",
@@ -40,8 +40,8 @@
40
40
  "access": "public"
41
41
  },
42
42
  "dependencies": {
43
- "@openzeppelin/contracts": "^5.4.0",
44
- "@openzeppelin/contracts-upgradeable": "^5.4.0"
43
+ "@openzeppelin/contracts": "^5.6.1",
44
+ "@openzeppelin/contracts-upgradeable": "^5.6.1"
45
45
  },
46
46
  "engines": {
47
47
  "node": ">=18.0.0"