Skip to content

Commit

Permalink
Add assertion that disbursement token value must be greater than or e…
Browse files Browse the repository at this point in the history
…qual to repayment amount
  • Loading branch information
rexcfnghk committed Sep 29, 2024
1 parent f00809d commit ded2e37
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 2 deletions.
8 changes: 6 additions & 2 deletions Q3/daml/LoanWorkflowWithRepayment.daml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ createTokenForChange : Party -> Party -> Decimal -> [Token] -> Optional Token
createTokenForChange minter owner repayment tokens =
if totalTokenValue <= repayment
then None
else Some $ Token with value = repayment - totalTokenValue; ..
else Some $ Token with value = totalTokenValue - repayment; ..
where totalTokenValue = tokenValue tokens

addChangeToDisbursements : Optional (ContractId Token) -> [ContractId Token] -> [ContractId Token]
Expand Down Expand Up @@ -131,10 +131,14 @@ template Loan
assertMsg "Repayment amount must be greater than zero" (amount > 0.0)

(repaymentRestrictionCid, repaymentRestriction) <- fetchByKey @RepaymentRestriction (bank, borrower, loanId)
assertMsg "Repayment amount must be greater than minimum amount specified in repayment restriction" (amount > repaymentRestriction.minimumAmount)
assertMsg "Repayment amount must be greater than minimum amount specified in repayment restriction" (amount >= repaymentRestriction.minimumAmount)

existingDisbursements <- getDisbursementMap disbursementCids

let existingTokenValue = tokenValue $ values existingDisbursements

assertMsg "Existing token value must be greater than or equal to repayment amount" (existingTokenValue > amount)

let repaymentTokens = getTokensForRepayment amount existingDisbursements
repaymentValue = tokenValue $ values repaymentTokens
newRepaidAmount = repaidAmount + repaymentValue
Expand Down
94 changes: 94 additions & 0 deletions Q3/daml/LoanWorkflowWithRepaymentTests.daml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module LoanWorkflowWithRepaymentTests where
import LoanWorkflowWithRepayment
import DA.Assert
import DA.Functor
import DA.List
import DA.Optional
import Daml.Script

Expand Down Expand Up @@ -231,3 +232,96 @@ test_borrowerCanCompletelyRepayLoanWhenRepaymentAmountMatchesTheOnlyDisbursedTok
[borrower, bank] `submitMulti` [] $ exerciseCmd loanCid Repay with amount = 90.0; ..

assert (isNone loanCidOpt)

test_borrowerCanRepayLoanWhenRepaymentAmountIsLessThanDisbursementTokens : Script ()
test_borrowerCanRepayLoanWhenRepaymentAmountIsLessThanDisbursementTokens = do
-- Arrange
[ bank, borrower ] <- allocateParties [ "bank", "borrower" ]
let limit = 100.0

loanLimitCid <- bank `submit` createCmd LoanLimit with amount = limit; ..

let borrowAmount = 90.0
loanRequestCid <-
borrower `submit` createCmd LoanRequest with amount = borrowAmount; ..

let minimumRepaymentAmount = 10.0
let loanId = "loan1"
loanCid <- bank `submit` exerciseCmd loanRequestCid ApproveRequest with ..

-- Act
let disbursement = 90.0
(tokenCid, loanCid) <-
borrower `submit` exerciseCmd loanCid Disburse with amount = disbursement; actor = borrower

Some loanCid <-
[borrower, bank] `submitMulti` [] $ exerciseCmd loanCid Repay with amount = 10.0; ..

Some newLoan <- borrower `queryContractId` loanCid

-- Assert
1 === length newLoan.disbursementCids
Some token <- borrower `queryContractId` head newLoan.disbursementCids
80.0 === token.value

test_borrowerCanRepayLoanWhenRepaymentAmountConsumesOneToken : Script ()
test_borrowerCanRepayLoanWhenRepaymentAmountConsumesOneToken = do
-- Arrange
[ bank, borrower ] <- allocateParties [ "bank", "borrower" ]
let limit = 100.0

loanLimitCid <- bank `submit` createCmd LoanLimit with amount = limit; ..

let borrowAmount = 90.0
loanRequestCid <-
borrower `submit` createCmd LoanRequest with amount = borrowAmount; ..

let minimumRepaymentAmount = 10.0
let loanId = "loan1"
loanCid <- bank `submit` exerciseCmd loanRequestCid ApproveRequest with ..

let disbursement = 20.0
(tokenCid, loanCid) <-
borrower `submit` exerciseCmd loanCid Disburse with amount = disbursement; actor = borrower

let disbursement = 10.0
(tokenCid, loanCid) <-
borrower `submit` exerciseCmd loanCid Disburse with amount = disbursement; actor = borrower

-- Act
Some loanCid <-
[borrower, bank] `submitMulti` [] $ exerciseCmd loanCid Repay with amount = 10.0; ..

Some newLoan <- borrower `queryContractId` loanCid

-- Assert
tokens <- mapA (fmap fromSome . (borrower `queryContractId`)) newLoan.disbursementCids
20.0 === tokenValue tokens

test_borrowerRepayingLoanShouldFailWhenRepaymentAmountIsGreaterThanRebursedTokens : Script ()
test_borrowerRepayingLoanShouldFailWhenRepaymentAmountIsGreaterThanRebursedTokens = do
-- Arrange
[ bank, borrower ] <- allocateParties [ "bank", "borrower" ]
let limit = 100.0

loanLimitCid <- bank `submit` createCmd LoanLimit with amount = limit; ..

let borrowAmount = 90.0
loanRequestCid <-
borrower `submit` createCmd LoanRequest with amount = borrowAmount; ..

let minimumRepaymentAmount = 10.0
let loanId = "loan1"
loanCid <- bank `submit` exerciseCmd loanRequestCid ApproveRequest with ..

let disbursement = 20.0
(tokenCid, loanCid) <-
borrower `submit` exerciseCmd loanCid Disburse with amount = disbursement; actor = borrower

let disbursement = 10.0
(tokenCid, loanCid) <-
borrower `submit` exerciseCmd loanCid Disburse with amount = disbursement; actor = borrower

-- Act
[borrower, bank] `submitMultiMustFail` [] $ exerciseCmd loanCid Repay with amount = 50.0; ..

0 comments on commit ded2e37

Please sign in to comment.