-
Notifications
You must be signed in to change notification settings - Fork 24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce MaxLTVLoanOffer class #325
Open
chrismin
wants to merge
38
commits into
master
Choose a base branch
from
ltv-class
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
38 commits
Select commit
Hold shift + click to select a range
4d71a0b
refactor: separate collateral from debt order params
saturnial 94a60c5
feat: introduce LTVLoanOffer class
saturnial b09e0f7
feat: hash creditor commitment terms
saturnial 3df8a89
feat: introduce collateralAmount getter and setter
chrismin 24f5237
feat: introduce principalPrice and collateralPrice getters and setters
chrismin b8373bf
feat: introduce signAsDebtor method
chrismin 313b236
feat: add placeholder for acceptAsDebtor
chrismin b4ac44f
refactor: remove unused interfaces
chrismin 97556c7
feat: make signAsDebtor more robust
chrismin 1bd585e
fix: add small fixes, TODOs
chrismin a4e840e
refactor: rename filename
chrismin 2661299
refactor: rename variables
chrismin d4bcdc1
feat: add scaffolding for MaxLTVLoanOffer integration test
chrismin e573d31
feat: make relayer and relayer fee optional
chrismin 5d41d64
feat: add isSignedByCreditor and isSignedByDebtor
chrismin 62608e5
test: add specs for constructor
chrismin 29ca740
feat: implement createAndSignAsCreditor
chrismin 7b8c6d0
feat: mock out commitment hash getters
chrismin 80e47c7
feat: add specs for createAndSignAsCreditor
chrismin 12d8b39
fix: rename file
chrismin bdae591
test: add specs for signAsCreditor
chrismin a1ef119
test: add generateSignedPrice util
chrismin 86d25c9
test: add spec for signAsDebtor
chrismin 4d068d9
feat: improve signAsDebtor error handling
chrismin 121aa04
test: improve signAsDebtor tests
chrismin 181838c
refactor: implement async create function to set contract addresses
chrismin a0b52e7
test: fix failing tests
chrismin cf70836
feat: introduce debtorFee to DebtOrder base class
chrismin 06feebd
refactor: make data interface more strict
chrismin 1744163
feat: unmock hashing of debtor commitment and pack parameters
chrismin afc90ae
fix: use correct types for relayer and relayer fee
chrismin 3789328
refactor: make packing of terms contract params sync
chrismin c224602
refactor: pack parameters when collateral amount is set
chrismin 51a20c4
feat: add more error handling
chrismin 7682fb7
refactor: rename to getDebtorCommitmentHash
chrismin 7455713
feat: add documentation
chrismin e6d5465
refactor: import constant from simple interest loan terms
chrismin 7d87c2c
fix: placate hound
chrismin File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
33 changes: 33 additions & 0 deletions
33
__test__/integration/max_ltv_loan_offer/max_ltv_loan_offer.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { Dharma, Web3 } from "../../../src"; | ||
|
||
jest.unmock("@dharmaprotocol/contracts"); | ||
|
||
import { VALID_MAX_LTV_LOAN_ORDER_PARAMS } from "./scenarios/valid_max_ltv_loan_order_params"; | ||
|
||
import { testConstructor } from "./runners/constructor"; | ||
import { testCreateAndSignAsCreditor } from "./runners/create_and_sign_as_creditor"; | ||
import { testSignAsCreditor } from "./runners/sign_as_creditor"; | ||
import { testSignAsDebtor } from "./runners/sign_as_debtor"; | ||
|
||
const provider = new Web3.providers.HttpProvider("http://localhost:8545"); | ||
const dharma = new Dharma(provider); | ||
|
||
describe("Max LTV Loan Offer (Integration)", () => { | ||
describe("constructor", () => { | ||
testConstructor(dharma, VALID_MAX_LTV_LOAN_ORDER_PARAMS); | ||
}); | ||
|
||
describe("createAndSignAsCreditor", async () => { | ||
await testCreateAndSignAsCreditor(dharma, VALID_MAX_LTV_LOAN_ORDER_PARAMS); | ||
}); | ||
|
||
describe("signAsCreditor", async () => { | ||
await testSignAsCreditor(dharma, VALID_MAX_LTV_LOAN_ORDER_PARAMS); | ||
}); | ||
|
||
describe("signAsDebtor", async () => { | ||
await testSignAsDebtor(dharma, VALID_MAX_LTV_LOAN_ORDER_PARAMS); | ||
}); | ||
|
||
describe("acceptAsDebtor", () => {}); | ||
}); |
31 changes: 31 additions & 0 deletions
31
__test__/integration/max_ltv_loan_offer/runners/constructor.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { Dharma } from "../../../../src"; | ||
|
||
import { MaxLTVLoanOffer } from "../../../../src/types"; | ||
|
||
import { MaxLTVParams } from "../../../../src/types/loan_offer/max_ltv"; | ||
|
||
export function testConstructor(dharma: Dharma, params: MaxLTVParams) { | ||
describe("passing valid params", () => { | ||
let loanOffer: MaxLTVLoanOffer; | ||
|
||
beforeEach(async () => { | ||
loanOffer = await MaxLTVLoanOffer.create(dharma, params); | ||
}); | ||
|
||
test("returns a MaxLTVLoanOffer", () => { | ||
expect(loanOffer).toBeInstanceOf(MaxLTVLoanOffer); | ||
}); | ||
|
||
test("not signed by the debtor", () => { | ||
const isSignedByDebtor = loanOffer.isSignedByDebtor(); | ||
|
||
expect(isSignedByDebtor).toEqual(false); | ||
}); | ||
|
||
test("not signed by the creditor", () => { | ||
const isSignedByCreditor = loanOffer.isSignedByCreditor(); | ||
|
||
expect(isSignedByCreditor).toEqual(false); | ||
}); | ||
}); | ||
} |
35 changes: 35 additions & 0 deletions
35
__test__/integration/max_ltv_loan_offer/runners/create_and_sign_as_creditor.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import { Dharma } from "../../../../src"; | ||
|
||
import { MaxLTVLoanOffer } from "../../../../src/types"; | ||
|
||
import { MaxLTVParams } from "../../../../src/types/loan_offer/max_ltv"; | ||
|
||
import { ACCOUNTS } from "../../../accounts"; | ||
|
||
export async function testCreateAndSignAsCreditor(dharma: Dharma, params: MaxLTVParams) { | ||
describe("passing valid params", () => { | ||
let loanOffer: MaxLTVLoanOffer; | ||
|
||
beforeEach(async () => { | ||
const creditor = ACCOUNTS[0].address; | ||
|
||
loanOffer = await MaxLTVLoanOffer.createAndSignAsCreditor(dharma, params, creditor); | ||
}); | ||
|
||
test("returns a MaxLTVLoanOffer", () => { | ||
expect(loanOffer).toBeInstanceOf(MaxLTVLoanOffer); | ||
}); | ||
|
||
test("not signed by the debtor", () => { | ||
const isSignedByDebtor = loanOffer.isSignedByDebtor(); | ||
|
||
expect(isSignedByDebtor).toEqual(false); | ||
}); | ||
|
||
test("is signed by the creditor", () => { | ||
const isSignedByCreditor = loanOffer.isSignedByCreditor(); | ||
|
||
expect(isSignedByCreditor).toEqual(true); | ||
}); | ||
}); | ||
} |
29 changes: 29 additions & 0 deletions
29
__test__/integration/max_ltv_loan_offer/runners/sign_as_creditor.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { Dharma } from "../../../../src"; | ||
|
||
import { MaxLTVLoanOffer } from "../../../../src/types"; | ||
|
||
import { MaxLTVParams } from "../../../../src/types/loan_offer/max_ltv"; | ||
|
||
import { ACCOUNTS } from "../../../accounts"; | ||
|
||
export async function testSignAsCreditor(dharma: Dharma, params: MaxLTVParams) { | ||
describe("passing valid params", () => { | ||
const creditor = ACCOUNTS[0].address; | ||
|
||
let loanOffer: MaxLTVLoanOffer; | ||
|
||
beforeEach(async () => { | ||
loanOffer = await MaxLTVLoanOffer.create(dharma, params); | ||
}); | ||
|
||
test("signs the offer as the creditor", async () => { | ||
const isSignedByCreditorBefore = loanOffer.isSignedByCreditor(); | ||
expect(isSignedByCreditorBefore).toBe(false); | ||
|
||
await loanOffer.signAsCreditor(creditor); | ||
|
||
const isSignedByCreditorAfter = loanOffer.isSignedByCreditor(); | ||
expect(isSignedByCreditorAfter).toBe(true); | ||
}); | ||
}); | ||
} |
132 changes: 132 additions & 0 deletions
132
__test__/integration/max_ltv_loan_offer/runners/sign_as_debtor.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
import { Dharma } from "../../../../src"; | ||
|
||
import { MaxLTVLoanOffer } from "../../../../src/types"; | ||
|
||
import { MAX_LTV_LOAN_OFFER_ERRORS, MaxLTVParams } from "../../../../src/types/loan_offer/max_ltv"; | ||
|
||
import { generateSignedPrice } from "../utils/generate_signed_price"; | ||
|
||
import { ACCOUNTS } from "../../../accounts"; | ||
|
||
export async function testSignAsDebtor(dharma: Dharma, params: MaxLTVParams) { | ||
describe("passing valid params", () => { | ||
const creditor = ACCOUNTS[0].address; | ||
const priceProvider = params.priceProvider; | ||
const debtor = ACCOUNTS[1].address; | ||
|
||
let loanOffer: MaxLTVLoanOffer; | ||
|
||
async function setPrices() { | ||
const principalTokenAddress = await dharma.contracts.getTokenAddressBySymbolAsync( | ||
params.principalToken, | ||
); | ||
const collateralTokenAddress = await dharma.contracts.getTokenAddressBySymbolAsync( | ||
params.collateralToken, | ||
); | ||
|
||
const principalPrice = await generateSignedPrice( | ||
dharma, | ||
priceProvider, | ||
principalTokenAddress, | ||
10, | ||
Math.round(Date.now() / 1000), | ||
); | ||
const collateralPrice = await generateSignedPrice( | ||
dharma, | ||
priceProvider, | ||
collateralTokenAddress, | ||
10, | ||
Math.round(Date.now() / 1000), | ||
); | ||
|
||
loanOffer.setPrincipalPrice(principalPrice); | ||
loanOffer.setCollateralPrice(collateralPrice); | ||
} | ||
|
||
beforeEach(async () => { | ||
loanOffer = await MaxLTVLoanOffer.create(dharma, params); | ||
}); | ||
|
||
test("signs the offer as the debtor if all prerequisites are met", async () => { | ||
const isSignedByDebtorBefore = loanOffer.isSignedByDebtor(); | ||
expect(isSignedByDebtorBefore).toBe(false); | ||
|
||
await loanOffer.signAsCreditor(creditor); | ||
|
||
await setPrices(); | ||
|
||
loanOffer.setCollateralAmount(160); | ||
|
||
await loanOffer.signAsDebtor(debtor); | ||
|
||
const isSignedByDebtorAfter = loanOffer.isSignedByDebtor(); | ||
expect(isSignedByDebtorAfter).toBe(true); | ||
}); | ||
|
||
describe("should throw", () => { | ||
test("when the debtor has already signed", async () => { | ||
const isSignedByDebtorBefore = loanOffer.isSignedByDebtor(); | ||
expect(isSignedByDebtorBefore).toBe(false); | ||
|
||
await loanOffer.signAsCreditor(creditor); | ||
|
||
await setPrices(); | ||
|
||
loanOffer.setCollateralAmount(160); | ||
|
||
await loanOffer.signAsDebtor(debtor); | ||
|
||
// second attempt to sign as debtor | ||
await expect(loanOffer.signAsDebtor(debtor)).rejects.toThrow( | ||
MAX_LTV_LOAN_OFFER_ERRORS.ALREADY_SIGNED_BY_DEBTOR(), | ||
); | ||
}); | ||
|
||
test("when prices are not set", async () => { | ||
const isSignedByDebtorBefore = loanOffer.isSignedByDebtor(); | ||
expect(isSignedByDebtorBefore).toBe(false); | ||
|
||
await loanOffer.signAsCreditor(creditor); | ||
|
||
loanOffer.setCollateralAmount(160); | ||
|
||
await expect(loanOffer.signAsDebtor(debtor)).rejects.toThrow( | ||
MAX_LTV_LOAN_OFFER_ERRORS.PRICES_NOT_SET(), | ||
); | ||
}); | ||
|
||
test("when the collateral amount is not set", async () => { | ||
const isSignedByDebtorBefore = loanOffer.isSignedByDebtor(); | ||
expect(isSignedByDebtorBefore).toBe(false); | ||
|
||
await loanOffer.signAsCreditor(creditor); | ||
|
||
await setPrices(); | ||
|
||
await expect(loanOffer.signAsDebtor(debtor)).rejects.toThrow( | ||
MAX_LTV_LOAN_OFFER_ERRORS.COLLATERAL_AMOUNT_NOT_SET(), | ||
); | ||
}); | ||
|
||
test("when the collateral amount is insufficient", async () => { | ||
const isSignedByDebtorBefore = loanOffer.isSignedByDebtor(); | ||
expect(isSignedByDebtorBefore).toBe(false); | ||
|
||
await loanOffer.signAsCreditor(creditor); | ||
|
||
const collateralAmount = 10; | ||
|
||
loanOffer.setCollateralAmount(collateralAmount); | ||
|
||
await setPrices(); | ||
|
||
await expect(loanOffer.signAsDebtor(debtor)).rejects.toThrow( | ||
MAX_LTV_LOAN_OFFER_ERRORS.INSUFFICIENT_COLLATERAL_AMOUNT( | ||
collateralAmount, | ||
params.collateralToken, | ||
), | ||
); | ||
}); | ||
}); | ||
}); | ||
} |
16 changes: 16 additions & 0 deletions
16
__test__/integration/max_ltv_loan_offer/scenarios/valid_max_ltv_loan_order_params.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { MaxLTVParams } from "../../../../src/types/loan_offer/max_ltv"; | ||
|
||
import { ACCOUNTS } from "../../../accounts"; | ||
|
||
export const VALID_MAX_LTV_LOAN_ORDER_PARAMS: MaxLTVParams = { | ||
collateralToken: "MKR", | ||
expiresInDuration: 5, | ||
expiresInUnit: "days", | ||
interestRate: 12.3, | ||
maxLTV: 50, | ||
priceProvider: ACCOUNTS[0].address, | ||
principalAmount: 10, | ||
principalToken: "REP", | ||
termDuration: 6, | ||
termUnit: "months", | ||
}; |
30 changes: 30 additions & 0 deletions
30
__test__/integration/max_ltv_loan_offer/utils/generate_signed_price.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { Dharma } from "../../../../src"; | ||
|
||
import { BigNumber } from "../../../../utils/bignumber"; | ||
|
||
import { SignedPrice } from "../../../../src/types/loan_offer/signed_price"; | ||
|
||
import { SignatureUtils } from "../../../../utils/signature_utils"; | ||
|
||
import { Web3Utils } from "../../../../utils/web3_utils"; | ||
|
||
export async function generateSignedPrice( | ||
dharma: Dharma, | ||
priceProvider: string, | ||
tokenAddress: string, | ||
tokenPriceAsNumber: number, | ||
timestampAsNumber: number, | ||
): Promise<SignedPrice> { | ||
const tokenPrice = new BigNumber(tokenPriceAsNumber); | ||
const timestamp = new BigNumber(timestampAsNumber); | ||
|
||
const priceHash = Web3Utils.soliditySHA3(tokenAddress, tokenPrice, timestamp); | ||
|
||
const operatorSignature = await dharma.sign.signPayloadWithAddress( | ||
priceHash, | ||
priceProvider, | ||
false, | ||
); | ||
|
||
return { tokenAddress, tokenPrice, timestamp, operatorSignature }; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
block is empty