PSMSwapper
Inherits: ISwapper
Title: PSMSwapper
Author: Golem Foundation
ISwapper adapter for Sky Protocol Peg Stability Module (PSM) and DaiUsds converter
Supports four swap routes for stablecoin conversions on Ethereum mainnet: SELL_GEM: gem (e.g., USDC) -> DAI/USDS via PSM (LitePSM or LitePSMWrapper) BUY_GEM: DAI/USDS -> gem (e.g., USDC) via PSM (LitePSM or LitePSMWrapper) DAI_TO_USDS: DAI -> USDS via DaiUsds converter (always 1:1, permanently fee-free) USDS_TO_DAI: USDS -> DAI via DaiUsds converter (always 1:1, permanently fee-free) Key addresses on Ethereum mainnet:
- LitePSM (USDC/DAI): 0xf6e72Db5454dd049d0788e411b06CfAF16853042
- LitePSMWrapper (USDC/USDS): 0xA188EEC8F81263234dA3622A406892F3d630f98c
- DaiUsds converter: 0x3225737a9Bbb6473CB4a45b7244ACa2BeFdB276A PSM fees (tin/tout) are currently 0% but are governance-controlled and may change. The BUY_GEM route dynamically queries tout() to calculate the correct gem amount. This contract is fully immutable and holds no tokens between calls.
Note: security-contact: [email protected]
Quick Start - What Matters Most
PSM adapter for the ISwapper pull pattern. It supports the configured PSM routes, enforces minimum output, and flushes leftovers rather than retaining balances.
State Variables
WAD
1e18, used for PSM fee calculations
uint256 internal constant WAD = 1e18
protocol
The PSM or DaiUsds converter contract address
address public immutable protocol
route
The configured swap direction
Route public immutable route
tokenIn
The expected input token for this swapper instance
address public immutable tokenIn
tokenOut
The expected output token for this swapper instance
address public immutable tokenOut
conversionFactor
Decimal conversion factor between gem and DAI/USDS (e.g., 1e12 for USDC)
Only used for BUY_GEM route. Set to 0 for other routes.
uint256 public immutable conversionFactor
Functions
constructor
Creates a PSMSwapper configured for a specific stablecoin swap route
constructor(address _protocol, Route _route, address _tokenIn, address _tokenOut, uint256 _conversionFactor) ;
Parameters
| Name | Type | Description |
|---|---|---|
_protocol | address | Address of the PSM or DaiUsds converter contract |
_route | Route | The swap direction this instance handles |
_tokenIn | address | Address of the input token |
_tokenOut | address | Address of the output token |
_conversionFactor | uint256 | Decimal scaling factor (e.g., 1e12 for 6->18 decimal conversion). Required for BUY_GEM, ignored for other routes. |
swap
Execute a token swap and send output to receiver
The caller MUST have approved this contract for at least amountIn
of tokenIn before calling. The implementation pulls via
transferFrom(msg.sender, this, amountIn) and returns any unused
tokenIn to msg.sender before returning.
Reverts if output is less than minAmountOut.
function swap(address _tokenIn, address _tokenOut, uint256 amountIn, uint256 minAmountOut, address receiver)
external
override
returns (uint256 amountOut);
Parameters
| Name | Type | Description |
|---|---|---|
_tokenIn | address | |
_tokenOut | address | |
amountIn | uint256 | Maximum amount of tokenIn to pull from msg.sender |
minAmountOut | uint256 | Minimum acceptable output amount (reverts if not met) |
receiver | address | Address to receive the output tokens |
Returns
| Name | Type | Description |
|---|---|---|
amountOut | uint256 | Actual amount of tokenOut sent to receiver |
_sellGem
Sell gem (e.g., USDC) for DAI/USDS via PSM. PSM pulls gem from this contract and sends DAI/USDS to this contract, which then forwards to receiver.
function _sellGem(uint256 amountIn, address receiver) internal returns (uint256 amountOut);
_buyGem
Buy gem (e.g., USDC) with DAI/USDS via PSM. Calculates max gem purchasable from amountIn accounting for PSM fees (tout), then pulls ONLY the exact charge (gemAmt * conversionFactor * (WAD + tout) / WAD) via transferFrom so the floor-division remainder stays with the caller rather than being stranded in this adapter.
function _buyGem(uint256 amountIn, address receiver) internal returns (uint256 amountOut);
_daiToUsds
Convert DAI to USDS via DaiUsds converter (always 1:1, permanently fee-free). Output is sent directly to receiver by the converter contract. Reverts if the actual output does not match amountIn exactly.
function _daiToUsds(uint256 amountIn, address receiver) internal returns (uint256 amountOut);
_usdsToDai
Convert USDS to DAI via DaiUsds converter (always 1:1, permanently fee-free). Output is sent directly to receiver by the converter contract. Reverts if the actual output does not match amountIn exactly.
function _usdsToDai(uint256 amountIn, address receiver) internal returns (uint256 amountOut);
Errors
InvalidProtocol
Thrown when the protocol address is zero
error InvalidProtocol();
InvalidToken
Thrown when a token address is zero or does not match the configured route
error InvalidToken();
InsufficientOutput
Thrown when the swap output is less than the minimum required
error InsufficientOutput(uint256 expected, uint256 actual);
Parameters
| Name | Type | Description |
|---|---|---|
expected | uint256 | Minimum amount expected |
actual | uint256 | Amount actually received |
NonOneToOneConversion
Thrown when a 1:1 DaiUsds conversion does not produce exact output
error NonOneToOneConversion(uint256 expected, uint256 actual);
Parameters
| Name | Type | Description |
|---|---|---|
expected | uint256 | The input amount (expected output for 1:1) |
actual | uint256 | Amount actually received |
InvalidConversionFactor
Thrown when conversionFactor is zero for the BUY_GEM route
error InvalidConversionFactor();
Enums
Route
enum Route {
SELL_GEM, // gem (e.g., USDC) -> DAI/USDS via IPSM.sellGem()
BUY_GEM, // DAI/USDS -> gem (e.g., USDC) via IPSM.buyGem()
DAI_TO_USDS, // DAI -> USDS via IExchange.daiToUsds()
USDS_TO_DAI // USDS -> DAI via IExchange.usdsToDai()
}