{"id":19096774,"url":"https://github.com/makerdao/dss-lite-psm","last_synced_at":"2025-04-30T14:15:02.504Z","repository":{"id":200504714,"uuid":"700399260","full_name":"makerdao/dss-lite-psm","owner":"makerdao","description":null,"archived":false,"fork":false,"pushed_at":"2025-03-28T12:20:22.000Z","size":2033,"stargazers_count":26,"open_issues_count":1,"forks_count":20,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-04-19T04:40:45.287Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Solidity","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/makerdao.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":"audits/ChainSecurity_MakerDAO_PSM_Lite_audit.pdf","citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-10-04T14:21:40.000Z","updated_at":"2025-04-09T13:30:01.000Z","dependencies_parsed_at":"2023-12-21T20:34:38.571Z","dependency_job_id":"b96023f6-0128-4c29-bef1-c8a1cf750e36","html_url":"https://github.com/makerdao/dss-lite-psm","commit_stats":null,"previous_names":["makerdao/dss-lite-psm"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/makerdao%2Fdss-lite-psm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/makerdao%2Fdss-lite-psm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/makerdao%2Fdss-lite-psm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/makerdao%2Fdss-lite-psm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/makerdao","download_url":"https://codeload.github.com/makerdao/dss-lite-psm/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251719146,"owners_count":21632618,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-09T03:37:46.599Z","updated_at":"2025-04-30T14:15:02.401Z","avatar_url":"https://github.com/makerdao.png","language":"Solidity","funding_links":[],"categories":[],"sub_categories":[],"readme":"# `dss-lite-psm`\n\nLightweight Peg Stability Module (LitePSM) implementation.\n\n## Table of Contents\n\n\u003c!-- vim-markdown-toc GFM --\u003e\n\n- [Deployments](#deployments)\n- [Overview](#overview)\n- [Architecture](#architecture)\n  - [Design and Constraints](#design-and-constraints)\n  - [Known Limitations](#known-limitations)\n    - [1. Potential Front-Running](#1-potential-front-running)\n    - [2. No Slippage Protection](#2-no-slippage-protection)\n    - [3. No Support for Upgradeable Gems](#3-no-support-for-upgradeable-gems)\n    - [4. Emergency Shutdown](#4-emergency-shutdown)\n- [Contributing](#contributing)\n\n\u003c!-- vim-markdown-toc --\u003e\n\n## Deployments\n\n| Network          | Chain ID | Description  | Address                                                                                                               |\n| :------          | -------: | :----------  | :------                                                                                                               |\n| Ethereum Mainnet | 1        | Gem (USDC)   | [`0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48`][usdc] |\n|                  |          | Lite PSM     | [`0xf6e72Db5454dd049d0788e411b06CfAF16853042`][lite-psm]                                                              |\n|                  |          | Pocket       | [`0x37305B1cD40574E4C5Ce33f8e8306Be057fD7341`][pocket]                                                                |\n|                  |          | Lite PSM Mom | [`0x467b32b0407Ad764f56304420Cddaa563bDab425`][lite-psm-mom]                                                          |\n\n  [usdc]: https://etherscan.io/address/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48\n  [lite-psm]: https://etherscan.io/address/0xf6e72Db5454dd049d0788e411b06CfAF16853042\n  [pocket]: https://etherscan.io/address/0x37305B1cD40574E4C5Ce33f8e8306Be057fD7341\n  [lite-psm-mom]: https://etherscan.io/address/0x467b32b0407Ad764f56304420Cddaa563bDab425\n\n## Overview\n\nA Peg Stability Module (PSM) is a facility through which users can freely swap Dai for stablecoins with no slippage.\nMakerDAO Governance can enable swap fees, though, which are computed as revenue for the protocol.\n\nThis module is heavily inspired by the [current PSM][psm], [PSM v2][psm-v2] and some other PSM prototypes within\nMakerDAO repositories.\n\nThe issue with those implementations is that swapping through them can be quite gas intensive, because they manipulate\nthe `Vat` (MakerDAO's main accounting module) directly on every swap.\n\nTo help alleviate this problem, `DssLitePsm` aims to be more gas efficient. The strategy is to allow users to swap in a\n**pool** of pre-minted Dai and stablecoins, reducing the swap to 2 ERC-20 token transfers with little overhead.\n\nThe required bookkeeping is done _off-band_ (not to be confused with _off-chain_), through a set of permissionless\nfunctions that aim to keep the pool operating under the predefined constraints, and incorporate the accumulated swap\nfees into the protocol's surplus buffer.\n\nFurthermore, there is a new requirement \u0026ndash; related to MakerDAO Endgame \u0026ndash; to allow authorized parties to swap\nthrough the PSM without paying any fees, even if they have been activated by Governance. Apart from the existing\npermissionless `buyGem` / `sellGem` functions, this iteration introduces `buyGemNoFee` / `sellGemNoFee` permissioned\ncounterparties.\n\nLast, but not least, in this version `gem` balance **can** be held in a different address to allow the protocol to\nreceive yield from stablecoins that require the custody of the assets to be segregated. This address can be either an\norphaned EOA or a bespoke smart contract. The only constraint is that `DssLitePsm` **should** be able to freely move any\namount of `gem` on behalf of such address.\n\n## Architecture\n\nA simplified diagram of the `DssLitePsm` architecture:\n\n```\n                                                buyGemNoFee /\n                                           ╭────────────────────────  🤴\n ╭─────────╮                               │    sellGemNoFee      Whitelisted\n │         │       transferFrom            │                         User\n │   Gem   ◄────────────────────────────╮  │\n │         │                            │  │\n ╰────▲────╯                            │  │\n      │                                 │  │\n      │                                 │  │\n      │ approve ·····╮                  │  │\n      │              ╎                  │  │\n╭─────┴────╮         ╎          ╭───────┴──▼───╮\n│          │         ╎          │              │     buyGem /\n│  Pocket  │         ╰·········\u003e│  DssLitePsm  ◄────────────────────  🧑\n│          │                    │              │     sellGem         User\n╰──────────╯                    ╰─┬──┬──┬──▲─▲─╯\n                                  │  │  │  │ │\n                                  │  │  │  │ │\n                 frob             │  │  │  │ │\n     ╭────────────────────────────╯  │  │  │ │\n     │                               │  │  │ │\n     │                               │  │  │ │\n     │                               │  │  │ │ fill / trim / chug\n     │                   join / exit │  │  │ ╰──────────────────────  👷\n     │                               │  │  │                        Keeper\n     │                               │  │  │\n╭────▼────╮          ╭───────────╮   │  │  │           ╭─────────────────╮   \n│         │   move   │           │   │  │  │   file    │                 │   \n│   Vat   ◄──────────┤  DaiJoin  ◄───╯  │  ╰───────────│  DssLitePsmMom  │   \n│         │          │           │      │              │                 │   \n╰─────────╯          ╰─────┬─────╯      │              ╰─────────────────╯   \n                           │            │\n                           │            │\n               mint / burn │            │\n                           │            │ transfer / transferFrom\n                           │            │\n                      ╭────▼────╮       │\n                      │         │       │\n                      │   Dai   ◄───────╯\n                      │         │\n                      ╰─────────╯\n```\n\n### Design and Constraints\n\nThese are the main constraints that guided the design of this module:\n\n1. Gas efficiency: make swaps as cheap in terms of gas as possible, without sacrificing security and readability.\n1. Backwards compatibility: the new implementation should not break integrations with the current one.\n1. Permissioned no-fee swaps: specific actors are allowed to use the PSM for swaps without paying any swap fees.\n\nPart of the Dai liquidity available in `DssLitePsm` is technically unbacked Dai. This not a problem because the Dai is\nlocked into `DssLitePsm` until users deposit USDC, backing the amount that is going to be released.\n\n### Known Limitations\n\n#### 1. Potential Front-Running\n\n`DssLitePsm` relies on pre-minted Dai. It is designed to keep a fixed-sized amount (`buf`) of it available most of the\ntime.  However, when users call `buyGem`, the amount of Dai available will be temporarily larger than `buf`.\n\n**Scenario A:** a user might observe the outstanding amount of Dai and wish to call `sellGem` to receive the total of\nDai in return. In that scenario, there is a possibility of a transaction calling any of the permissionless bookkeeping\nfunctions to front-run them, causing the swap to fail, as the Dai liquidity would be lower than the required amount.\n\nThe scenario A above is not possible with the current PSM implementation because each swap is \"self-balancing\", so no\noff-band bookkeeping is required.\n\n**Scenario B:** a large swap might front-run another one, even if unintentionally. Imagine there is `10M` Dai\noutstanding in `DssLitePsm`. If Alice \u0026ndash; who wants to swap `8M` \u0026ndash; and Bob \u0026ndash; who wants to swap `3M`\n\u0026ndash; submit their transactions at the same time, only the first one will be executed.\n\nThe scenario B above is not possible with the current PSM implementation because `sellGem` is able to mint Dai\non-the-fly to fulfill the swap, given that there is enough room in the debt ceiling.\n\nNotice how the same issue happens in `buyGem`, however the amount of `gem` deposited into `DssLitePsm` is only bounded\nby the debt ceiling, while the amount of `Dai` will tend to gravitate towards `buf`.\n\nThe consequence is that anyone willing to call `sellGem` with a value larger than `buf` should take care of potential\nfront-running transactions by bundling it with an optional liquidity increase (`fill`).\n\n#### 2. No Slippage Protection\n\nSwaps in `DssLitePsm` are generally not subject to slippage. The only exception is when there is a MakerDAO Governance\nproposal to increase the swapping fees `tin` and/or `tout`. That is done through an Executive Spell, which is an\non-chain smart contract that can be permissionlessly _cast_ (executed) after following the Governance process.\n\nIf Alice sends a swap transaction and a spell increasing the fees is cast before her transaction, she will either pay\nmore Dai when buying gems or receive less Dai when selling gems than the originally expected.\n\nThis is a highly unlikely scenario, but users or aggregators are able to handle this issue through a wrapper contract.\n\n#### 3. No Support for Upgradeable Gems\n\nWe no longer have a dedicated `GemJoin` contract to normalize different token implementations. For instance, we lost the\ncapacity to identify upgrades in upgradeable tokens when compared to the previous iteration of the [PSM][gem-join-8].\n\nOn the other hand, non-upgradeable gems that [do not return `true` on `transfer`/`transferFrom`][weird-erc20] were not\npreviously supported, but we removed such restriction in this iteration.\n\n#### 4. Emergency Shutdown\n\n`DssLitePsm` assumes the ESM threshold is set large enough prior to its deployment, so Emergency Shutdown can never be\ncalled.\n\n## Contributing\n\nTo be able to run the integration tests, you need to set the `ETH_RPC_URL` env var to a valid Mainnet node:\n\n```bash\nETH_RPC_URL='...' forge test -vvv\n```\n\nYou can also use a `.env` file for that (see `.env.example`):\n\n```bash\n# .env\nETH_RPC_URL='...'\n```\n\nThen simply run:\n```bash\nforge test -vvv\n```\n\n[psm]: https://github.com/makerdao/dss-psm/blob/master/src/psm.sol\n[psm-v2]: https://github.com/makerdao/dss-psm/blob/v2/src/psm.sol\n[auto-line]: https://etherscan.io/address/0xc7bdd1f2b16447dcf3de045c4a039a60ec2f0ba3\n[gem-join-8]: https://github.com/makerdao/dss-psm/blob/master/src/join-8-auth.sol#L36\n[weird-erc20]: https://github.com/d-xo/weird-erc20/#missing-return-values\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmakerdao%2Fdss-lite-psm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmakerdao%2Fdss-lite-psm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmakerdao%2Fdss-lite-psm/lists"}