Normalization and Configuration
The contract configuration flow MUST follow the same sequence as the reference implementation:
%%{init: {'flowchart':{'nodeSpacing': 20, 'rankSpacing': 20}}}%%
flowchart TD
A[ContractAttributes] --> B[normalize_contract_attributes]
B --> C[contract_config]
C --> D[contract_schedule]
D --> E[primary_distribution]
E --> F[contract_execute_ied]
Required steps
-
Define the debt instrument with
ContractAttributes. -
Normalize the contract off chain with
normalize_contract_attributes(). -
Upload
NormalizedActusTerms,InitialKernelState, and the prospectus withcontract_config. -
Upload the normalized schedule in contiguous pages with
contract_schedule. -
Reserve all units with
primary_distribution. -
Activate issuance by executing
contract_execute_ied.
contract_schedule MUST be called after contract_config, and contract_execute_ied
MUST be called only after the full schedule is uploaded and the full unit supply
is reserved.
Example
The deployment helpers and tests provide a code-accurate PAM fixed coupon bond example:
attrs = make_pam_fixed_coupon_bond_profile(
contract_id=1,
status_date=1_700_000_000,
initial_exchange_date=1_702_592_000,
maturity_date=1_858_112_000,
notional_principal=10_000,
nominal_interest_rate=0.02,
interest_payment_cycle=Cycle.parse_cycle("90D"),
interest_payment_anchor=1_710_368_000,
)
normalized = normalize_contract_attributes(
attrs,
denomination_asset_id=12345,
denomination_asset_decimals=2,
notional_unit_value=100,
secondary_market_opening_date=1_702_592_000,
secondary_market_closure_date=1_858_198_400,
)
pages = normalized.schedule_pages(page_size=16)
The normalized result has the following properties:
notional_principal = 1_000_000base units;total_units = 100;fixed_point_scale = 1_000_000_000;schedule = [IED] + 20 * [IP] + [MD];len(schedule) = 22;len(pages) = 2.
The upload sequence is:
client.send.contract_config(...)
client.send.contract_schedule(schedule_page_index=0, is_last_page=False, ...)
client.send.contract_schedule(schedule_page_index=1, is_last_page=True, ...)
client.send.primary_distribution(...)
client.send.contract_execute_ied()
Schedule paging
Schedule paging is part of configuration, not a transport detail. The caller MUST preserve:
- contiguous
schedule_page_indexvalues; - contiguous
event_idvalues across pages; - chronological ordering across page boundaries;
- one final page flagged with
is_last_page = true.
Secondary-market configuration
transfer_set_schedule is separate from kernel configuration. Secondary-market
dates are not part of the on-chain NormalizedActusTerms struct in the current
ABI and, if enforced, MUST be configured separately at the execution layer.
The SDK normalization metadata for secondary-market dates MUST satisfy
secondary_market_opening_date >= initial_exchange_date and
secondary_market_closure_date > secondary_market_opening_date.
Performance state
The contract-level defaulted performance flag is not part of normalization or
InitialKernelState. If used, it is updated separately at execution time through
the RBAC method rbac_contract_default.