Skip to content
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

docs: add initial threat model diagrams for multipool autoswap and treasury #3888

Merged
merged 4 commits into from
Oct 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions docs/threat_models/gen.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/sh
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, useful! I'm going to have to crib from this for the governance diagrams.

pumljar="${PLANTUML:-$HOME/plantuml/plantuml.jar}"
page="index.md"
java -jar "$pumljar" "./**/*.puml"
echo "# Threat Model Diagrams" > "$page"
for diag in $(find . -name "*.png" | sort); do
echo "## $diag\n" >> "$page"
echo "[![$diag]($diag)]($diag)\n" >> "$page"
done
25 changes: 25 additions & 0 deletions docs/threat_models/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Threat Model Diagrams
## ./smart_contracts/multipool_autoswap/mpas_component.png

[![./smart_contracts/multipool_autoswap/mpas_component.png](./smart_contracts/multipool_autoswap/mpas_component.png)](./smart_contracts/multipool_autoswap/mpas_component.png)

## ./smart_contracts/multipool_autoswap/mpas_sequence.png

[![./smart_contracts/multipool_autoswap/mpas_sequence.png](./smart_contracts/multipool_autoswap/mpas_sequence.png)](./smart_contracts/multipool_autoswap/mpas_sequence.png)

## ./smart_contracts/multipool_autoswap/mpas_sequence_001.png

[![./smart_contracts/multipool_autoswap/mpas_sequence_001.png](./smart_contracts/multipool_autoswap/mpas_sequence_001.png)](./smart_contracts/multipool_autoswap/mpas_sequence_001.png)

## ./smart_contracts/multipool_autoswap/mpas_sequence_002.png

[![./smart_contracts/multipool_autoswap/mpas_sequence_002.png](./smart_contracts/multipool_autoswap/mpas_sequence_002.png)](./smart_contracts/multipool_autoswap/mpas_sequence_002.png)

## ./smart_contracts/multipool_autoswap/mpas_sequence_003.png

[![./smart_contracts/multipool_autoswap/mpas_sequence_003.png](./smart_contracts/multipool_autoswap/mpas_sequence_003.png)](./smart_contracts/multipool_autoswap/mpas_sequence_003.png)

## ./treasury/treasury.png

[![./treasury/treasury.png](./treasury/treasury.png)](./treasury/treasury.png)

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
@startuml
'https://plantuml.com/component-diagram
header Agoric Systems Operating Company.
footer v0.0.1
title Multiswap Auto Pool Component Diagram

skinparam componentStyle rectangle
skinparam defaultTextAlignment center

actor "Multipool Autoswap Contract creator" as cc1
actor "Random Pool Creator" as cc2
actor "Person wanting to swap" as cc3
interface "startInstance()" as si0
package "zoe" as zoe {
interface "offer()" as offer
}

package "Multipool Autoswap" {
[creatorFacet] as cf0
node contractFacet <<zcf>> as conf1 {
package "poolSeatA" as pa1 {
interface "incrementBy" as pa1i1
interface "decrementBy" as pa1i2
}

package "poolSeatB" as pa2 {
interface "incrementBy" as pa2i1
interface "decrementBy" as pa2i2
}
package "UserSeat" as use {
interface "incrementBy" as usi1
interface "decrementBy" as usi2
}

interface "reallocate" as reall

}
package "publicFacet" as pf0 {
interface "addPool()" as ap
interface "otherMethods..." as om
}

si0 -> cf0


node "Pool B" as poolb {
[Central Token] as ct2
database "Price Registry" <<Central/B>> as pr2
[Secondary Token B]
[Secondary Token B] --> ct2
interface "getPoolSeat()" as gps2
}

node "Pool A" as poola {
[Central Token] as ct1
database "Price Registry" <<Central/A>> as pr1
[Secondary Token A]
[Secondary Token A] --> ct1
interface "getPoolSeat()" as gps1
}

node "pool n" as pooln {
}

ap -d-> pooln

offer --> conf1: execute method
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this part of the diagram (offer(), validateTerms(), executeMethod) trying to convey?

Everything else appears to be either the ways a client of the APIs can interact with methods on the AMM pools or how zoe/zcf manage the balances of the pools.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In regards to Zoe, I wanted to show that it referenced the contract and in invoked the contract functionality, however I may have it backwards. What is the best way to represent offer() does stuff with the respective seats here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's a quick sketch. Zoe holds funds in escrow, and has the user seats. each user seat is paired with a ZCF seat in the corresponding ZCF vat.

A ZCF vat runs a single contract (in this case MPAS). MPAS has multiple pools, each of which knows two balances that reflect a claim on escrowed funds in Zoe.

When a seat is created for a transaction (addLiquidity or adjustBalances are the two examples here) it interacts with the conctract code, reallocations are done, and the user gets something back.

The publicFacet, creatorFacet, etc. could also be pictured within the ZCF vat, since they're facets of the contract.

Threat Model--multipool components

We can jump on a call if you want to wave my hands and point at the parts of the diagram.


gps1 -d-> pa1
gps2 -d-> pa2
conf1 --> pa1i1
conf1 --> pa1i2
conf1 --> pa2i1
conf1 --> pa2i2
conf1 --> usi1
conf1 --> usi2
conf1 --> reall
}

cc1 --> si0
cc2 --> ap
cc3 -u-> offer
offer -> offer: validate terms

offer -> use
cc3 --r-> use: reclaim funds
cc3 --> om
@enduml
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
@startuml
'https://plantuml.com/sequence-diagram
header Agoric Systems Operating Company.
footer Page %page% of %lastpage%
title Multipool Auto Swap Sequence Diagram Creation

autonumber
actor "MPAS Creator" as masc #lime
actor "Pool Adder N" as pa #yellow
actor "Pool User" as pu
database "MPAS Contract" as mpas
box "Zoe"
entity "Zoe" as zoe
entity "userSeat" as usA
end box

== MPAS Creation ==
masc -> mpas: Create instance
return ""creatorFacet""
== Pool Addition SML:BCK==
autonumber 10
pa -> mpas: ""addPool()""
Comment on lines +19 to +22
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In order to get from creating an instance to adding a pool, the creator has to publish the instance of the contract somewhere. Otherwise, even though the addPool() method is "public", no one would be able to find it. It is completely possible in this model to create an AMM, and add pools, and only tell friends about it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to enumerate or directly reference this contract somehow through reflection or other means? Or does it need to be explicitly published?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It needs to be explicitly published. We have a Board on which references to such things can be shared, but it takes an explicit action to make them visible.

It's a crucial part of the security model. We don't want to treat instances of contracts like they're ambient authority, even though we do share them widely for convenience in some circumstances.

database "Pool SML:BUCK" as pool
entity "poolSeat SML:BUCK" as psA

mpas -> pool: Create pool for SML -> BUCK
mpas --> pa: ""Issuer""
== Pool Addition MOOL:BCK==
autonumber 10
pa -> mpas: ""addPool()""
database "Pool MOOL:BUCK" as pool2
mpas -> pool2: Create pool for MOOL -> BUCK
mpas --> pa: ""Issuer""


== Duplicate Pool Addition MOOL:BCK==
autonumber 30
pa -> mpas: ""addPool()""
mpas -->x pa: pool for MOOL:BCK already exists
newpage Multipool Auto Swap Sequence Diagram Swap Request

autonumber 50
== Swap Request ==
group asking for the current price UNK:BUCK
pu -> mpas: ""getOutputPrice(UNK:BUCK)""
mpas -->x pu: ""brands were not recognized""
end
group asking for the current price MOOL:BUCK


pu -> mpas: ""getOutputPrice(MOOL:BUCK)""
mpas -> pool2: ""getPriceGivenRequiredOutput(MOOL:BUCK)""
pool2 --> mpas: ""quote""
mpas --> pu: ""quote""
end

group making a proposal
pu -> pu: create proposal for SML:BUCK as ""proposal""

end

group requesting an invitation for a SwapOut
pu -> mpas: ""makeSwapOutInvitation()""
return ""invitation""

end

group making an offer
pu -> pu: withdraw funds from purse of SML into ""payment""
pu -> zoe: ""offer(invitation, proposal, payment))""
zoe -> zoe: validate offer

zoe -> usA: create ""userSeat""
usA --> zoe: ""userSeat""
zoe -> pool: ""getPoolSeat()""
pool -> psA: create ""poolSeat""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no "Create poolSeat" call at this point in the transaction. I would actually show the poolSeat as having the same lifetime as the Pool. It's created when the pool comes into existence, and holds the pools assets.

psA --> zoe: ""poolSeat""
mpas -> psA: stage assets
mpas -> usA: stage assets
zoe -> zoe: ""reallocate(seat, poolSeat)""

usA --> pu: ""userSeat""
pu -> zoe: ""getOfferResult()""
return result of failure or success
end
group recovering funds
pu -> usA: ""getPayout("Central")"" (give)
return ""payoutCentral""
pu -> pu: deposit ""payoutCentral"" into purse
pu -> usA: ""getPayout("Secondary")"" (want)
return ""payoutSecondary""
pu -> pu: deposit ""payoutSecondary"" into purse
end

newpage Multipool Auto Swap Sequence Diagram Adding Liquidity

autonumber 100
== Adding Liquidity ==
group discover existing proportion of balances
pu -> pool: ""getPoolAllocation(SML)""
return ""poolAllocation""
end
group create invite
pu -> mpas: ""makeAddLiquidityInvitation""
return ""invitation""
end


group create proposal
pu -> pu: Create ""proposal"" to add 1 BUCK, and 1 SML\nat ratio of ""poolAllocation"" for X ""liquidity""
end
group withdraw funds
pu -> pu: withdraw funds for ""BUCK"" into ""payments"" record
pu -> pu: withdraw funds for ""SML"" into ""payments"" record
pu -> zoe: ""offer(invitation, proposal, payments)""
zoe -> zoe: validate offer

zoe -> usA: create ""userSeat""
usA --> zoe: ""userSeat""
zoe -> pool: ""getPoolSeat()""
pool -> psA: create ""poolSeat""
psA --> zoe: ""poolSeat""

zoe -> psA: ""addLiquidity""
mpas -> psA: stage assets
mpas -> usA: stage assets
zoe -> zoe: ""reallocate(seat, poolSeat)""

usA --> pu: ""userSeat""
pu -> zoe: ""getOfferResult()""
return result of failure or success
end
group recovering funds
pu -> usA: ""getPayout("Central")"" (give)
return ""payoutCentral""
pu -> pu: deposit ""payoutCentral"" into purse
pu -> usA: ""getPayout("Secondary")"" (give)
return ""payoutSecondary""
pu -> pu: deposit ""payoutSecondary"" into purse
pu -> usA: ""getPayout("Liquidity")"" (want)
return ""payoutLiquidity""
pu -> pu: deposit ""payoutLiquidity"" into purse
end


newpage Multipool Auto Swap Sequence Diagram Removing Liquidity

autonumber 200
== Removing Liquidity ==
group discover existing proportion of balances
pu -> pool: ""getPoolAllocation(SML)""
return ""poolAllocation""
end
group create invite
pu -> mpas: ""makeAddLiquidityInvitation""
return ""invitation""
end


group create proposal
pu -> pu: Create ""proposal"" to remove 1 ""liquidity"" for 1 BUCK and 1 SML\nat ratio of ""poolAllocation""
end
group withdraw funds
pu -> pu: withdraw funds for ""liquidity"" into ""payments"" record
pu -> zoe: ""offer(invitation, proposal, payments)""
zoe -> zoe: validate offer

zoe -> usA: create ""userSeat""
usA --> zoe: ""userSeat""
zoe -> pool: ""getPoolSeat()""
pool -> psA: create ""poolSeat""
psA --> zoe: ""poolSeat""

zoe -> psA: ""addLiquidity""
mpas -> psA: stage assets
mpas -> usA: stage assets
zoe -> zoe: ""reallocate(seat, poolSeat)""

usA --> pu: ""userSeat""
pu -> zoe: ""getOfferResult()""
return result of failure or success
end
group recovering funds
pu -> usA: ""getPayout("Liquidity")"" (give)
return ""payoutLiquidity""
pu -> pu: deposit ""payoutLiquidity"" into purse
pu -> usA: ""getPayout("Central")"" (want)
return ""payoutCentral""
pu -> pu: deposit ""payoutCentral"" into purse
pu -> usA: ""getPayout("Secondary")"" (want)
return ""payoutSecondary""
pu -> pu: deposit ""payoutSecondary"" into purse
end

@enduml
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/threat_models/treasury/treasury.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
59 changes: 59 additions & 0 deletions docs/threat_models/treasury/treasury.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
@startuml
header Agoric Systems Operating Company.
footer v0.0.1
title Treasury

skinparam componentStyle rectangle
skinparam defaultTextAlignment center


actor "TreasuryCreator aka Governance" as tc

actor Borrower

node AdjustBalancesInvitation
node "CloseVaultInvitation"
node LiquidationPromise
node LiquidationSeat {
circle getPayout
circle getPayouts
}
node "Vat" {
node Treasury {
node AMM
node "publicAPI" {
circle getCollaterals
circle makeLoanInvitation
circle getRunIssuer
circle getAMM
getAMM -d-> AMM
}
node "creatorFacet" {
circle makeAddTypeInvitation
}
}
node "Vault" {
circle makeCloseInvitation
makeCloseInvitation -u-> CloseVaultInvitation
circle makeAdjustBalancesInvitation
makeAdjustBalancesInvitation -u-> AdjustBalancesInvitation
circle getCollateralAmount
circle getDebtAmount
circle getLiquidationSeat
getLiquidationSeat -u-> LiquidationSeat
circle getLiquidationPromise
getLiquidationPromise -u-> LiquidationPromise
}
}
Borrower -> makeLoanInvitation: open vault and transfer collateral
makeLoanInvitation -d-> Vault
Borrower -u-> getPayout: retrieve any proceeds
Borrower -u-> getPayouts: retrieve any proceeds
Borrower -d-> LiquidationPromise: did loan get liquidated?
Borrower -> AdjustBalancesInvitation: add or remove collateral or \nincrease or decrease the loan balance
Borrower -l-> CloseVaultInvitation: close loan and withdraw \nany remaining collateral
tc -d-> makeAddTypeInvitation
Borrower -d-> getDebtAmount: how much do I owe
Borrower -d-> getCollateralAmount: how much did I \ndeposit as collateral

@enduml