Skip to content

fix: [FIND-033] exclude disabled corporate actions from pending task aggregations#1175

Merged
jaime-iobermudez merged 18 commits into
developmentfrom
fix/find-033-2
May 29, 2026
Merged

fix: [FIND-033] exclude disabled corporate actions from pending task aggregations#1175
jaime-iobermudez merged 18 commits into
developmentfrom
fix/find-033-2

Conversation

@jaime-iobermudez
Copy link
Copy Markdown
Contributor

@jaime-iobermudez jaime-iobermudez commented May 21, 2026

This pull request fixes an issue where cancelled (disabled) corporate actions were incorrectly included in pending task aggregations, affecting coupon listings, balance adjustments, and related queries. The fix ensures that disabled tasks are now properly excluded from all internal calculations, resulting in accurate live values for functions like getCouponsOrderedList, balanceOfAt, and others. The external API remains unchanged; the changes are internal and transparent to consumers.

Bug fix: Exclude disabled corporate actions from pending task aggregations

  • All internal aggregation functions (e.g., getPendingScheduledCouponListingTotalAt, getPendingScheduledBalanceAdjustmentsAt) now accept a _includeDisabled flag, allowing them to skip disabled tasks when computing live values. All internal callers that compute live values pass false, ensuring disabled tasks are excluded. (.changeset/fix-find-033-pending-task-disabled-exclusion.md, [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14]

Library and function interface changes

  • The _includeDisabled flag was propagated through several internal and library functions, including those in CouponStorageWrapper, ScheduledTasksStorageWrapper, and others, to ensure consistent exclusion of disabled tasks across all relevant queries and calculations. [1] [2] [3] [4] [5] [6]

New helper functions

  • Added isScheduledCouponListingDisabledAtIndex to efficiently check if a scheduled coupon listing task is related to a disabled corporate action, supporting the correct filtering of tasks.

Test coverage

  • Added an integration test to ensure that after a scheduled balance adjustment is cancelled, it is properly excluded from projected balances (e.g., balanceOfAt returns the unadjusted value after cancellation).

These changes collectively resolve the bug (FIND-033) and ensure that disabled corporate actions no longer affect live or projected calculations for coupons and balances.

Type of change

  • Bug fix 🐞
  • New feature ✨
  • Breaking change 💥
  • Documentation update 📖
  • Refactor 🔧

Testing

Node version:

  • 20
  • 22
  • 24

Checklist

  • Style Guidelines followed ✅
  • Documentation Updated 📚
  • Linters - No New Warnings ⚠️
  • Local Tests Pass ✅
  • Effective Tests Added ✔️
  • No reduction of Coverage

Signed-off-by: jaime-iobermudez <jaime.bermudez@io.builders>
Signed-off-by: jaime-iobermudez <jaime.bermudez@io.builders>
@jaime-iobermudez jaime-iobermudez requested review from a team as code owners May 21, 2026 10:05
@jaime-iobermudez jaime-iobermudez changed the title fix: exclude disabled corporate actions from pending task aggregations fix: [FIND-033] exclude disabled corporate actions from pending task aggregations May 21, 2026
@jaime-iobermudez jaime-iobermudez self-assigned this May 21, 2026
Comment thread packages/ats/contracts/contracts/domain/asset/KpisStorageWrapper.sol Outdated
Comment thread packages/ats/contracts/contracts/domain/asset/KpisStorageWrapper.sol Outdated
Signed-off-by: jaime-iobermudez <jaime.bermudez@io.builders>
@github-actions github-actions Bot added the hash-change PR modifies @custom:hash annotations or codegen formula — review on-chain impact carefully label May 22, 2026
@MiguelLZPF MiguelLZPF removed the hash-change PR modifies @custom:hash annotations or codegen formula — review on-chain impact carefully label May 25, 2026
Signed-off-by: jaime-iobermudez <jaime.bermudez@io.builders>
Signed-off-by: jaime-iobermudez <jaime.bermudez@io.builders>
Signed-off-by: jaime-iobermudez <jaime.bermudez@io.builders>
Signed-off-by: jaime-iobermudez <jaime.bermudez@io.builders>
Signed-off-by: jaime-iobermudez <jaime.bermudez@io.builders>
Signed-off-by: jaime-iobermudez <jaime.bermudez@io.builders>
Signed-off-by: jaime-iobermudez <jaime.bermudez@io.builders>
Signed-off-by: jaime-iobermudez <jaime.bermudez@io.builders>
Signed-off-by: jaime-iobermudez <jaime.bermudez@io.builders>
Signed-off-by: jaime-iobermudez <jaime.bermudez@io.builders>
Copy link
Copy Markdown
Contributor

@marcosio marcosio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A lot of improvements related with logic reduction, gas and bytecode improvements. Review.


if (_includeDisabled) {
uint256 index = ScheduledTasksStorageWrapper.getScheduledCouponListingCount(true) - 1 - pendingIndexOffset;
return ScheduledTasksStorageWrapper.getScheduledCouponListingIdAtIndex(index);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid variable of single use. Remove index and use inline.

// When excluding disabled, iterate the queue skipping disabled tasks to find the
// correct coupon at the filtered pending index.
uint256 queueLen = ScheduledTasksStorageWrapper.getScheduledCouponListingCount(true);
uint256 seen = 0;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

avoid 0 initializations.

// correct coupon at the filtered pending index.
uint256 queueLen = ScheduledTasksStorageWrapper.getScheduledCouponListingCount(true);
uint256 seen = 0;
for (uint256 j = queueLen; j > 0; ) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove queueLen and assign to j=ScheduledTasksStorageWrapper.getScheduledCouponListingCount(true).

}
}
}
return 0;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed, couponID_ is 0 jet.

}
}
return active;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps is better this:

    function getScheduledSnapshotCount(bool _includeDisabled) internal view returns (uint256 active) {
        ScheduledTasksDataStorage storage store = scheduledSnapshotStorage();
        uint256 total = ScheduledTasksLib.getScheduledTaskCount(store);
        if (_includeDisabled) return total;
        
        for (uint256 i; i < total; ) {
            unchecked {
                active += CorporateActionsStorageWrapper.isCorporateActionDisabled(
                    abi.decode(ScheduledTasksLib.getScheduledTasksByIndex(store, i).data, (bytes32))
                )
                    ? 0
                    : 1;
                ++i;
            }
        }
    }

if (_includeDisabled) {
return ScheduledTasksLib.getScheduledTasks(scheduledCouponListingStorage(), _pageIndex, _pageLength);
}
return _getFilteredPage(scheduledCouponListingStorage(), _pageIndex, _pageLength);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactor as getScheduledSnapshots

++i;
}
}
return active;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactor as getScheduledSnapshotCount

if (_includeDisabled) {
return ScheduledTasksLib.getScheduledTasks(scheduledBalanceAdjustmentStorage(), _pageIndex, _pageLength);
}
return _getFilteredPage(scheduledBalanceAdjustmentStorage(), _pageIndex, _pageLength);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactor


pendingABAF_ *= balanceAdjustment.factor;
pendingDecimals_ += balanceAdjustment.decimals;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better:

    function getPendingScheduledBalanceAdjustmentsAt(
        uint256 _timestamp,
        bool _includeDisabled
    ) internal view returns (uint256 pendingABAF_, uint8 pendingDecimals_) {
        // * Initialization
        pendingABAF_ = 1;
        ScheduledTasksDataStorage storage scheduledBalanceAdjustments = scheduledBalanceAdjustmentStorage();
        uint256 length = ScheduledTasksLib.getScheduledTaskCount(scheduledBalanceAdjustments);
        uint256 pos = length;

        for (uint256 i; i < length; ) {
            unchecked {
                --pos;
                ++i;
            }

            ScheduledTask memory scheduledTask = ScheduledTasksLib.getScheduledTasksByIndex(
                scheduledBalanceAdjustments,
                pos
            );

            if (_timestamp >= scheduledTask.scheduledTimestamp) return (pendingABAF_, pendingDecimals_);

            bytes32 actionId = abi.decode(scheduledTask.data, (bytes32));

            if (_includeDisabled || !CorporateActionsStorageWrapper.isCorporateActionDisabled(actionId)) {
                IScheduledBalanceAdjustment.ScheduledBalanceAdjustment memory balanceAdjustment = abi.decode(
                    CorporateActionsStorageWrapper.getCorporateActionData(actionId),
                    (IScheduledBalanceAdjustment.ScheduledBalanceAdjustment)
                );

                pendingABAF_ *= balanceAdjustment.factor;
                pendingDecimals_ += balanceAdjustment.decimals;
            }
        }
    }

++i;
}
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not optimal:

  • Don't use PaginationLib
  • Remove final for for assembly code to reduce buffer.
  • Don't create buffer, result_ is jet created.
  • For very complex to follow, is possible reduce jumps.

Signed-off-by: jaime-iobermudez <jaime.bermudez@io.builders>
Signed-off-by: jaime-iobermudez <jaime.bermudez@io.builders>
Signed-off-by: jaime-iobermudez <jaime.bermudez@io.builders>
Signed-off-by: jaime-iobermudez <jaime.bermudez@io.builders>
Signed-off-by: jaime-iobermudez <jaime.bermudez@io.builders>
@jaime-iobermudez jaime-iobermudez merged commit 54a7ce1 into development May 29, 2026
19 checks passed
@jaime-iobermudez jaime-iobermudez deleted the fix/find-033-2 branch May 29, 2026 13:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants