Bond Implementation

I am looking to create a smart contract for bond payments. The idea is that a bond holder will get an asset representing the bond, receive periodic coupon payments and then at maturity can exchange the bond for the principal.

I am unsure whether to use a non-fungible or fungible asset to represent the bond. The challenge I am trying to solve is knowing whether a specific coupon payment has or has not been collected for a bond. This is made harder by the fact that I want people to be able to transfer the bond between themselves.

If a non-fungible asset is used then the smart contract would need to know about every single asset ID which I don’t think is possible with limitted global state.

If a fungible asset is used then there is no obvious way of distinguishing between an asset that has collected a coupon payment and one that has not. One option would be to create x number of assets for the x different coupon payments, although again the smart contract would need to know the x asset IDs.

Alternatively with a fungible token maybe you can track the asset somehow in the smart contract? You could record in the local state of the bond owner how many coupon payments they have collected. When the asset is transfered you would have to copy over this local state to the new owner.

Would love some feedback and ideas on my proposed approaches. I am new to Algorand so there is probably a solution that I am completely ignoring. Maybe there is a way to collectively pay all bond owners at the same time which would avoid my problem entirely?

These are really good questions.

I don’t think there is an easy way to securely pay all bond owners at the same time, except if there are fewer than 16 of them and you can do a group transaction.

I am thinking of two potential solutions (that can definitely be refined):

  1. Do not use at all a token and instead store in local storage the details about the bond. To transfer the bond to someone else, you need to do a smart contract call (instead of an ASA transfer). This has the advantage of being quite easy to implement but you lose the advantage of ASA transfer.
  2. Each time a bond is issued, you create a new smart contract address (stateless TEAL) that will be the creator of the bond NFT and you store the bond parameters in the local storage of this new contract. Note that the stateful TEAL application can generate itself the smart contract address as it consists of the hash of the smart contract (that can be reconstructed as the concatenation of several strings). There is an additional trick to reduce size of the stateful application described at the bottom of this post. Note also that the stateful TEAL application can access the creator of any NFT so can check it is an NFT mapping to a real bond and retrieve the bond parameters from there.

Trick to reduce the size of the stateful application: The stateless smart contract will consist of three parts (once compiled): prefix, some value x to distinguish each bond, suffix.
The prefix is short (most likely just the version number and the bytecblock instruction) but the suffix can be long. What you can do is hardcode the hash of the suffix instead of the suffix in the application and require one argument of the application to be the suffix itself.
This way you moved the long suffix from the program (very constrained in size) to the arguments (much less constrained in size).

1 Like

I’d like to throw in an additional idea to what @fabrice mentioned. Since making changes to many accounts might not be feasable, what about making a change to a global account that would render additional deferred value to each of the individual account ?

Concretly, i’m referring to the same model the node is using in order to distribute rewards. Instead of updating millions of accounts, the node add a global “reward level” variable, and each account contain its own reward level. When an account is being modified, it’s rewards are being rendered by diffing the global reward level over the local account reward level.

Thank you for your suggestions.

I don’t quite understand the second solution. My understanding is that you are referring to a ‘Contract Account - Stateless Smart Contract’. Would every bond have its own Contract Account and how would you store any parameters in a stateless contract? Also how would these Contract Accounts be created initially and then facilitate bond transfers?

Is there somewhere I can read more about the model the node is using in order to distrubute rewards?

The model used by the node is described in the protocol specification ( specs/ledger.md at master · algorandfoundation/specs · GitHub ).

Regarding the way Algorand distributes rewards, see https://www.algorand.com/resources/blog/rewards-technical-overview

Regarding the second solution, here is how I was thinking of it.
You create a stateless smart contract C_x that does the following:

accept any transaction as long as it’s called in a group with an application call to your application App. The application App will be responsible to only allow the transactions described below.

The stateless smart contract also contains an ID x that it just discards, just to distinguish between each bond. The application App contains a counter X in global storage used to initialize x.
Instead of using a counter, you may use other values such as the hash of the calling account A and a byte chosen by A.

Then, to issue the bond to an account A, you do the following:

  1. First, you need to create the new smart contract account C_x and store in local storage of A that it should receive this NFT from C_x. You do that using the following group of transactions:
    a. Opt-in application call of App by A that will make A opt-in to App and store in A’s local storage that it is allowed to get the bond with ID X. (X is then incremented.)
    b. Payment from A to buy the bond
    c. Payment from A to the stateless smart contract C_x of 1 Algo to be able to issue transactions from C_x
    d. Creation of a bond NFT by C_x
    e. Opt-in application call of App by C_x to store in C_x’s local state the bond parameters.
  2. Second, the account A can opt-in to the NFT created by C_x
  3. Third, the account A can get the NFT by doing the following group of transactions:
    a. Close-out application call of App by A that will see that A is still owed the NFT created by C_x.
    b. Asset transfer from C_x to A

The reason that you need to do the process in 3 steps rather than a big transaction is that you cannot know the asset ID created by C_x until the transaction is executed. So you cannot do the asset transfer of the NFT bond immediately. Instead, you need to store in local storage of A that A is meant to receive this NFT. And then make the asset transfer.

1 Like

I propose another possibility, inspired by the original meaning of a bond coupon. From Coupon Definition

Coupon Bonds

The term “coupon” originally refers to actual detachable coupons affixed to bond certificates. Bonds with coupons, known as coupon bonds or bearer bonds, are not registered, meaning that possession of them constitutes ownership. To collect an interest payment, the investor has to present the physical coupon.

The idea

Create an ASA corresponding to each payment deadline, and the the final principal. When you buy a “bond”, you get one of each. When you wish to get paid for a coupon, you send it to a smart contract that pays you out (assuming the deadline associated with the coupon has passed). Same for the principal.

Now the coupons are individually tradable which seems like an advantage. And the “tracking” is only on the number of payment deadlines, rather than number of bonds issued.

1 Like

I’m not sure I understand your solution correctly @fabrice .

  1. C_x is an escrow account (stateless smart contract), right - this is what I get from 1 and 1.b?
  2. How C_x can create an NFT (ref: 1 and 1.d)?
  3. In step 1.b: why A has to make a payment to buy a bond?
  4. In 1.e what kind of parameters do you have in mind? Like, bond value in USD? This should be done during maturity - at the time when a user is requesting the bond.
  5. I guess the NFT will be redeemable to the underlying bond value, right (set in 1.e - my point above).
    It sounds a bit over complexified (especially the part with NFT and then redeeming that NFT).

I’m thinking about something along this lines, @jannotti. Let me describe the process:

Bond is represented by a fungible token - ASA. Let’s call it B0.
Whenever we know the coupon parameters: interest per unit of B0 token, we create:

  • new token B1
  • escrow escrow account: DEX_0. The code of the contract will store: B0 maturity date, interest rate: R_0.
    The DEX-b0 will have store a whole supply of B1 tokens, which is equal to the supply of B0 tokens and a supply of coupons equal to the total value of the interest with appropriate denomination.
    At maturity, B0 holder will be able to use DEX_0 to exchange B0 to B1 and receive coupons. After exchange, the B0 will be locked forever in DEX_0 (essentially burned), and a user will have equal amount of B1 + number of C coupons = B0_user_exchanged x R_b. The coupons have a constant exchange rate to the principle, eg USD. We can say that 1e9 coupons = 1 USD. If there is a well adopted USD token with sufficient precision (eg 9 decimals) then we could use it directly instead of the coupons, but then we would need to lock that USD, which may not be optimal.

Now we can repeat: B2 will represent same token at next maturity, we create DEX_1 and set R_1
For each exchange user will need to optInt to the DEX_n, after the exchange he will opt out from DEX_n.

We could template this algorithm in Algo Builder.

That sounds like it will work, but I’m not sure why the buyer needs to keep exchanging his B0 to B1, and so on. How about when you buy the bond, you get one P token (representing the amount you get back when the bond fully matures, often that will be the principal), and one each of several coupons tokens, C1, C2, C3, etc. There exists a smart contract for each kind of token (P, C1, C2, etc…) that contract is willing to take its associated token, and return something (whatever the coupon or P redeems for) if the maturity date for the coupon or complete bond has passed.

This way, every single bit of the bond is tradeable. I can sell you my C5 if you want it, it doesn’t affect my ability to redeem the other coupons or the P token.

If you cycle through B1, B2, etc, then you can’t trade off individual coupons.

It sounds like you have a requirement for setting the payment amounts after selling the bonds and giving out P, C1, C2… That should also be no problem as you can configure the redeeming smart contracts later. Or, you give a B token at purchase time, and create the P, C1… tokens later and given them for a B.

(of course, it could be a single smart contract for redemption that knows how to handle all of the different token types)

Hi guys,

I believe that the ASA way described by jannotti is better for bonds use case, however I see two major challanges:

  1. How do you ensure that the bond will be paid?
    If A issues the bonds, receives fe $100. D has debt $103 payable at maturity date.
    B buys the bonds in mid term for $101
    C buys the bond one day before expiration for $102
    Now D will not pay the bond at maturity date. What happens now?

  2. How do you ensure that you are not financing terrorism or illegal activity? If C is the drug dealer or politician who takes bribes, how do you ensure that B will not accept dirty money?

2 Likes

@jannotti is definitely better than mine for that use case.

That being said, here are the answers to your questions:

  1. C_x a smart contract account, but not an escrow in the sense that it will not keep funds. It will only be used to create the NFT.
  2. C_x is a contract account, so as any account, it can create NFT. The TEAL script of C_x allows issuing a transaction from C_x to create an NFT
  3. I’m assuming Alice has to pay for the bond. But if it’s not the case, if it’s given to her, this step is not needed.
  4. It can be the number / amount / time of interest payments, and the value of the principal.
  5. @jannotti is definitely simpler for that use case.

For the right solution of this problem we need to have a right specification, which we are missing.

I assumed following specification:

  1. coupons are only created and delivered during certain period (In my proposal it’s B0, B1, … maturity). So you are not able to receive and trade future coupons.
  2. Nobody is able to use / trade future coupons - because we don’t know who will be a right beneficent of it.
  3. for each bond, coupons at certain maturity, can be delivered only once. That’s why I create B0, B1 … to make sure that bonds at certain period matured and should claim coupons to go to the next period.
  4. Anyone can trade any available bonds. So, if we are already in B4, B0 are still tradeable unless they have been redeemed for C and B1 in `DEX_0 (locked / burned).

In your solution, I understand that (please correct me if I’m wrong or which assumption should be corrected to better reflect the market reality):

  • We create C1, C2 … coupons upfront.
  • Cx holder can redeem the coupon in Cx_contract only at Cx maturity.
  • The initial bond owner will receive all future coupons, which will give him additional assets he shouldn’t have. Specifically: if he will sell all his P bonds, he will still have C1, C2 … which will give him additional value he shouldn’t have.

BTW: In my proposal, we have only one ASA for coupons: C (we don’t have C1, C2, …). The coupon will have a constant denomination. Eg 1C = 0.0001 USD . Or 1C = 0.0001 USD + 2 something_else.

I’m not sure if coupons have same representation across different epochs (so only the ratio per bond changes). If market expects more flexibility, then we would need to create a family coupons as in your proposal, and DEX_n-1 will redeem B_n-1 to B_n and C_n.

I think everything you said is correct technically about my proposal, though I’d say your last bullet’s “shouldn’t have” clause is not a technical point, it’s a decision you can make about your use-case. For example, I think it’s perfectly reasonable that I could sell all my coupons to someone else, yet retain P, or vice versa. Perhaps I bought the bond and need some money now. I can sell my right to a future redeemable coupon by trading that coupon now with a third party. The buyer probably won’t pay me the full amount, due to the time value of money, and counterparty risk. That’s fine.

Using ASA in their “bare form” as I recommended, tends to support these flexible arrangements. There are some tools to give the issuer a bit more control - things like freezing and clawback. The nice thing here is that everyone can relatively easily understand your asset because it uses well-defined primitives. You can go out and implement just about anything you want as a smart contract, but now people have to pay very close attention to what they can and can’t do with your product. That’s fine, but in some sense it becomes impossible to give advice about the “best” way to do such a thing. If you have very specific needs to control the way you tokens can be redeemed, fractionalized, resold, etc - then you will use smart contracts, but the result will be bespoke. It does exactly what you code it to do, so it’s the best way if it has the properties you want!

Thanks for the response.
Yes, using ASA is a clear advantage.

I can sell my right to a future redeemable coupon by trading that coupon now with a third party

I don’t know if this is correct. This allows to trade future revenues from bond without the bond itself. To note - one may not even hold the bond in the future when selling the future coupons at present. More specifically, this allows to sell bond without a promise of future revenues based on that bond (the coupons). This may not be legally correct. It would also classify coupons as futures. Moreover this will make the bond pricing different - because the bond won’t have any coupon yield.

1 Like

We are implementing a Bond Token template. Here is the spec, would love to get you review. Don’t hesitate to comment in the document:

2 Likes

Nice,looking forward to its completion

is there a website for this?