Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
6b5ff26
feat: initializer facet created
AlbertoMolinaIoBuilders Apr 29, 2026
b1527c5
feat: code updated
AlbertoMolinaIoBuilders Apr 29, 2026
00104a7
feat: initializer modifiers addedto modifiers file
AlbertoMolinaIoBuilders Apr 29, 2026
e1e1991
feat: code refactored
AlbertoMolinaIoBuilders Apr 29, 2026
9e54753
feat: initializer added to core and controller
AlbertoMolinaIoBuilders Apr 29, 2026
eca1bb4
Merge remote-tracking branch 'origin/development' into feat/Initializ…
AlbertoMolinaIoBuilders Apr 29, 2026
060451e
Merge branch 'development' into feat/InitializeFacet
marcosio May 4, 2026
86b48ac
feat(contracts): add counter-based auto-operational activation to ini…
marcosio May 6, 2026
e261b4e
refactor: introduce BalanceTrackerAtSnapshotFacet
themariofrancia Apr 29, 2026
7e13fa1
feat: burn by partition facet (#1006)
jaime-iobermudez Apr 29, 2026
32aaa69
fix: transfer event must be emitted in every balance movement in erc …
marcosio May 4, 2026
8243fa4
feat: deactivate facet implemented (#1031)
AlbertoMolinaIoBuilders May 4, 2026
25e12e4
feat: hold at snapshot facet (#1034)
jaime-iobermudez May 4, 2026
aa3f395
fix(contracts): hiero-solo facet registration race (BBND-1703)
MiguelLZPF May 5, 2026
a33d97b
chore(ci): add lint+format workflows, template, and Node.js centraliz…
MiguelLZPF May 5, 2026
bd96e2f
chore: clear ATS and MP lint debt for new CI gate
MiguelLZPF May 5, 2026
1c630d4
fix(test): restore jest polyfills and fix coupon lint
MiguelLZPF May 5, 2026
146b858
ci: bump solo-deployment timeout to 45 min (BBND-1703)
MiguelLZPF May 5, 2026
b57e6df
feat: adjustBalancesFacet (#1017)
Axel-IoBuilders May 5, 2026
1a1427f
feat: new HoldAtSnapshotByPartition facet (#1035)
mamoralesiob May 5, 2026
4444b47
feat: lock at snapshot facet (#1040)
jaime-iobermudez May 5, 2026
35b758c
fix(contracts): remove duplicate PauseModifiers and reorder imports i…
marcosio May 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
6 changes: 6 additions & 0 deletions .changeset/ci-lint-format-workflows.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@hashgraph/asset-tokenization-contracts": patch
"@hashgraph/mass-payout-contracts": patch
---

Add PR-gating lint and format CI workflows for ATS and MP, align workflow name prefixes with filenames, pin Node.js version via .nvmrc, and remove obsolete NODE_OPTIONS heap workarounds.
12 changes: 12 additions & 0 deletions .changeset/fix-hiero-solo-facet-registration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
"@hashgraph/asset-tokenization-contracts": patch
---

Fix BBND-1703: Hiero Solo deployment failure during facet registration.

The `deploySystemWithNewBlr` workflow's "Step 4/12: Registering facets in BLR" step was racing on the Hedera Solo JSON-RPC relay. It fired one parallel `eth_call` per facet (β‰ˆ101 concurrent reads of `getStaticResolverKey()`) via `Promise.all`, which Hardhat's in-process provider absorbs but the Hedera relay rejects/rate-limits. The deterministic resolver keys are already available offline via `getFacetDefinition()` from `@scripts/domain`, so the registration phase now reads them synchronously from the registry instead of fanning out RPC calls.

Two related fixes ride along:

- The `error()` / `warn()` / `debug()` loggers were silently dropping their `data` argument in text mode, masking the real exception body in CI logs (`❌ Deployment failed:` with no details). Text mode now also prints `Error.name` / `message` / `stack` and ethers-specific fields (`reason`, `shortMessage`, `code`, `data`).
- `registerFacets()` had an off-by-one in its batch loop (`length / FACET_REGISTRATION_BATCH_SIZE` without `Math.ceil` plus `i <= iterations`) that would have sent an empty final transaction whenever the facet count was an exact multiple of the batch size. Hardened with `Math.ceil`, strict `<`, and a defensive empty-slice guard.
30 changes: 30 additions & 0 deletions .changeset/maf-hold-at-snapshot.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
"@hashgraph/asset-tokenization-contracts": minor
---

# HoldAtSnapshot split

Extract `heldBalanceOfAtSnapshot` from `SnapshotsFacet` into a dedicated
`HoldAtSnapshotFacet` registered under `_HOLD_AT_SNAPSHOT_RESOLVER_KEY`.

## Changes

- Added `contracts/facets/holdAtSnapshot/IHoldAtSnapshot.sol`,
`HoldAtSnapshot.sol`, `HoldAtSnapshotFacet.sol`.
- Added `_HOLD_AT_SNAPSHOT_RESOLVER_KEY` constant in `resolverKeys.sol`.
- Removed `heldBalanceOfAtSnapshot` from `ISnapshots.sol`, `Snapshots.sol`,
and `SnapshotsFacet.sol` (11 β†’ 10 selectors).
- `IAsset` now inherits `IHoldAtSnapshot`.
- Updated `Configuration.ts` and 7 `createConfiguration.ts` scripts
(equity, bond, bondFixedRate, bondKpiLinkedRate,
bondSustainabilityPerformanceTargetRate, loan, loanPortfolio) to register
`HoldAtSnapshotFacet`.
- Added `test/contracts/integration/holdAtSnapshot/holdAtSnapshot.test.ts`
covering revert cases (SnapshotIdNull, SnapshotIdDoesNotExists), happy paths,
historical correctness across two snapshots, and multi-holder independence.
- Removed `heldBalanceOfAtSnapshot` assertions from `snapshots.test.ts`.

## Non-breaking

The 4-byte selector of `heldBalanceOfAtSnapshot` is unchanged. Any call
through `IAsset` continues to work without modification.
28 changes: 28 additions & 0 deletions .changeset/maf-lock-at-snapshot.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
"@hashgraph/asset-tokenization-contracts": minor
---

# LockAtSnapshot split

Extract `lockedBalanceOfAtSnapshot` from `SnapshotsFacet` into a dedicated
`LockAtSnapshotFacet` registered under `_LOCK_AT_SNAPSHOT_RESOLVER_KEY`.

## Changes

- Added `contracts/facets/lockAtSnapshot/ILockAtSnapshot.sol`,
`LockAtSnapshot.sol`, `LockAtSnapshotFacet.sol`.
- Added `_LOCK_AT_SNAPSHOT_RESOLVER_KEY` constant in `resolverKeys.sol`.
- Removed `lockedBalanceOfAtSnapshot` from `Snapshots.sol`, `ISnapshots.sol`,
and `SnapshotsFacet.sol` (10 β†’ 9 selectors).
- `IAsset` now inherits `ILockAtSnapshot`.
- Updated `Configuration.ts` and 7 `createConfiguration.ts` scripts
(equity, bond, bondFixedRate, bondKpiLinkedRate, bondSPTR, loan,
loanPortfolio) to register `LockAtSnapshotFacet`.
- Added `test/contracts/integration/lockAtSnapshot/lockAtSnapshot.test.ts`
covering null snapshot, unknown snapshot, zero-lock, exact-amount,
historical isolation, and multi-holder scenarios.

## Non-breaking

The 4-byte selector of `lockedBalanceOfAtSnapshot` is unchanged. Any call
through `IAsset` continues to work without modification.
5 changes: 5 additions & 0 deletions .changeset/maf-split-adjust-balances.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hashgraph/asset-tokenization-contracts": minor
---

Consolidate 8 balance-adjustment functions from ScheduledBalanceAdjustmentsFacet, EquityUSAFacet, and ERC1410TokenHolderFacet into a single AdjustBalancesFacet at the flat contracts/facets/adjustBalances/ path.
5 changes: 5 additions & 0 deletions .changeset/maf-split-holdAtSnapshotByPartition.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hashgraph/asset-tokenization-contracts": minor
---

refactor(contracts): split HoldAtSnapshotByPartition facet out of Snapshots
57 changes: 57 additions & 0 deletions .changeset/poc-auto-operational-counter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
---
"@io-builders/ats-contracts": minor
---

## PoC: Counter-Based Auto-Operational Activation

Introduces an O(1) counter mechanism that eliminates the need for an explicit
`setOperationalStatus` transaction after every initialisation or upgrade flow.

### Problem

The current approach requires operators to call `setOperationalStatus` as a separate
on-chain transaction after all facets are ready. This transaction iterates all facets in
batches of 10, violating the Minimum-Action-per-Facet (MAF) principle and growing linearly
with config size.

### Solution

Each `setFacetToReady` call now atomically increments a counter. When the counter reaches
`configTargetCount` (set once before the first registration), the config transitions to
operational and emits `TokenOperational` β€” all within the same transaction as the last
facet registration.

### Changes

**`IInitializer`**

- Added `event TokenOperational(bytes32 indexed configId, uint256 indexed versionId)`
- Added `setConfigTargetCount(bytes32, uint256, uint256)` β€” set before first `setFacetToReady`
- Added `getConfigInitializedCount(bytes32, uint256)` β€” how many facets have registered
- Added `getConfigTargetCount(bytes32, uint256)` β€” the configured target

**`InitializerStorageWrapper`**

- Extended `InitializerDataStorage` with `configInitializedCount` and `configTargetCount` mappings
- `setFacetToReady` now calls `_tryAutoActivate()` (private, O(1)) after marking the facet ready
- Added `setConfigTargetCount`, `getConfigInitializedCount`, `getConfigTargetCount` internal helpers

**`Initializer` / `InitializerFacet`**

- Exposed the three new functions as external selectors

**Gas benchmark**

- `GasBenchmarkInitializerHarness.sol` β€” standalone harness for gas measurement without full diamond
- `gasBenchmarkInitializer.test.ts` β€” benchmarks N = {1, 5, 10, 25, 50, 100} facets,
asserts every single call stays below the Hedera 7.5M practical gas limit

**ADR**

- `docs/adr/ADR-002-counter-based-auto-operational.md` documents the decision, tradeoffs,
and rejected alternatives

### Backward compatibility

`setConfigTargetCount` defaults to 0. When 0, `_tryAutoActivate` is a no-op and
`setOperationalStatus` continues to work exactly as before. No breaking changes.
23 changes: 23 additions & 0 deletions .changeset/slow-places-shout.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
"@hashgraph/asset-tokenization-contracts": minor
---

Add irreversible token deactivation via `DeactivateFacet`.

**New `DeactivateFacet` β€” one-way retirement of a security token**
Introduces a dedicated facet that permanently retires a token from active use. Once `deactivate()` is called by an account holding `DEACTIVATE_ROLE`, every operation guarded by `onlyActivated` reverts with `Deactivated`. The transition is intentionally one-way: there is no `reactivate` counterpart. The facet exposes two selectors: `deactivate()` and `isDeactivated()`.

**New `DeactivateStorageWrapper` β€” diamond storage for the deactivation flag**
Persists the deactivation state at a dedicated `_DEACTIVATE_STORAGE_POSITION` slot. Single-field struct (`bool deactivated`) designed for forward compatibility β€” future metadata (operator, timestamp, reason) can be appended without changing the slot. Provides `deactivate()`, `isDeactivated()`, and `requireActivated()` internals.

**New `DeactivateModifiers` + `onlyActivated` wired into `CoreModifiers`**
Adds the `onlyActivated` modifier as a reusable mix-in backed by `DeactivateStorageWrapper.requireActivated()`. `CoreModifiers` is updated to inherit `DeactivateModifiers`, making the guard available to all facets that already extend `CoreModifiers` without any further import changes.

**New `DEACTIVATE_ROLE` constant and storage slot**
`constants/roles.sol` and `constants/storagePositions.sol` receive the new `DEACTIVATE_ROLE` and `_DEACTIVATE_STORAGE_POSITION` entries. `IAsset.sol` is updated to expose the `IDeactivate` interface. The auto-generated `factory/ERC3643/interfaces/roles.sol` is regenerated accordingly.

**Registry and configuration updated**
`atsRegistry.data.ts` registers `DeactivateFacet` with its selectors. All existing `createConfiguration` scripts for bond, equity, and loan-portfolio token types are updated to include the new facet in the default diamond cut.

**Integration tests**
`deactivate.test.ts` covers: successful deactivation by role holder, revert on second call, revert when caller lacks `DEACTIVATE_ROLE`, revert on operations guarded by `onlyActivated` after deactivation, and `isDeactivated` read path.
2 changes: 1 addition & 1 deletion .github/workflows/000-flow-changeset-check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ jobs:
- name: Setup NodeJS Environment
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: 22.20.0
node-version-file: .nvmrc

- name: Check for bypass labels
id: bypass
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/001-flow-pull-request-formatting.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: "000: [FLOW] PR Formatting"
name: "001: [FLOW] PR Formatting"
on:
pull_request_target:
# This covers: new PRs, title edits, new commits, and assignee changes - everything the workflow actually validates
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/002-user-ats-release.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: "000: [USER] ATS Release"
name: "002: [USER] ATS Release"

on:
# Manual trigger with preview/release option
Expand Down Expand Up @@ -43,7 +43,7 @@ jobs:
- name: Setup NodeJS Environment
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: v22.20.0
node-version-file: .nvmrc

- name: Install dependencies
run: npm ci
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/003-user-mp-release.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: "000: [USER] MP Release"
name: "003: [USER] MP Release"

on:
# Manual trigger with preview/release option
Expand Down Expand Up @@ -43,7 +43,7 @@ jobs:
- name: Setup NodeJS Environment
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: 22.20.0
node-version-file: .nvmrc

- name: Install dependencies
run: npm ci
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/100-flow-ats-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ jobs:
runs-on: token-studio-linux-large
timeout-minutes: 45
env:
NODE_OPTIONS: "--max-old-space-size=32768"
CONTRACT_SIZER_RUN_ON_COMPILE: "false"
REPORT_GAS: "false"
CLIENT_PRIVATE_KEY_ECDSA_1: ${{ secrets.CLIENT_PRIVATE_KEY_ECDSA_1 }}
Expand Down Expand Up @@ -63,7 +62,8 @@ jobs:
- name: Setup NodeJS Environment
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: 22.20.0
node-version-file: .nvmrc
cache: "npm"

- name: Install dependencies
run: npm ci
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/101-flow-mp-test.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: "100: [FLOW] MP Test"
name: "101: [FLOW] MP Test"

on:
push:
Expand All @@ -25,7 +25,6 @@ jobs:
runs-on: token-studio-linux-large
timeout-minutes: 45
env:
NODE_OPTIONS: "--max-old-space-size=32768"
CONTRACT_SIZER_RUN_ON_COMPILE: "false"
REPORT_GAS: "false"
CLIENT_PRIVATE_KEY_ECDSA_1: ${{ secrets.CLIENT_PRIVATE_KEY_ECDSA_1 }}
Expand Down Expand Up @@ -64,7 +63,8 @@ jobs:
- name: Setup NodeJS Environment
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: 22.20.0
node-version-file: .nvmrc
cache: "npm"

- name: Install dependencies
run: npm ci
Expand Down
13 changes: 5 additions & 8 deletions .github/workflows/102-flow-ats-deployment-test.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: "100: [FLOW] ATS Deployment Test"
name: "102: [FLOW] ATS Deployment Test"

on:
pull_request:
Expand Down Expand Up @@ -35,7 +35,6 @@ jobs:
runs-on: token-studio-linux-large
timeout-minutes: 10
env:
NODE_OPTIONS: "--max-old-space-size=32768"
CONTRACT_SIZER_RUN_ON_COMPILE: "false"
REPORT_GAS: "false"

Expand All @@ -51,7 +50,7 @@ jobs:
- name: Setup NodeJS Environment
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: 22.20.0
node-version-file: .nvmrc

- name: Restore dependencies from cache
id: deps-cache
Expand Down Expand Up @@ -102,7 +101,6 @@ jobs:
runs-on: token-studio-linux-large
timeout-minutes: 15
env:
NODE_OPTIONS: "--max-old-space-size=32768"
CONTRACT_SIZER_RUN_ON_COMPILE: "false"
REPORT_GAS: "false"

Expand All @@ -118,7 +116,7 @@ jobs:
- name: Setup NodeJS Environment
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: 22.20.0
node-version-file: .nvmrc

- name: Restore dependencies from cache
id: deps-cache
Expand Down Expand Up @@ -221,9 +219,8 @@ jobs:
needs:
- build
runs-on: token-studio-linux-large
timeout-minutes: 30
timeout-minutes: 45
env:
NODE_OPTIONS: "--max-old-space-size=32768"
CONTRACT_SIZER_RUN_ON_COMPILE: "false"
REPORT_GAS: "false"

Expand All @@ -239,7 +236,7 @@ jobs:
- name: Setup NodeJS Environment
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: 22.20.0
node-version-file: .nvmrc

- name: Check Docker availability
id: docker-check
Expand Down
26 changes: 26 additions & 0 deletions .github/workflows/103-flow-ats-lint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: "103: [FLOW] ATS Lint and Format"

on:
pull_request:
paths:
- "packages/ats/**"
- "apps/ats/**"
- "package.json"
- "package-lock.json"
- ".github/workflows/103-flow-ats-lint.yaml"
- ".github/workflows/800-call-lint-format.yaml"
workflow_dispatch:

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
lint-and-format:
name: lint-and-format
uses: ./.github/workflows/800-call-lint-format.yaml
with:
module: ats
26 changes: 26 additions & 0 deletions .github/workflows/104-flow-mp-lint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: "104: [FLOW] MP Lint and Format"

on:
pull_request:
paths:
- "packages/mass-payout/**"
- "apps/mass-payout/**"
- "package.json"
- "package-lock.json"
- ".github/workflows/104-flow-mp-lint.yaml"
- ".github/workflows/800-call-lint-format.yaml"
workflow_dispatch:

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
lint-and-format:
name: lint-and-format
uses: ./.github/workflows/800-call-lint-format.yaml
with:
module: mass-payout
Loading
Loading