diff --git a/src/lib/LibRebase.sol b/src/lib/LibRebase.sol index 6d56ea7..b2d45a7 100644 --- a/src/lib/LibRebase.sol +++ b/src/lib/LibRebase.sol @@ -73,25 +73,30 @@ library LibRebase { /// tests in `test/src/concrete/StoxReceiptVault.t.sol`. /// /// @param storedBalance The account's raw stored balance. - /// @param cursor The index of the last node this account was migrated - /// through. The default 0 is the bootstrap node — fresh holders start - /// at the bootstrap, and the walk advances them through every - /// subsequent completed split. + /// @param fromActionId The action id of the last node this account was + /// migrated through. The default 0 is the bootstrap node — fresh + /// holders start at the bootstrap, and the walk advances them through + /// every subsequent completed split. /// @return migratedBalance The balance after sequential multiplier /// application. Always 0 when `storedBalance == 0`. - /// @return newCursor The index of the last completed split node visited. - /// Equals the input cursor if there were no further completed splits. - function migratedBalance(uint256 storedBalance, uint256 cursor) internal view returns (uint256, uint256 newCursor) { - newCursor = cursor; + /// @return toActionId The action id of the last completed split node + /// visited. Equals `fromActionId` if there were no further completed + /// splits. + function migratedBalance(uint256 storedBalance, uint256 fromActionId) + internal + view + returns (uint256, uint256 toActionId) + { + toActionId = fromActionId; LibCorporateAction.CorporateActionStorage storage s = LibCorporateAction.getStorage(); uint256 balance = storedBalance; uint256 nodeIndex = - LibCorporateActionNode.nextOfType(cursor, BALANCE_MIGRATION_TYPES_MASK, CompletionFilter.COMPLETED); + LibCorporateActionNode.nextOfType(fromActionId, BALANCE_MIGRATION_TYPES_MASK, CompletionFilter.COMPLETED); while (nodeIndex != NODE_NONE) { - newCursor = nodeIndex; + toActionId = nodeIndex; // Skip the multiplier read and float math whenever the balance // is already zero. This covers both dormant zero-balance accounts // (never held / fully burned) and mid-iteration truncation to @@ -121,6 +126,6 @@ library LibRebase { LibCorporateActionNode.nextOfType(nodeIndex, BALANCE_MIGRATION_TYPES_MASK, CompletionFilter.COMPLETED); } - return (balance, newCursor); + return (balance, toActionId); } } diff --git a/src/lib/LibReceiptRebase.sol b/src/lib/LibReceiptRebase.sol index ff6a92e..8fd3fbf 100644 --- a/src/lib/LibReceiptRebase.sol +++ b/src/lib/LibReceiptRebase.sol @@ -46,37 +46,38 @@ import {LibRebaseMath} from "./LibRebaseMath.sol"; /// expected to be rare (O(10) over a contract's lifetime) so the /// per-receipt-holder migration cost is bounded and acceptable. library LibReceiptRebase { - /// @notice Walk the vault's completed stock split list from `cursor` - /// forward, returning the rebased balance and the advanced cursor. + /// @notice Walk the vault's completed stock split list from + /// `fromActionId` forward, returning the rebased balance and the + /// advanced action id. /// /// @param storedBalance The raw stored receipt balance for /// `(holder, id)`, read directly from OZ's ERC1155 storage. - /// @param cursor The index of the last vault corporate-action node this - /// `(holder, id)` pair was migrated through. The default 0 is the - /// vault's bootstrap node — fresh `(holder, id)` pairs start there - /// and the walk advances them through every subsequent completed - /// stock split. + /// @param fromActionId The action id of the last vault corporate-action + /// node this `(holder, id)` pair was migrated through. The default 0 + /// is the vault's bootstrap node — fresh `(holder, id)` pairs start + /// there and the walk advances them through every subsequent + /// completed stock split. /// @param vault The vault contract implementing `ICorporateActionsV1`. /// @return migratedBalance The balance after sequential multiplier /// application. Always 0 when `storedBalance == 0`. - /// @return newCursor The index of the last completed stock split - /// visited. Equals the input cursor if no further completed splits - /// were found. - function migratedBalance(uint256 storedBalance, uint256 cursor, ICorporateActionsV1 vault) + /// @return toActionId The action id of the last completed stock split + /// visited. Equals `fromActionId` if no further completed splits were + /// found. + function migratedBalance(uint256 storedBalance, uint256 fromActionId, ICorporateActionsV1 vault) internal view - returns (uint256, uint256 newCursor) + returns (uint256, uint256 toActionId) { - newCursor = cursor; + toActionId = fromActionId; - // Discard effectiveTime — only nextCursor and actionType are used + // Discard effectiveTime — only nextActionId and actionType are used // for the walk. The mask covers init and stock-split nodes; // effectiveTime is irrelevant here (the COMPLETED filter already // handled it on the vault side). actionType lets us skip the // float multiplier read for the identity init node. // slither-disable-next-line unused-return (uint256 nodeIndex, uint256 actionType,) = - vault.nextOfType(cursor, BALANCE_MIGRATION_TYPES_MASK, CompletionFilter.COMPLETED); + vault.nextOfType(fromActionId, BALANCE_MIGRATION_TYPES_MASK, CompletionFilter.COMPLETED); // Fast path: zero balance still advances the cursor through every // completed migration node without any multiplier math. Required for @@ -87,18 +88,18 @@ library LibReceiptRebase { // mechanism on the share side. if (storedBalance == 0) { while (nodeIndex != NODE_NONE) { - newCursor = nodeIndex; + toActionId = nodeIndex; // slither-disable-next-line unused-return (nodeIndex, actionType,) = vault.nextOfType(nodeIndex, BALANCE_MIGRATION_TYPES_MASK, CompletionFilter.COMPLETED); } - return (0, newCursor); + return (0, toActionId); } uint256 balance = storedBalance; while (nodeIndex != NODE_NONE) { - newCursor = nodeIndex; + toActionId = nodeIndex; // Init is identity — no multiplier, no balance change. Skip the // cross-contract `getActionParameters` call entirely; the // bootstrap node has empty parameters that would not decode as @@ -113,6 +114,6 @@ library LibReceiptRebase { vault.nextOfType(nodeIndex, BALANCE_MIGRATION_TYPES_MASK, CompletionFilter.COMPLETED); } - return (balance, newCursor); + return (balance, toActionId); } } diff --git a/src/lib/LibTotalSupply.sol b/src/lib/LibTotalSupply.sol index 4075107..f5c5cf8 100644 --- a/src/lib/LibTotalSupply.sol +++ b/src/lib/LibTotalSupply.sol @@ -240,19 +240,19 @@ library LibTotalSupply { } /// @notice Update tracking when an account is migrated. - /// @param fromCursor The account's cursor before migration. + /// @param fromActionId The action id the account's cursor was at before migration. /// @param storedBalance The account's stored balance before migration. - /// @param toCursor The account's cursor after migration. + /// @param toActionId The action id the account's cursor is at after migration. /// @param newBalance The account's rasterized balance after migration. - function onAccountMigrated(uint256 fromCursor, uint256 storedBalance, uint256 toCursor, uint256 newBalance) + function onAccountMigrated(uint256 fromActionId, uint256 storedBalance, uint256 toActionId, uint256 newBalance) internal { LibCorporateAction.CorporateActionStorage storage s = LibCorporateAction.getStorage(); - // Checked subtraction: safe by the pot invariant I(fromCursor) stated + // Checked subtraction: safe by the pot invariant I(fromActionId) stated // at the top of this library. `storedBalance` is one of the summands - // of `unmigrated[fromCursor]`, so the subtraction cannot underflow. - s.unmigrated[fromCursor] -= storedBalance; - s.unmigrated[toCursor] += newBalance; + // of `unmigrated[fromActionId]`, so the subtraction cannot underflow. + s.unmigrated[fromActionId] -= storedBalance; + s.unmigrated[toActionId] += newBalance; } /// @notice Update tracking for a mint (adds to the latest cursor pot).