From 1623eb21037a95d8ae5f5fef9f9b4d345bb4fbfc Mon Sep 17 00:00:00 2001 From: Graeme Date: Mon, 9 Jul 2018 17:14:36 -0700 Subject: [PATCH 1/5] feat: add structure and filler content for main concepts --- src/components/Main/Main.tsx | 4 + .../Main/MainConcepts/MainConcepts.tsx | 171 ++++++++++++++++++ src/components/Navigation/Navigation.tsx | 56 +----- .../Navigation/Sections/BasicContent.tsx | 41 +++++ .../Sections/InstallationContent.tsx | 25 +++ .../Sections/MainConceptsContent.tsx | 33 ++++ 6 files changed, 280 insertions(+), 50 deletions(-) create mode 100644 src/components/Main/MainConcepts/MainConcepts.tsx create mode 100644 src/components/Navigation/Sections/BasicContent.tsx create mode 100644 src/components/Navigation/Sections/InstallationContent.tsx create mode 100644 src/components/Navigation/Sections/MainConceptsContent.tsx diff --git a/src/components/Main/Main.tsx b/src/components/Main/Main.tsx index 40b7ad6..5cc73d8 100644 --- a/src/components/Main/Main.tsx +++ b/src/components/Main/Main.tsx @@ -15,6 +15,7 @@ import Contributing from "./Contributing/Contributing"; import DebtOrderAPI from "./DebtOrderAPI/DebtOrderAPI"; import Interface from "./Interface/Interface"; import Installation from "./Introduction/Installation"; +import MainConcepts from "./MainConcepts/MainConcepts"; import Upgrading from "./Upgrading/Upgrading"; interface Props { @@ -33,6 +34,9 @@ export default class Main extends React.Component { + + + diff --git a/src/components/Main/MainConcepts/MainConcepts.tsx b/src/components/Main/MainConcepts/MainConcepts.tsx new file mode 100644 index 0000000..b921786 --- /dev/null +++ b/src/components/Main/MainConcepts/MainConcepts.tsx @@ -0,0 +1,171 @@ +// External libraries +import * as React from "react"; + +// Semantic-UI components +import { Container, Header as SemanticHeader } from "semantic-ui-react"; + +// Components +import ContentAnchor from "../ContentAnchor"; + +/** + * A component that renders main concepts to the documentation. + */ +export default class MainConcepts extends React.Component<{}, {}> { + public render() { + return ( + + + Main Concepts + + +
+ + Debt Order + +

Debt orders are data packets listed by relayers that are the fundamental + primitive of Dharma protocol -- submitting a valid debt order to the Debt + Kernel triggers the issuance of a debt token and its swap with the requested + principal amount. Dharma protocol is agnostic to the means by which + creditors, debtors, underwriters, and relayers communicate and transfer debt + order packets between one another -- A debt order can have up to 3 ECDSA + signatures attached to it -- a debtor's signature, a creditor's signature, + and an underwriter's signature.

+
+ +
+ + Terms Contract + +

We require that any Debt issued via Dharma protocol commit to a smart + contract, referred to as a Terms Contract. The purpose of the Terms Contract + is to provide an immutable and programmatically queryable source-of-truth + revealing the repayment status of the debt. This allows us to empirically + and unambiguously both define the terms repayment scheme in the Debt + Issuance process and evaluate the debt's repayment status during the debt's + lifecycle both on and off-chain.

+
+ +
+ + Debt Token + +

A Dharma Debt Token is a non-fungible token that a creditor receives when + filling a loan. Future repayments on the loan go to the owner of the Debt + Token.

+
+ +
+ + Relayer + +

Relayers in Dharma protocol perform an analogous function to relayers in the + 0x Protocol -- namely, relayers aggregate signed debt order messages and, + for an agreed upon fee, host the messages in a centralized order book and + provide retail investors with the ability to invest in the requested debt + orders by filling the signed debt orders. Note that, similarly to the 0x + relaying mechanism, Dharma Protocol relayers need not hold any agent's + tokens -- they simply provide a mechanism for creditors to browse through + aggregated signed debt order messages, which creditors can use to + trustlessly issue themselves debt tokens in exchange for the requested + principal via client-side contract interactions (this mechanism is specified + later in this paper). The primary differences between relayers in Dharma + protocol and 0x are:

+ +
    +
  1. Dharma protocol relayers are not hosting a secondary market order book, + but rather, an order book containing requests for debts that have yet to + be issued +
  2. +
  3. Dharma protocol relayers provide creditors with signed debt-specific + metadata associated with the debt order messages and their accompanying + underwriter so that they can make informed investment decisions about + the risk profile of a given debt order. +
  4. +
  5. Dharma protocol relayers do not freely allow any anonymous party to + publish signed debt orders on to their order book, and use their + discretion to only accept signed debt orders from known, trusted + underwriters. +
  6. +
+ +
+

Example: Bob wants to build a retail loan investor portal through which + users can invest in a variety of debt assets -- a Kayak for peer-to-peer + loans, if you will. Bob becomes a Dharma protocol relayer by setting up + an online order book, building a retail investment platform, and + allowing investors to browse through debt requests and examine + associated data pertaining to the debtors' credit worthiness and the + identity of the backing underwriters. Since Bob has seen that the + empirical historical performance of Alice's attested assets has been in + line with her predictions and knows that Alice's company is a publicly + trusted and regulated entity, Bob allows Alice to broadcast signed debt + orders onto his order book. When a debt order is filled on his platform, + Bob is paid out a fee stipulated in the signed debt order.

+
+
+ +
+ + Underwriter + +

In traditional debt markets, underwriters are entities that collect fees for + administering the public issuance of debt and pricing borrower default risk + into the asset. In Dharma protocol, this definition is expanded and + formalized. An underwriter is a trusted entity that + collects market-determined fees for performing the following functions: +

+ +
    +
  • Originating a debt order from a borrower
  • +
  • Determining and negotiating the terms of the debt (i.e. term length, + interest, amortization) with the potential debtor +
  • +
  • Cryptographically committing to the likelihood they ascribe to that debt + relationship ending in default (process described in detail under Specification) +
  • +
  • Administering the debt order's funding by forwarding it to any number of + relayers. +
  • +
  • Servicing the debt -- i.e. doing everything in the underwriter's + reasonable power to ensure timely repayment according to the agreed upon + terms +
  • +
  • In the case of defaults or delinquencies, collecting on collateral (if + debt is secured) or the individual's assets via legal mechanisms and + passing collected proceeds to investors +
  • +
+ +

This is not particularly out of band with what most online lenders do in + their day-to-day underwriting and servicing operations. We foresee Dharma + protocol facilitating an alternative, cheaper route for aspiring online + lending platforms to bootstrap their operations and earn similar margins as + they would in the status quo by becoming an underwriter -- all-the-while + never holding balance sheet risk and avoiding the upfront time and capital + costs associated with raising the requisite debt vehicles from traditional + investors.

+ +
+

Example: Alice has a novel thesis on how to originate, underwrite, and + service loans to aspiring ZCash miners who need significant upfront + capital to buy GPUs on bulk. In lieu of knocking on the doors of + traditional fixed-income investors, Alice decides to become an + underwriter in Dharma protocol. She obtains the necessary lending + licenses, sets up a website advertising lending services for miners, and + drums up hype in the ZCash community for her credit product. When + borrowers come to her site, their creditworthiness is automatically + scored by Alice's proprietary technology and they are presented with the + terms of the loan, as determined by Alice. Upon acceptance of the terms, + Alice cryptographically attests to the borrower's likelihood of default, + forwards the signed debt order to a relayer, and, upon the loan's + funding, collects her desired fee. The entire flow of funds is + transparently auditable on-chain, and Alice's competence in servicing + and collecting on the debt can be empirically determined ex post + facto.

+
+
+
+ ); + } +} diff --git a/src/components/Navigation/Navigation.tsx b/src/components/Navigation/Navigation.tsx index 4c8cc0b..effabb5 100644 --- a/src/components/Navigation/Navigation.tsx +++ b/src/components/Navigation/Navigation.tsx @@ -6,6 +6,9 @@ import { Accordion, Menu, Sidebar } from "semantic-ui-react"; import "./Navigation.css"; import Classes from "./Classes"; +import BasicContent from "./Sections/BasicContent"; +import InstallationContent from "./Sections/InstallationContent"; +import MainConceptsContent from "./Sections/MainConceptsContent"; interface Props { documentation: Documentation; @@ -56,54 +59,6 @@ export default class Navigation extends React.Component { ), }); - const InstallationContent = ( - - ); - - const BasicContent = ( - - ); - const APIReferenceContent = (
@@ -111,8 +66,9 @@ export default class Navigation extends React.Component { ); const rootPanels = [ - { title: "Installation", content: { content: InstallationContent, key: "content-1" } }, - { title: "Introduction", content: { content: BasicContent, key: "content-2" } }, + { title: "Installation", content: { content: , key: "content-1" } }, + { title: "Main Concepts", content: { content: , key: "content-1" } }, + { title: "Introduction", content: { content: , key: "content-2" } }, { title: "API Reference", content: { content: APIReferenceContent, key: "content-3" } }, ]; diff --git a/src/components/Navigation/Sections/BasicContent.tsx b/src/components/Navigation/Sections/BasicContent.tsx new file mode 100644 index 0000000..ea2ccd8 --- /dev/null +++ b/src/components/Navigation/Sections/BasicContent.tsx @@ -0,0 +1,41 @@ +// External libraries +import * as React from "react"; + +// Semantic-UI components +import { Menu } from "semantic-ui-react"; + +export default class BasicContent extends React.Component<{}, {}> { + public render() { + return ( + + ); + } +} diff --git a/src/components/Navigation/Sections/InstallationContent.tsx b/src/components/Navigation/Sections/InstallationContent.tsx new file mode 100644 index 0000000..de1379c --- /dev/null +++ b/src/components/Navigation/Sections/InstallationContent.tsx @@ -0,0 +1,25 @@ +// External libraries +import * as React from "react"; + +// Semantic-UI components +import { Menu } from "semantic-ui-react"; + +export default class InstallationContent extends React.Component<{}, {}> { + public render() { + return ( + + ); + } +} diff --git a/src/components/Navigation/Sections/MainConceptsContent.tsx b/src/components/Navigation/Sections/MainConceptsContent.tsx new file mode 100644 index 0000000..e0be9de --- /dev/null +++ b/src/components/Navigation/Sections/MainConceptsContent.tsx @@ -0,0 +1,33 @@ +// External libraries +import * as React from "react"; + +// Semantic-UI components +import { Menu } from "semantic-ui-react"; + +export default class MainConceptsContent extends React.Component<{}, {}> { + public render() { + return ( +
+ + Debt Order + + + + Terms Contract + + + + Debt Token + + + + Relayer + + + + Underwriter + +
+ ); + } +} From 439c2058e34d84e8950ee3ba8e654cc0cb19e577 Mon Sep 17 00:00:00 2001 From: Graeme Date: Mon, 9 Jul 2018 17:41:19 -0700 Subject: [PATCH 2/5] feat: add more content for new sections --- .../Main/Architecture/Architecture.tsx | 50 +++++++++++++++++++ src/components/Main/Main.tsx | 4 ++ src/components/Navigation/Navigation.tsx | 10 ++-- .../Sections/ArchitectureContent.tsx | 29 +++++++++++ .../Navigation/Sections/FurtherReading.tsx | 17 +++++++ 5 files changed, 107 insertions(+), 3 deletions(-) create mode 100644 src/components/Main/Architecture/Architecture.tsx create mode 100644 src/components/Navigation/Sections/ArchitectureContent.tsx create mode 100644 src/components/Navigation/Sections/FurtherReading.tsx diff --git a/src/components/Main/Architecture/Architecture.tsx b/src/components/Main/Architecture/Architecture.tsx new file mode 100644 index 0000000..e99af64 --- /dev/null +++ b/src/components/Main/Architecture/Architecture.tsx @@ -0,0 +1,50 @@ +// External libraries +import * as React from "react"; + +// Semantic-UI components +import { Container, Header as SemanticHeader } from "semantic-ui-react"; + +// Components +import ContentAnchor from "../ContentAnchor"; + +/** + * A component that renders an overview of architecture to the documentation. + */ +export default class Architecture extends React.Component<{}, {}> { + public render() { + return ( + + + Architecture + + +

Introduction and diagram

+ +
+ + Introduction + +

Introduction to overview of architecture.

+
+ +
+ + DebtKernel.sol + +
+ +
+ + DebtRegistry.sol + +
+ +
+ + TokenTransferProxy.sol + +
+
+ ); + } +} diff --git a/src/components/Main/Main.tsx b/src/components/Main/Main.tsx index 5cc73d8..e5e355d 100644 --- a/src/components/Main/Main.tsx +++ b/src/components/Main/Main.tsx @@ -11,6 +11,7 @@ import Section from "./Section/Section"; // Component-specific style import "./Main.css"; +import Architecture from "./Architecture/Architecture"; import Contributing from "./Contributing/Contributing"; import DebtOrderAPI from "./DebtOrderAPI/DebtOrderAPI"; import Interface from "./Interface/Interface"; @@ -40,6 +41,9 @@ export default class Main extends React.Component { + + + { // For each section, render a Section component with the relevant data. _.map(documentation.sections, (section) => { diff --git a/src/components/Navigation/Navigation.tsx b/src/components/Navigation/Navigation.tsx index effabb5..09d6dc0 100644 --- a/src/components/Navigation/Navigation.tsx +++ b/src/components/Navigation/Navigation.tsx @@ -6,7 +6,9 @@ import { Accordion, Menu, Sidebar } from "semantic-ui-react"; import "./Navigation.css"; import Classes from "./Classes"; +import ArchitectureContent from "./Sections/ArchitectureContent"; import BasicContent from "./Sections/BasicContent"; +import FurtherReading from "./Sections/FurtherReading"; import InstallationContent from "./Sections/InstallationContent"; import MainConceptsContent from "./Sections/MainConceptsContent"; @@ -67,9 +69,11 @@ export default class Navigation extends React.Component { const rootPanels = [ { title: "Installation", content: { content: , key: "content-1" } }, - { title: "Main Concepts", content: { content: , key: "content-1" } }, - { title: "Introduction", content: { content: , key: "content-2" } }, - { title: "API Reference", content: { content: APIReferenceContent, key: "content-3" } }, + { title: "Main Concepts", content: { content: , key: "content-2" } }, + { title: "Using DharmaJS", content: { content: , key: "content-3" } }, + { title: "Architecture Overview", content: { content: , key: "content-4" } }, + { title: "API Reference", content: { content: APIReferenceContent, key: "content-5" } }, + { title: "Further Reading", content: { content: , key: "content-6" } }, ]; return ( diff --git a/src/components/Navigation/Sections/ArchitectureContent.tsx b/src/components/Navigation/Sections/ArchitectureContent.tsx new file mode 100644 index 0000000..cf4cacd --- /dev/null +++ b/src/components/Navigation/Sections/ArchitectureContent.tsx @@ -0,0 +1,29 @@ +// External libraries +import * as React from "react"; + +// Semantic-UI components +import { Menu } from "semantic-ui-react"; + +export default class ArchitectureContent extends React.Component<{}, {}> { + public render() { + return ( + + ); + } +} diff --git a/src/components/Navigation/Sections/FurtherReading.tsx b/src/components/Navigation/Sections/FurtherReading.tsx new file mode 100644 index 0000000..6bb7809 --- /dev/null +++ b/src/components/Navigation/Sections/FurtherReading.tsx @@ -0,0 +1,17 @@ +// External libraries +import * as React from "react"; + +// Semantic-UI components +import { Menu } from "semantic-ui-react"; + +export default class FurtherReading extends React.Component<{}, {}> { + public render() { + return ( +
+ + Whitepaper + +
+ ); + } +} From 8d9e3c41614a9d744bbeb2299d9efbde5b81ef7d Mon Sep 17 00:00:00 2001 From: Graeme Date: Mon, 9 Jul 2018 17:57:38 -0700 Subject: [PATCH 3/5] feat: add contract addresses --- .../DeployedAddresses/DeployedAddresses.tsx | 132 ++++++++++++++++++ src/components/Main/Main.tsx | 4 + src/components/Navigation/Navigation.tsx | 6 +- .../Navigation/Sections/DeployedAddresses.tsx | 62 ++++++++ 4 files changed, 202 insertions(+), 2 deletions(-) create mode 100644 src/components/Main/DeployedAddresses/DeployedAddresses.tsx create mode 100644 src/components/Navigation/Sections/DeployedAddresses.tsx diff --git a/src/components/Main/DeployedAddresses/DeployedAddresses.tsx b/src/components/Main/DeployedAddresses/DeployedAddresses.tsx new file mode 100644 index 0000000..97b190f --- /dev/null +++ b/src/components/Main/DeployedAddresses/DeployedAddresses.tsx @@ -0,0 +1,132 @@ +// External libraries +import * as React from "react"; + +// Semantic-UI components +import { Container, Header as SemanticHeader } from "semantic-ui-react"; + +// Components +import ContentAnchor from "../ContentAnchor"; + +/** + * A component that renders an overview of architecture to the documentation. + */ +export default class DeployedAddresses extends React.Component<{}, {}> { + public render() { + return ( + + + Contract Addresses + + +
+ + DebtKernel + +

Mainnet:

0x8ef1351941d0cd8da09d5a4c74f2d64503031a18

+ +

Kovan:

0x755e131019e5ab3e213dc269a4020e3e82e06e20

+
+ +
+ + DebtToken + +

Mainnet:

0xf7b3fc555c458c46d288ffd049ddbfb09f706df7

+ +

Kovan:

0x12c8615fd55bf6e1f5a298cebdc72e50f838df74

+
+ +
+ + DebtRegistry + +

Mainnet:

0x4e0f2b97307ad60b741f993c052733acc1ea5811

+ +

Kovan:

0x9662d6cae0e6914a388cb96c1c161cc4d12c3d7a

+
+ +
+ + TokenTransferProxy + +

Mainnet:

0x2f40766e91aaee4794d3389ac8dc3a4b8fd7ab3e

+ +

Kovan:

0x668beab2e4dfec1d8c0a70fb5e52987cb22c2f1a

+
+ +
+ + DharmaMultiSigWallet + +

Mainnet:

0x9445d5ddc2d8a3663ce8cc9fe74009f99b343cfc

+ +

Kovan:

0x5e6d80063af17bf22b6828a7a61693ec37881563

+
+ +
+ + RepaymentRouter + +

Mainnet:

0xc1df9b92645cc3b6733992c692a39c34a86fae5f

+ +

Kovan:

0x0688659d5e36896da7e5d44ebe3e10aa9d2c9968

+
+ +
+ + TokenRegistry + +

Mainnet:

0xd79396ab3bfaaa0d9f6d11f95bb641601d93c0a9

+ +

Kovan:

0x6949948d93f3dbe50ec2fe54815fa33bfa284d35

+
+ +
+ + SimpleInterestTermsContract + +

Mainnet:

0xb78a7d1c1d03cf9155cc522097cbc679e15cf9a3

+ +

Kovan:

0x4cad7ad79464628c07227928c851d3bc5ef3da0c

+
+ +
+ + CollateralizedSimpleInterestTermsContract + +

Mainnet:

0x5de2538838b4eb7fa2dbdea09d642b88546e5f20

+ +

Kovan:

0x13763cf3eb3b6813fa800d4935725a0504c8eb8f

+
+ +
+ + Collateralizer + +

Mainnet:

0xecc718386176d714dc9e4e35e177396b291499ee

+ +

Kovan:

0x4b86bbe375577262cb0b3b7893e3de0d11751dd6

+
+ +
+ + PermissionsLib + +

Mainnet:

0xba0d793fb316d7a457b758e75a57e22ee14bc188

+ +

Kovan:

0x0e7e2aace2ed2565777b420fd181b556971a8cb1

+
+ +
+ + ContractRegistry + +

Mainnet:

0x10512440113cb6cb613be403135876d2e0a42c0b

+ +

Kovan:

0x506acb19a451cc6e2a5c76e65f6b65840406e5f9

+
+
+ ); + } +} diff --git a/src/components/Main/Main.tsx b/src/components/Main/Main.tsx index e5e355d..b72b047 100644 --- a/src/components/Main/Main.tsx +++ b/src/components/Main/Main.tsx @@ -14,6 +14,7 @@ import "./Main.css"; import Architecture from "./Architecture/Architecture"; import Contributing from "./Contributing/Contributing"; import DebtOrderAPI from "./DebtOrderAPI/DebtOrderAPI"; +import DeployedAddresses from "./DeployedAddresses/DeployedAddresses"; import Interface from "./Interface/Interface"; import Installation from "./Introduction/Installation"; import MainConcepts from "./MainConcepts/MainConcepts"; @@ -44,6 +45,9 @@ export default class Main extends React.Component { + + + { // For each section, render a Section component with the relevant data. _.map(documentation.sections, (section) => { diff --git a/src/components/Navigation/Navigation.tsx b/src/components/Navigation/Navigation.tsx index 09d6dc0..282315d 100644 --- a/src/components/Navigation/Navigation.tsx +++ b/src/components/Navigation/Navigation.tsx @@ -8,6 +8,7 @@ import "./Navigation.css"; import Classes from "./Classes"; import ArchitectureContent from "./Sections/ArchitectureContent"; import BasicContent from "./Sections/BasicContent"; +import DeployedAddresses from "./Sections/DeployedAddresses"; import FurtherReading from "./Sections/FurtherReading"; import InstallationContent from "./Sections/InstallationContent"; import MainConceptsContent from "./Sections/MainConceptsContent"; @@ -72,8 +73,9 @@ export default class Navigation extends React.Component { { title: "Main Concepts", content: { content: , key: "content-2" } }, { title: "Using DharmaJS", content: { content: , key: "content-3" } }, { title: "Architecture Overview", content: { content: , key: "content-4" } }, - { title: "API Reference", content: { content: APIReferenceContent, key: "content-5" } }, - { title: "Further Reading", content: { content: , key: "content-6" } }, + { title: "Contract Addresses", content: { content: , key: "content-5" } }, + { title: "API Reference", content: { content: APIReferenceContent, key: "content-6" } }, + { title: "Further Reading", content: { content: , key: "content-7" } }, ]; return ( diff --git a/src/components/Navigation/Sections/DeployedAddresses.tsx b/src/components/Navigation/Sections/DeployedAddresses.tsx new file mode 100644 index 0000000..d922c55 --- /dev/null +++ b/src/components/Navigation/Sections/DeployedAddresses.tsx @@ -0,0 +1,62 @@ +// External libraries +import * as React from "react"; + +// Semantic-UI components +import { Menu } from "semantic-ui-react"; + +export default class DeployedAddresses extends React.Component<{}, {}> { + public render() { + return ( + + ); + } +} From 8df6b0ff3f222ce492a849ba1f15f24ad54fe7a7 Mon Sep 17 00:00:00 2001 From: Graeme Date: Tue, 10 Jul 2018 11:41:04 -0700 Subject: [PATCH 4/5] feat: add more content --- .../Main/Architecture/Architecture.tsx | 277 +++++++++++++++++- src/components/Main/Main.css | 8 + src/components/Main/Main.tsx | 12 +- .../Main/MainConcepts/MainConcepts.tsx | 3 +- .../Sections/ArchitectureContent.tsx | 4 + 5 files changed, 292 insertions(+), 12 deletions(-) diff --git a/src/components/Main/Architecture/Architecture.tsx b/src/components/Main/Architecture/Architecture.tsx index e99af64..d5bb77d 100644 --- a/src/components/Main/Architecture/Architecture.tsx +++ b/src/components/Main/Architecture/Architecture.tsx @@ -18,25 +18,48 @@ export default class Architecture extends React.Component<{}, {}> { Architecture -

Introduction and diagram

-
Introduction - -

Introduction to overview of architecture.

DebtKernel.sol +

The debt kernel is a smart contract that contains business logic + associated with filling a debt order. This includes determining whether a + debt order is valid and consensual, minting a non-fungible + debt token and transferring it to the creditor, and transferring fees to the + appropriate relayer and underwriter.

+ +

The debt kernel also handles logic for cancelling an signed debt + order, so that a debtor can prevent a counterparty from filling it in the + future. Similarly, underwriters and relayers can use the debt kernel to + cancel an issuance that they have signed from being used in a debt order in + the future.

DebtRegistry.sol +

The debt registry contains detailed information about each debt agreement, + including:

+
    +
  • The beneficiary of repayments
  • +
  • The address of the associated terms contract and the relevant + parameters for that contract +
  • +
  • The address of the underwriter
  • +
  • The underwriter's risk rating
  • +
  • The address of debt kernel contract used (referred to as its version) +
  • +
  • The block timestamp at issuance
  • +
+ +

The debt registry also contains a mapping of each debtor to the list of debt + agreements.

@@ -44,6 +67,252 @@ export default class Architecture extends React.Component<{}, {}> { TokenTransferProxy.sol
+ +
+ + Upgrade Procedure + +

The Ethereum community is rapidly iterating on multiple layers of its + technology + stack, and hence protocols need to accommodate upgrades. Once a contract has + been deployed to the Ethereum blockchain, however, its internal logic cannot + be + changed, and so any changes to protocol logic requires completely new + contracts + to be deployed. Each time a new contract is deployed, other contracts and + accounts (including the protocol’s users) that make transfers through that + contract need to grant transfer approval - I.E. "opt-in" to using + that + contract.

+

To avoid disruptions to user experience during upgrades, Dharma Protocol uses + a "proxy" mechanism for token transfers. Specifically, a user + authorizes a simple proxy contract to make transfers with specified amounts + from + their account, and core Dharma Protocol contracts are authorized to invoke + those + transfers. When a core contract needs to be replaced, the old contract’s + proxy + permissions will be revoked, and a newly deployed contract will be + authorized to + make transfers through the proxy. However, this change will only go into + effect + if at least three of the five signatories in the Dharma Protocol multi-signature wallet agree to the + change, and a “timelock” period of seven days has passed since the change + was + submitted.

+

The timelock is imposed to allow the Dharma community to view, contest, or + opt-out of any such changes if they do not agree that they are appropriate. + At + no time can the Dharma Protocol team make any changes to the logic of the + protocol within the timelock period, except to{" "} + pause + the protocol in the case of an emergency. Proposed changes are + broadcast + as events to the public blockchain at the time of proposal, before the + timelock + begins.

+ + +

Disaster Recovery

+

The Dharma Protocol contracts have tested extensively, and independently + audited + and reviewed by three external auditors (Zeppelin, ZK Labs, and Trail of + Bits) + Even so, it is possible that vulnerabilities may surface in the protocol. + The + team has implemented a way to pause the procotcol in the case of + emergencies, to + prevent a situation where a hacker is able to exploit a known vulnerability. + The + signatories of Dharma’s multi-signature wallet, collectively are able to + pause + any the following Dharma Protocol contracts:

+
    +
  • DebtKernel

    +
  • +
  • DebtRegistry

    +
  • +
  • Collateralizer

    +
  • +
  • RepaymentRouter

    +
  • +
+

The pause operation is the only function that the Dharma Protocol + can + invoke + immediately - all other functions require a timelock of seven days to elapse + before taking effect. Hence, once a fix has been made for the vulnerability, + the + protocol can only be unpause again after seven days have passed. + This + allows + Dharma community members to view and contest the fix, and, if necessary, + revoke + transfer allowances.

+ + +

The Effect of + Pausing Contracts on Users

+

The pause operation prevents the core functions in a contract from + further + execution. For example, if the Collateralizer contract is paused, users will + no + longer be able to return and seize collateral assets, or collateralize more + assets using the contract. In the case of the DebtKernel contract, a pause + would + mean that users are no longer allowed to fill debt orders, cancel debt + orders, + or cancel an issuance. The pause function is therefore a way to protect + assets + that might otherwise be at risk in the case of a vulnerability.

+

It is important to note that in the case of open orders, an inability to make + repayments due to a paused RepaymentRouter may result in delinquency.

+

Here is a list of functions that are will be paused, in the case of an + emergency, + for each contract:

+
    +
  • + DebtKernel +
      +
    • fillDebtOrder
    • +
    • cancelDebtOrder
    • +
    • cancelIssuance
    • +
    +
  • +
  • + DebtRegistry +
      +
    • insert
    • +
    • modifyBeneficiary
    • +
    +
  • +
  • + Collateralizer +
      +
    • seizeCollateral
    • +
    • collateralize
    • +
    • returnCollateral
    • +
    +
  • +
  • + RepaymentRouter +
      +
    • repay
    • +
    +
  • +
+ + +

Multisig Management

+

We have deployed a 3-of-5 multi-signature wallet to be the owner of all + deployed + Dharma Protocol contracts. This means that there are five signatories who + can + submit or confirm a transaction as the owner of a Dharma Protocol contract, + and + that any such transaction will only be executed if at least 3 of the + signatories + confirm the transaction. All of the multi-signature wallet transactions, + with + the exception of the pause operation, are subject to a seven-day + timelock + following the majority confirmation.

+ +

Contract Owner Capabilities

+

The owner of the Dharma Protocol contracts, the multi-signature wallet, + cannot + directly control any assets or debt orders on the protocol. Its main + capabilities relate to pausing contracts in the case of an emergency, and + authorizing which contracts may execute functions on other contracts within + the + protocol. For example, the signatories may collectively vote to change which + contracts will be allowed to act as a transfer agent - to transfer funds + using + the transfer proxy. Currently this set of contracts include the + /RepaymentRouter/ (to transfer funds specified as loan repayments), the + /DebtKernel/ (to transfer principal from the creditor to the debtor, and + fees to + the underwriter and relayer), and the /Collateralizer/ (to transfer + collateral + to the Collateralizer contract.) If one of these contracts were to be + upgraded, + a new contract would be deployed and the signatories would vote on granting + that + contract the authorization to act as a transfer agent. If the majority of + the + signatories confirm that authorization, the update will occur following a + seven-day timelock.

+

The following functions are executable by the contract owner:

+
    +
  • + DebtKernel +
      +
    • setDebtToken
    • +
    +
  • +
  • + DebtToken +
      +
    • addAuthorizedMintAgent
    • +
    • revokeMintAgentAuthorization
    • +
    • addAuthorizedTokenURIAgent
    • +
    • revokeTokenURIAuthorization
    • +
    +
  • +
  • + Collateralizer +
      +
    • addAuthorizedCollateralizeAgent
    • +
    • revokeCollateralizeAuthorization
    • +
    +
  • +
  • + DebtRegistry +
      +
    • addAuthorizedInsertAgent
    • +
    • revokeInsertAgentAuthorization
    • +
    • addAuthorizedEditAgent
    • +
    • revokeEditAgentAuthorization
    • +
    +
  • +
  • + TokenRegistry +
      +
    • setTokenAttributes
    • +
    +
  • +
  • + TokenTransferProxy +
      +
    • addAuthorizedTransferAgent
    • +
    • revokeTransferAgentAuthorization
    • +
    +
  • +
+ +

Security Considerations

+

Static Token Address Assumptions

+

Tokens on the Ethereum blockchain are upgradeable, in which case the address + or + symbol for that token may change. When token upgrades occur for supported + tokens, Dharma Protocol contracts that store those token attributes, such as + the + TokenRegistry, will need to be updated.

+

The TokenRegistry in Dharma Protocol provides a mapping of each supported + token’s + symbol to the address of that token. The Dharma team can update the stored + attributes for any supported token in the registry, including the token’s + address, and add new token symbols to the registry. However, like other + contract + upgrades, these changes invoke the seven-day time-lock. In the case of token updates, + it is appropriate for the applications that use Dharma Protocol (e.g. Dharma + Plex), to signal to their users that the token has changed.

+

We have audited the Dharma Protocol and found no further cases where the + assumption has been made that a token’s attributes will remain fixed over + time.

+
); } diff --git a/src/components/Main/Main.css b/src/components/Main/Main.css index ecf6a28..a720c6c 100644 --- a/src/components/Main/Main.css +++ b/src/components/Main/Main.css @@ -33,3 +33,11 @@ p { .subsection { margin-top: 40px; } + +blockquote { + margin: 0; + margin-bottom: .85em; + padding: 0 15px; + color: #858585; + border-left: 4px solid #e5e5e5; +} \ No newline at end of file diff --git a/src/components/Main/Main.tsx b/src/components/Main/Main.tsx index b72b047..1b002a7 100644 --- a/src/components/Main/Main.tsx +++ b/src/components/Main/Main.tsx @@ -12,13 +12,13 @@ import Section from "./Section/Section"; import "./Main.css"; import Architecture from "./Architecture/Architecture"; -import Contributing from "./Contributing/Contributing"; +// import Contributing from "./Contributing/Contributing"; import DebtOrderAPI from "./DebtOrderAPI/DebtOrderAPI"; import DeployedAddresses from "./DeployedAddresses/DeployedAddresses"; import Interface from "./Interface/Interface"; import Installation from "./Introduction/Installation"; import MainConcepts from "./MainConcepts/MainConcepts"; -import Upgrading from "./Upgrading/Upgrading"; +// import Upgrading from "./Upgrading/Upgrading"; interface Props { documentation: Documentation; @@ -64,11 +64,11 @@ export default class Main extends React.Component { }) } - - + {/**/} + {/**/} - - + {/**/} + {/**/} ); } diff --git a/src/components/Main/MainConcepts/MainConcepts.tsx b/src/components/Main/MainConcepts/MainConcepts.tsx index b921786..901bc87 100644 --- a/src/components/Main/MainConcepts/MainConcepts.tsx +++ b/src/components/Main/MainConcepts/MainConcepts.tsx @@ -121,8 +121,7 @@ export default class MainConcepts extends React.Component<{}, {}> { interest, amortization) with the potential debtor
  • Cryptographically committing to the likelihood they ascribe to that debt - relationship ending in default (process described in detail under Specification) + relationship ending in default
  • Administering the debt order's funding by forwarding it to any number of relayers. diff --git a/src/components/Navigation/Sections/ArchitectureContent.tsx b/src/components/Navigation/Sections/ArchitectureContent.tsx index cf4cacd..a12a85f 100644 --- a/src/components/Navigation/Sections/ArchitectureContent.tsx +++ b/src/components/Navigation/Sections/ArchitectureContent.tsx @@ -23,6 +23,10 @@ export default class ArchitectureContent extends React.Component<{}, {}> { TokenTransferProxy.sol + + + Upgrade Procedure +
  • ); } From 5310a926e8923b0242f7b474630063e82120d0fd Mon Sep 17 00:00:00 2001 From: Graeme Date: Tue, 10 Jul 2018 15:34:38 -0700 Subject: [PATCH 5/5] feat: add more content --- src/assets/images/Broadcast-Debt-Order.png | Bin 0 -> 44958 bytes .../Main/Architecture/Architecture.tsx | 53 +++++++++++++++--- 2 files changed, 46 insertions(+), 7 deletions(-) create mode 100644 src/assets/images/Broadcast-Debt-Order.png diff --git a/src/assets/images/Broadcast-Debt-Order.png b/src/assets/images/Broadcast-Debt-Order.png new file mode 100644 index 0000000000000000000000000000000000000000..49c36db3a2e975be53bbad4ab5ef5ac3a1caf8dd GIT binary patch literal 44958 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 IG$8dq0BU5fU;qFB literal 0 HcmV?d00001 diff --git a/src/components/Main/Architecture/Architecture.tsx b/src/components/Main/Architecture/Architecture.tsx index d5bb77d..bf3d6be 100644 --- a/src/components/Main/Architecture/Architecture.tsx +++ b/src/components/Main/Architecture/Architecture.tsx @@ -14,18 +14,43 @@ export default class Architecture extends React.Component<{}, {}> { public render() { return ( + - Architecture + Architecture Overview

    - - Introduction +

    Dharma Protocol defines a procedure for issuing, funding, administering, + and trading debt assets using a set of smart contracts.

    + +

    In the broadcast debt order model, a debtor will sign a debt order + specifying the parameters of a debt they want funded. An underwriter will + commit a risk rating to this order, and post it on a relayer's order book. A + creditor will fund the debt by filling the debt order. The Debt Kernel contract will issue a + tradable debt token (ERC721) to the creditor, and + store the details of the debt agreement in the Debt Registry contract. The + debt kernel will transfer funds from the creditor to the borrower, and pay + relevant fees to the underwriter and relayer for their services.

    + +

    Note: The Debt Kernel makes all transfers via a Token Transfer Proxy contract, so + that the creditor and debtor would not need to update their token + permissions in the case of a contract upgrade.

    + +

    Filling a Broadcast Debt Order

    +
    - DebtKernel.sol + + + DebtKernel.sol + +

    The debt kernel is a smart contract that contains business logic associated with filling a debt order. This includes determining whether a @@ -42,7 +67,11 @@ export default class Architecture extends React.Component<{}, {}> {

    - DebtRegistry.sol + + + DebtRegistry.sol + +

    The debt registry contains detailed information about each debt agreement, including:

    @@ -64,8 +93,17 @@ export default class Architecture extends React.Component<{}, {}> {
    - TokenTransferProxy.sol + + + TokenTransferProxy.sol + + +

    This contract exists in order to transfer tokens (including principal, fees, + repayments, and collateral), on behalf of core Dharma Protocol contracts + such as the Debt Kernel. By decoupling contracts from transfers, the + core contracts can be upgraded without requiring users to grant new transfer + approvals to the new contract's address.

    @@ -306,7 +344,8 @@ export default class Architecture extends React.Component<{}, {}> { attributes for any supported token in the registry, including the token’s address, and add new token symbols to the registry. However, like other contract - upgrades, these changes invoke the seven-day time-lock. In the case of token updates, + upgrades, these changes invoke the seven-day time-lock. In the case of token + updates, it is appropriate for the applications that use Dharma Protocol (e.g. Dharma Plex), to signal to their users that the token has changed.

    We have audited the Dharma Protocol and found no further cases where the