Skip to content

Instantly share code, notes, and snippets.

@marco-martins
Created June 24, 2022 10:26
Show Gist options
  • Save marco-martins/68713a16a3ab8dd186ce560874ea25c2 to your computer and use it in GitHub Desktop.
Save marco-martins/68713a16a3ab8dd186ce560874ea25c2 to your computer and use it in GitHub Desktop.
Bank Loan Using Compound
{-# LANGUAGE OverloadedStrings #-}
module Example where
import Language.Marlowe.Extended
-- Simulates an auto loan for a used car with compound interest. Native token represents title for the car.
-- Input loan amount. We imagine the car costs 5000 ADA
loan_amount_in_ADA = 5000 :: Double
-- Input number of payments. We imagine 36 monthly payments.
number_of_payments = 36 :: Integer
-- Input interest rate in percent per year. This goes to the bank.
-- We imagine 8% interest
interest_in_percent_per_year = 8 :: Double
-- Input the number of payments per year.
-- The formula compounds the interest every payment period.
-- Monthly in this case but you can set it to whatever you want using the periods_per_year field.
-- We imagine monthly payments.
periods_per_year = 12 :: Integer
{-
Code generation based on Haskell example by a_juggler which is linked below.
https://gist.github.com/ajuggler/c9b2617295112cb2f4839f4cda4a6b58
Thank you @a_juggler for providing this example of foldr and replicate.
@IndyCoin did the code generation using a different method as seen below:
https://gist.github.com/CardanoDVPR/0a3bc218d0ab98564d723cc4e40dfebc
Lars has provided a nice example of code generation found at the link below and is discussed in the Lesson 4 at 30 minutes into the video:
https://github.com/input-output-hk/marlowe-pioneer-program/blob/lecture05/code/src/lecture04/multi-pay.hs
From lesson 5, the ACTUS demo app has no trouble with interest payments.
http://demo.actusfrf.org/form/PAM
That was the inspiration for working with compound interest for this homework assignment.
The bank earns ADA from interest on the car loan.
Native token (serves as title for the car) is automatically transfered to borrower if all payments are made on time.
Thanks to support from Hernan Rajchert (our own @Sherman in the Marlowe discord) for the help on stackexchange.
https://cardano.stackexchange.com/questions/8459/nft-support-for-marlowe
-}
-- Imagining a car loan smart contract in Marlowe for 5000 ADA as per the example found at the following link.
-- https://www.double-entry-bookkeeping.com/periodic-payment/auto-loan-payment/
-- payment_amount_in_ADA = PV x i / (1 - 1 / (1 + i)^n)
-- PV = Value of the auto loan 5,000
-- n = number of months = 3 x 12 = 36
-- i = nominal rate = 8%/12 per month
-- payment_amount_in_ADA = 5000 x (8%/12) / (1 - 1 / (1 + 8%/12)^36)
-- payment_amount_in_ADA = 156.68
interest_in_decimal_per_period = interest_in_percent_per_year / 100 / (fromIntegral periods_per_year)
--payment_amount_in_ADA = PV x i / (1 - 1 / (1 + i) ^ n)
--payment_amount_in_ADA = 5000 x (.08/12) / (1 - 1 / (1 + .08/12) ^ 36) = 156.68
payment_amount_in_ADA = loan_amount_in_ADA * interest_in_decimal_per_period / (1 - 1 / (1 + interest_in_decimal_per_period) ^ number_of_payments) :: Double
-- Specify function to convert ADA to Lovelace
convert_ADA_To_Lovelace x = x * 1000000
loan_amount_in_lovelace_as_type_double = convert_ADA_To_Lovelace loan_amount_in_ADA
loan_amount_in_lovelace = floor loan_amount_in_lovelace_as_type_double :: Integer
payment_amount_in_lovelace_as_type_double = convert_ADA_To_Lovelace payment_amount_in_ADA
payment_amount_in_lovelace = floor payment_amount_in_lovelace_as_type_double :: Integer
main :: IO ()
main = printJSON $ contract loan_amount_in_lovelace payment_amount_in_lovelace number_of_payments (TimeParam "Deadline Bank Deposit") (TimeParam "Payment Deadline")
contract :: Integer -> Integer -> Integer -> Timeout -> Timeout -> Contract
contract loan_amount_in_lovelace payment_amount_in_lovelace number_of_payments deadlineBankDeposit paymentDeadline =
When
[Case
(Deposit
(Role "Bank")
(Role "Bank")
(Token "e0d123" "Car Title")
(Constant 1)
)
(deposits number_of_payments)]
(TimeParam "deadlineBankDeposit")
Close
where
deposits :: Integer -> Contract
deposits m = foldr addContract payClient $ replicate (fromIntegral m) True
where
addContract :: Bool -> Contract -> Contract
addContract x y = case x of
True -> (When [Case deposit y] paymentDeadline Close)
False -> Close
payClient :: Contract
payClient = (Pay
(Role "Bank")
(Account (Role "Borrower"))
(Token "e0d123" "Car Title")
(Constant 1)
Close
)
deposit :: Action
deposit =
Deposit
(Role "Bank")
(Role "Borrower")
(Token "" "")
(Constant payment_amount_in_lovelace)
{"valueParameterInfo":[],"timeParameterDescriptions":[],"roleDescriptions":[],"contractType":"Other","contractShortDescription":"Unknown","contractName":"Unknown","contractLongDescription":"We couldn't find information about this contract","choiceInfo":[]}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment