Native Program
A Nigo Native Program is a protocol program that validates state-transition rules for a PROGRAM_VALIDATED_CELL transaction. It is written in Solidity and runs as EVM bytecode, but unlike a general Ethereum smart contract, it does not mutate contract storage directly or call other accounts.
Its primary purpose is to separate business rules from hard-coded Java Core and storage logic, representing them instead as versioned artifacts with immutable descriptors.
Differences from a general EVM contract
| Area | General EVM contract | Native Program |
|---|---|---|
| Execution purpose | Mutate application state | Validate declared StateCell transitions |
| Revision | General Osaka profile | Paris, pinned in the descriptor |
| State access | EVM storage and account host | Inputs and outputs in canonical context |
| External calls | Allowed | Forbidden |
SLOAD / SSTORE | Allowed | Forbidden |
| Contract creation | Allowed | Forbidden |
| Result | EVM state, logs, and return value | Validation result for authorization, state transitions, and events |
Solidity and the EVM serve as the language and engine for deterministic validators. Core applies the actual ledger change only after exact-matching the Native Program result against the transaction's declared transition.
Execution flow
State-closed validator
A Native Program receives all required state through the transaction and the context built by Core:
- chain ID, block height, and timestamp;
- transaction hash, signer, and intent hash;
- input and output StateCells;
- signed asset scope;
- Asset, Policy, and Supply views validated by Core;
- method selector and arguments; and
- protocol fee.
The runtime cannot use:
SLOADorSSTORE;- account balance or code queries;
- external calls;
- contract creation; or
- self-destruct.
Executable instructions are inspected before a runtime is installed in the registry. The inspection rejects forbidden behavior while correctly skipping PUSHn data rather than misinterpreting it as opcodes.
This structure prevents a validator from producing different results based on node-local databases or call order, and makes the access set derivable from transaction inputs and outputs.
Program identity and revision
Native Programs separate stable identity from immutable revisions.
| Value | Role |
|---|---|
programId | Revision-independent program identity and Program State namespace |
revision | Positive UINT32 revision number |
descriptorHash | Identity of one immutable revision descriptor |
runtimeCodeHash | Content address of the runtime bytecode |
previousDescriptorHash | Link to the previous descriptor in the revision chain |
A transaction's ProgramInvocation signs all of the following:
programId
expectedRevision
expectedDescriptorHash
methodSelector
assetScopes
arguments
Execution is rejected if the registry's active revision differs from the revision and hash expected by the transaction. A PINNED consumer uses an exact revision; a FOLLOW_GOVERNED consumer resolves the available governance default at the execution height.
Registry and consensus state
Program identities, revision descriptors, runtimes, status, defaults, and authority schedules are stored in NATIVE_SYSTEM StateCells. Artifact manifests and classpath/filesystem loaders are inputs used to create that state during genesis or publication; they do not overwrite consensus state with a separate runtime catalog.
Runtimes are content-addressed by code hash, and (programId, revision, descriptorHash) forms the execution-cache key. Both admission and actual block execution validate the revision and hash.
Program classes and capabilities
A program class sets the upper bound on publication and activation privileges.
USER: a general validator installable through the public publication pathASSET_CONTROLLER: a privileged program that validates Native Asset transitionsPROTOCOL: a protocol-level privileged program
A public USER installation cannot create privileged classes or capabilities. Asset Controller and Protocol classes must pass the governance and activator policy pinned by the profile.
Capabilities restrict the effects that a validator result may request. Returning a canonical result from bytecode does not grant authorization, event, or state-transition capabilities absent from the descriptor.
Built-in fungible asset controllers
Current artifacts include the Native Asset Registry and three controller tiers.
| Program | Function | Ordinary owner transfer | Representative configuration |
|---|---|---|---|
| Asset Registry | Registers non-zero Asset IDs and validates descriptors and zero supply | Not applicable | Registry |
| Basic Controller | Allowance approval/update/revoke and transferFrom | Direct Cell | NIGO |
| Mintable Controller | Basic plus mint/burn | Direct Cell | BWGC example |
| Managed Controller | Mintable plus controller-validated transfer | Program-validated Cell | KRWN example |
Representative asset names are display information that helps explain profiles. Consensus state stores exact programId, revision mode, revision, and descriptor hash rather than these strings.
The existence of a controller does not mean the policy for a particular security or asset is complete. Investor eligibility, transfer restrictions, freezes, forced transfers, rights exercises, and institutional integration require separate product and policy design and validation.
Lifecycle governance
A governed program can change revision and authority schedules through canonical lifecycle actions.
INSTALL
STAGE
ACTIVATE
SET_DEFAULT
DEACTIVATE
ROTATE_AUTHORITY
MIGRATE
ABORT
The action wire binds expected and target revisions, descriptor hashes, activation height, authority revision, lifecycle nonce, and deadline. The action hash is a content hash, not an independent authorization signature.
The fixed Lifecycle Extension is the stateful protocol boundary through which a general EVM contract may request a governance action.
address: 0x4e49474f00000000000000000000000000000001
ABI: requestLifecycle(bytes) -> bytes32
Only direct CALL, zero value, and the strict ABI are allowed. Authorization exact-matches the EVM frame's msg.sender against current StateCell authority; it does not trust tx.origin or a role encoded in calldata.
Consumed and produced Cells and events from an approved action bind into the transaction proof journal. All are rolled back if a parent frame reverts or runs out of gas. State or authority rejection is transaction-fatal so a contract cannot catch it and partially commit only the governance effect.
MIGRATE and ABORT fail closed while no current state-migration machine exists.
Public publication
Artifact publication and installation for a public USER Program use a separate Publication Extension.
address: 0x4e49474f00000000000000000000000000000002
ABI: requestPublication(bytes) -> bytes32
actions: PUBLISH, INSTALL_USER
PUBLISH writes the descriptor and runtime to content-addressed StateCells. INSTALL_USER derives a program ID from the chain ID, msg.sender, and salt, then installs published revision 1.
The public path can create only USER, IMMUTABLE, and capabilities within the allowed ceiling. It remains separate from privileged asset and protocol activation paths.
Artifacts
Each artifact revision contains:
| File | Role |
|---|---|
runtime.bin | Deployed runtime bytecode executed by NigoVM |
manifest.json | Compiler, identity, revision, hash, capability, and schema manifest |
abi.json | Solidity ABI for development and analysis |
opcodes.txt | Runtime opcode review material |
The build pins the compiler profile and source/runtime hashes, then validates generated output as an exact gate. An operating node uses the validated runtime and descriptor rather than recompiling Solidity source.
Current boundaries
- Current built-in Programs use immutable revision 1 by default.
- Lifecycle scheduling and publication foundations do not imply that every business migration is implemented.
- The Rust consumer is classified as
SPECIFIED_NOT_IMPLEMENTEDin canonical vectors. - The Native Program foundation alone does not automatically provide regulatory compliance for regulated assets or STO workflows.