Lightweight Contracts Design

Architecture of the Ardor Lightweight Contracts

Lightweight Contracts Design. Image credit: Fleur Treurniet from Unplash.

See all lightweight contracts articles

The design of the Ardor Lightweight Contracts feature continues to progress rapidly. I would like to share some of the design decisions taken based on our prototyping efforts and your feedback.


To support versioning of contracts we made the contract deployment a two- step process. First, the contract class file itself is deployed as a cloud data transaction, then a contract reference transaction is submitted from the account running the contract which references the cloud data transaction. The name of the contract reference is the unique identifier of the contract for the account, the value of the reference is a JSON format which represents the contract setup parameters.

To save developers the hassle of submitting two separate transactions, we developed the contract manager utility which loads the contract data and submits it to the blockchain together with its contract reference. Deploying a contract now requires a single command line tool invocation which can be further automated.

The advantage of this new approach is that trigger transaction now references the contract reference by name when invoking the contract, i.e. {“contract”:”HelloWorld”} instead of by the transaction hash used in earlier prototypes. This means that if a bug is found in the original HelloWorld contract and a new version is deployed. All the developer has to do is deploy the new contract version and modify the contract reference to reference it, all client applications will immediately switch to using the updated version without any intervention.


Lightweight contracts now have three levels of configuration parameters stored in JSON format.

Contract Runner Parameters— configures the operation of the contract runner and private contract parameters which cannot be stored on the Blockchain, for example account passphrases. Defined in the contracts.json configuration file of the node running the addon. These parameters are shared by all contracts deployed on this specific contract runner.

Contract Setup Parameters— configures the specific contract parameters for the particular account running the contract. These parameters are stored on the Blockchain as the value of the contract reference transaction.

Contract Runtime Parameters — for contracts triggered by a trigger transaction or a voucher, the transaction itself provides parameters to the contract as an attached message, these parameters are specific to this invocation of the contract.


There are four optional methods to trigger a contract.

By Transaction — the contract is triggered by a transaction which specifies the contract name as an attached message. The trigger transaction is stored on the Blockchain, it can pass runtime parameters to the contract.

By Voucher — similar to “By Transaction” but instead of an actual transaction submitted to the Blockchain, the trigger transaction information is encapsulated into a digitally signed voucher which is submitted using an API call to the node running the contract. Vouchers can be used in case the account invoking the contract cannot submit a transaction, or cannot afford to pay the transaction fee, or simply to reduce Blockchain bloat. A typical example is a faucet contract which is used to fund new accounts.

By Block — contracts can be triggered at a certain block height without requiring a trigger transaction. This type of contract will run after the contract runner node receives a new block. Typically, the contract will check the content of the block for new transactions or other conditions and if necessary execute its code. This type of contract is typical in case of a daemon process or an Oracle which executes during specific block intervals regardless of which transactions were submitted.

By API — provides an alternative method to trigger a contract by simply passing the parameters it expects. The actual parameters passed by the API are contract specific. This trigger is useful for simulating contract execution, testing, and validation. To prevent misuse it requires the admin password of the node operator.


To make sure contract execution is reproducible and consistent, we use several existing Blockchain tools.

EC Block — to ensure a certain block does not trigger a contract and then disappears when a better Blockchain fork is received, every transaction submitted by a contract references the last block in the Blockchain as its EC block. This means that if this block is replaced by a better fork, the transactions submitted by the contract it triggered will never get confirmed, and will eventually expire.

Referenced Transaction — to ensure that a trigger transaction does not trigger a contract and then expire when a better fork is received, every transaction submitted by a contract references the trigger transaction for the contract using the reference transaction link. This makes sure that any transaction submitted by the contract is confirmed only if the contract trigger transaction remains confirmed.

Transaction Timestamp — to make sure the content of transactions submitted by a contract is reproducible regardless of the time in which the transaction is submitted. The transaction timestamp is always set to the time of the last block.

To summarize, the design of the lightweight contract feature is rapidly progressing. In the upcoming days, we will release additional examples of new contracts functionality which addresses real use cases, explains how transaction vouchers work, and how they can be easily integrated with contracts to unleash the full power of decentralized applications.