Skip to main content

Zero-Coupon bond


A Zero-Coupon bond is a bond in which the face value is repaid some predefined time after it has been released (maturity time).

In this contract, the present value of the bond (value at which the bond is traded) is computed as the face value (value at which the bond is redeemed at maturity time) minus a discount percent of face value.

A detailed presentation of the process is available in the Zero-Coupon Bond DApp example.



issueraddressBond issuer's address.
subscriberaddressBond subscriber's address.
facevaluetezValue at which the bond is redeemed at maturity time.
discoutrationalDiscount applied to facevalue to compute present value (at emission)
maturitydurationdurationDuration before maturity time.
paybackdurationdurationDuration of payback period after maturity date
issuersignedbooltrue is issuer has signed, false otherwise.
subscribersignedbooltrue is subscriber has signed, false otherwise.
_statestatesOne of Created, Signed, Terminated, Disputed


toSignedCalled by sign to set contract's state to Signed.
signCalled by issuer or subscriber. subscriber must transfer the present value to the contract.
terminateCalled by issuer during payback period, to transfer the face value to subscriber.
disputeCalled by subscriber if issuer has not terminated the contract in the payback period.


archetype zero_coupon_bond (
issuer : address,
subscriber : address,
facevalue : tez,
discount : rational,
maturityduration : duration,
paybackduration : duration,
issuersigned : bool,
subscribersigned : bool

variable signaturedate : option<date> = none

states =
| Created initial
| Signed
| Terminated
| Disputed

transition toSigned() {
called by selfaddress
from Created to Signed with effect {
signaturedate := some(now)

entry sign () {
if caller = issuer then
issuersigned := true
else if caller = subscriber then begin
subscribersigned := true;
var presentvalue = discount * facevalue;
dorequire(transferred >= presentvalue, "SUBSCRIBER_INVALID_TRANSFERRED");
transfer presentvalue to issuer;
else fail("CALLER_NOT_A_SIGNER");
if issuersigned and subscribersigned then
transfer 0tz to entry self.toSigned();

transition terminate () {
called by issuer
from Signed to Terminated when {
match signaturedate with
| some(d) ->
d + maturityduration <= now <= d + maturityduration + paybackduration and
transferred >= facevalue
| none -> false
} with effect {
transfer facevalue to subscriber

transition dispute () {
called by subscriber
from Signed to Disputed when {
match signaturedate with
| some(d) ->
d + maturityduration + paybackduration <= now
| none -> false