@startuml
digraph g {
    size="10,15"
    rankdir=BT
    node [shape=record]

    /* Nodes */

    DSAuthority [
        shape=Mrecord
        label="{
            DSAuthority
            | canCall(src, dst, methodSig)
        }"
    ]

    DSAuthEvents [
        shape=Mrecord
        label="{
            DSAuthEvents
            | LogSetAuthority(authority)
            | LogSetOwner(owner)
        }"
    ]

    DSAuth [
        label="{
           DSAuth
           |
           | DSAuthority authority
           |
           | setOwner(owner)
           | setAuthority(authority)
           | isAuthorized(src, methodSig)
           | modifier auth()
        }"
    ]

    DSRoles [
        shape=Mrecord
        label="{
            DSRoles
            |
            | getUserRoles()
            | getCapabilityRoles()
            | isUserRoot()
            | isCapabilityPublic()
            | hasUserRole()
            |
            | canCall()
            | setRootUser() auth
            | setUserRole() auth
            | setPublicCapability() auth
            | setRoleCapability() auth
        }"
    ]

    ERC20 [
        shape=Mrecord
        label="{
            ERC20
            | totalSupply()
            | balanceOf(guy)
            | allowance(src, guy)
            | approve(guy, wad)
            | transfer(dst, wad)
            | transferFrom(src, dst, wad)
        }"
    ]

    DSTokenBase [
        shape=record
        label="{
            DSTokenBase
            |
            | uint256 _supply
            | (address =\> uint256) _balances
            | (address =\> (address =\> uint256))  _approvals
            |
            | totalSupply()
            | balanceOf(guy)
            | allowance(src, guy)
            | approve(guy, wad)
            | transfer(dst, wad)
            | transferFrom(src, dst, wad)
        }"
    ]

    DSToken [
        shape=record
        label="{
            DSToken
            |
            | approve(guy, wad) stoppable
            | transferFrom(src, dst, wad) stoppable
            |
            | mint(guy, wad) auth stoppable
            | burn(guy, wad) auth stoppable
        }"
    ]

    ERC20Events [
        shape=Mrecord
        label="{
            ERC20Events
            | Approval(src, guy, wad)
            | Transfer(src, dst, wad)
        }"
    ]

    KycAmlRule [
        shape=Mrecord,
        label="{
            KycAmlRule
            | canTransfer(asset, from, to)
        }"
    ]

    NoKycAmlRule [
        label="{
            NoKycAmlRule
            | canTransfer(asset, from, to)
        }"
    ]

    KycAmlERC20 [
        shape=Mrecord
        label="{
           <kycAmlRule> KycAmlERC20(kycAmlRule)
           |
           | KycAmlRule kycAmlRule
           |
           | modifier checkTransfer(from, to, value)
        }"
    ]

    Gate [
        label="{
           <constructor> Gate(authority, kycAmlRule)
           |
           | transferFrom(src, dst, wad)
           | checkTransfer(src, dst, wad)
         }"
    ]

    /* Edges */

    DSAuth -> DSAuthEvents [style=dotted]
    DSRoles -> DSAuthority [style=dotted]
    DSRoles -> DSAuth

    DSStop -> DSNote, DSAuth
    Gate:constructor -> DSRoles [dir=back; arrowtail=diamond]

    ERC20 -> ERC20Events [style=dotted]
    DSTokenBase -> ERC20, DSMath
    DSToken -> DSTokenBase, DSStop
    KycAmlERC20  -> KycAmlRule, ERC20 [style=dotted]
    NoKycAmlRule -> KycAmlRule [style=dotted]
    Gate:constructor -> NoKycAmlRule [dir=back; arrowtail=diamond]

    Gate -> DSToken, KycAmlERC20
}
@enduml
