Bytom Smart Contracts that you can use right now: Time deposits & Financial bonds on the blockchain

Dimitris Sfounis
7 min readMay 20, 2019

--

This article is part of a series on the ready-to-use Smart Contracts of Bytom, contracts that any user can freely use now for his own needs.
The Bytom team regularly release new Smart Contract templates as part of their equity and main bytom GitHub repos, but the more advanced of these templates are actually ready to use by themselves, with minimal work.

We will describe the contracts named FixedLimitCollect and FixedLimitProfit — they’re part of the same “Contract” group as one completes the other.
And while they’re one of the most complicated smart contract templates released by the Bytom dev team, I am of the opinion that it’s one of the most useful, and one that successfully manages to digitize one of the real-world’s most important banking procedures: Time deposits and rewards at the end of term.

Contract workflow

FixedLimitCollect & FixedLimitProfit workflow

The FixedLimitCollect contract is a BYTOM Smart Contract intended to reward users that keep an **Amount of Asset** locked with the contract and refrain from transacting with them for a time period on the blockchain.

The contract expires after a set amount of time (in this context, Block Height), returning the assets to the users.
Additionally, users receive additional profit for having locked their assets, through a sister-contract, FixedLimitProfit. The Profit Asset may or may not be the same one locked initially by the savers.

The behaviour of these two contracts closely resembles the behaviour of Time Deposits and Financial Bonds.

The workflow can be separated into two phases:

Phase 1 — Collection:

The bank decides on how many assets it wants to lock, how long, and issues its own custom asset (Bill Asset) to keep track of how many CollectionAssets users are going to deposit.
It then deploys two contracts: FixedLimitCollect and FixedLimitProfit.

On the FixedLimitCollect UTXO, it locks up the entirety of the BillAsset amount, ready to be given back to users as “receipts” of collection.
On the FixedLimitProfit UTXO, it locks up the bonus reward amount of CollectedAsset, as a “vow” of the soon-to-come reward for users that choose to invest in the Banker user.

Users are then free to deposit their own CollectedAssets (probably an asset already on the chain, like BTM or something many people could have) in the FixedLimitCollect contract, and get the corresponding amount of BillAssets back.

The FixedLimitCollect contract now stacks multiple UTXOs upon itself — many different UTXOs, from each user, are locked using its internal logic.
The FixedLimitCollect contract also creates multiple FixedLimitProfit UTXOs, which stack on-top of the FixedLimitProfit contract itself.

The 2 contracts, at the end of Phase 1, are loaded and filled with the necessary funds, ready for redistribution.

Phase 2 — Profit:

After a declared amount of time (above a specific BlockHeight), users can return their amount of BillAsset to the FixedLimitProfit smart contract.
The contract itself returns their CollectedAssets, and calculates an extra amount of CollectedAssets to be given as a reward, corresponding to how much they contributed in Phase 1.

Note that the Banker user has absolutely no part to play in Phase 2, and when reward assets are locked in the Profit contract, they are bound, trustlessly, to be given to users participating in the process.

Smart Contract source code & line-by-line analysis

The contracts were submitted on 11th Dec 2018, in Commit #28

FixedLimitCollect:

import “./FixedLimitProfit”contract FixedLimitCollect(assetDeposited: Asset,
totalAmountBill: Amount,
totalAmountCapital: Amount,
dueBlockHeight: Integer,
expireBlockHeight: Integer,
additionalBlockHeight: Integer,
banker: Program,
bankerKey: PublicKey) locks billAmount of billAsset {
clause collect(amountDeposited: Amount, saver: Program) {
verify below(dueBlockHeight)
verify amountDeposited/100000000 > 0 && amountDeposited <= billAmount && totalAmountBill <= totalAmountCapital
define sAmountDeposited: Integer = amountDeposited/100000000
define sTotalAmountBill: Integer = totalAmountBill/100000000
verify sAmountDeposited > 0 && sTotalAmountBill > 0
define gain: Integer = totalAmountCapital*sAmountDeposited/sTotalAmountBill
verify gain > 0
if amountDeposited < billAmount {
lock amountDeposited of assetDeposited with FixedLimitProfit(billAsset, totalAmountBill, totalAmountCapital, expireBlockHeight, additionalBlockHeight, banker, bankerKey)
lock amountDeposited of billAsset with saver
lock billAmount-amountDeposited of billAsset with FixedLimitCollect(assetDeposited, totalAmountBill, totalAmountCapital, dueBlockHeight, expireBlockHeight, additionalBlockHeight, banker, bankerKey)
}
else {
lock amountDeposited of assetDeposited with FixedLimitProfit(billAsset, totalAmountBill, totalAmountCapital, expireBlockHeight, additionalBlockHeight, banker, bankerKey)
lock billAmount of billAsset with saver
}
}
clause cancel(bankerSig: Signature) {
verify above(dueBlockHeight)
verify checkTxSig(bankerKey, bankerSig)
unlock billAmount of billAsset
}
}

FixedLimitProfit:

contract FixedLimitProfit(assetBill: Asset,
totalAmountBill: Amount,
totalAmountCapital: Amount,
expireBlockHeight: Integer,
additionalBlockHeight: Integer,
banker: Program,
bankerKey: PublicKey) locks capitalAmount of capitalAsset {
clause profit(amountBill: Amount, saver: Program) {
verify above(expireBlockHeight)
define sAmountBill: Integer = amountBill/100000000
define sTotalAmountBill: Integer = totalAmountBill/100000000
verify sAmountBill > 0 && sTotalAmountBill > 0 && amountBill < totalAmountBill
define gain: Integer = totalAmountCapital*sAmountBill/sTotalAmountBill
verify gain > 0
if gain < capitalAmount {
lock amountBill of assetBill with banker
lock gain of capitalAsset with saver
lock capitalAmount — gain of capitalAsset with FixedLimitProfit(assetBill, totalAmountBill, totalAmountCapital, expireBlockHeight, additionalBlockHeight, banker, bankerKey)
}
else {
lock amountBill of assetBill with banker
lock capitalAmount of capitalAsset with saver
}
}
clause cancel(bankerSig: Signature) {
verify above(additionalBlockHeight)
verify checkTxSig(bankerKey, bankerSig)
unlock capitalAmount of capitalAsset
}
}

Compiling the contracts

To compile the above source code, you can either pass them through the Equity compiler tool or send them to a running BYTOM node through the API’s compile command.

The resulting binary code for compiling them should be as follows:

======= FixedLimitProfit =======
Binary:
587a64980000005479cd9f6959790400e1f5059653790400e1f505967800a07800a09a5c7956799f9a6955797b957c967600a069c3787c9f91616481000000005b795479515b79c1695178c2515d79c16952c3527994c251005d79895c79895b79895a79895979895879895779895679890274787e008901c07ec1696393000000005b795479515b79c16951c3c2515d79c16963a4000000557acd9f69577a577aae7cac
Hex length: 328
======= FixedLimitCollect =======
Binary:
597a64370200005479cda069c35b790400e1f5059600a05c797ba19a53795579a19a695a790400e1f5059653790400e1f505967800a07800a09a6955797b957c9600a069c35b797c9f9161645b010000005b79c2547951005e79895d79895c79895b7989597989587989537a894ca4587a64980000005479cd9f6959790400e1f5059653790400e1f505967800a07800a09a5c7956799f9a6955797b957c967600a069c3787c9f91616481000000005b795479515b79c1695178c2515d79c16952c3527994c251005d79895c79895b79895a79895979895879895779895679890274787e008901c07ec1696393000000005b795479515b79c16951c3c2515d79c16963a4000000557acd9f69577a577aae7cac890274787e008901c07ec169515b79c2515d79c16952c35c7994c251005d79895c79895b79895a79895979895879895779895679895579890274787e008901c07ec1696332020000005b79c2547951005e79895d79895c79895b7989597989587989537a894ca4587a64980000005479cd9f6959790400e1f5059653790400e1f505967800a07800a09a5c7956799f9a6955797b957c967600a069c3787c9f91616481000000005b795479515b79c1695178c2515d79c16952c3527994c251005d79895c79895b79895a79895979895879895779895679890274787e008901c07ec1696393000000005b795479515b79c16951c3c2515d79c16963a4000000557acd9f69577a577aae7cac890274787e008901c07ec16951c3c2515d79c1696343020000547acd9f69587a587aae7cac
Hex length: 1158

Note the difference in length. Longer binary codes directly represents longer instruction codes, therefore longer, more complex contracts.

Clauses and parameters

FixedLimitCollect — initial parameters
locks:
billAmount of billAsset: The amount and hex id of the Asset exchanged as a certificate for the time deposit of assets — The asset that the bank gives to users participating, and the asset the users return back to FixedLimitProfit to receive their assets and reward back.

NOTE #0: Although billAssets are exchanged at a 1-to-1 ratio for CollectionAssets (to be locked with the contract), the reward asset capital can (and should, if the contract wants to reward users!) be larger than billAmount.
Rewards/gains are calculated as a percentage of certificate/billAssets deposited by the users (savers).
NOTE #1: Regarding dueBlockHeight, the relation to the other two block height parameters (expireBlockHeight, additionalBlockHeight) is as follows:

FixedLimitCollect.collect()

Description: Up until dueBlockHeight, users can send their Assets in the contract through this clause, until the limit is reached. The more you send, the bigger percentage of the final reward/profit a saver can claim for himself.

FixedLimitCollect.cancel()

FixedLimitProfit — initial parameters

locks: capitalAmount of capitalAsset: The amount and hex id of the Asset intended for rewarding savers for having participated in the sister contract: (FixedLimitCollect). Funds and rewards are available to be transferred out after a certain block height.

FixedLimitProfit.profit()

Description: After expireBlockHeight, savers can send back the billAssets (acting as certificates), to claim back their initial CollectedAssets and receive their reward for having used the time deposit contract.

FixedLimitProfit.cancel()

Same description, use and parameters as the FixedLimitCollect.cancel() clause. It’s a failsafe, in case there’s unclaimed funds leftover.

Example workflow

To verbally explain the flowchart in section one, let’s look at the process in a simplified, step-by-step manner:

  • The Bank decides on the total amount and type of asset they’d like to “freeze” in this time deposit. In our example, the amount of this capital that they want to retain, is 1000.
    The bank then issues 1000 billAssets, 1-to-1 with the capital amount, on its own. Issuing on the BYTOM blockchain is free.
  • The bank also needs to have the reward capital, in this case 200 of whatever Asset, not necessarily the same as the capital asset, but let’s assume the simple case where RewardAsset == CollectedAsset.
  • The Bank, having both the 1000 billAssets and 200 RewardAssets, as well as a relevant blockHeight (time) it wants the assets locked for, deploys two contracts:
    - One instance of the FixedLimitCollect contract, and loads it with the full 1000 billAssets
    - One instance of the FixedLimitProfit contract, and loads it with the full 200 RewardAssets
  • Users are now send their assets of type: CollectedAsset to the FixedLimitCollect contract. They receive an equal amount of billAssets back.
  • The FixedLimitCollect contract automatically re-locks the CollectedAssets sent to it to a FixedLimitProfit contract.
  • The work for FixedLimitContract is done. The collected assets stay locked inside FixedLimitProfit for as long as the blockHeight parameter dictates.
  • After that time, users can send their billAssets back to the FixedLimitProfit contract and successfully claim back:
    - Their initial CollectedAssets deposited and also
    - A reward for their participation, calculated as a percentage of their contribution.

Easy enough? I would hope so! And this contract is ready to be used right now for any institution or organization that wishes to lock any asset on the Bytom blockchain.

Make sure you keep up with the Equity contract updates from the Bytom dev team, they keep adding these useful examples at a regular basis, and they can act as your template when you’re trying to build something personalized for your own needs.

--

--