Skip to main content

PSMSwapper

Git Source

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

NameTypeDescription
_protocoladdressAddress of the PSM or DaiUsds converter contract
_routeRouteThe swap direction this instance handles
_tokenInaddressAddress of the input token
_tokenOutaddressAddress of the output token
_conversionFactoruint256Decimal 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

NameTypeDescription
_tokenInaddress
_tokenOutaddress
amountInuint256Maximum amount of tokenIn to pull from msg.sender
minAmountOutuint256Minimum acceptable output amount (reverts if not met)
receiveraddressAddress to receive the output tokens

Returns

NameTypeDescription
amountOutuint256Actual 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

NameTypeDescription
expecteduint256Minimum amount expected
actualuint256Amount actually received

NonOneToOneConversion

Thrown when a 1:1 DaiUsds conversion does not produce exact output

error NonOneToOneConversion(uint256 expected, uint256 actual);

Parameters

NameTypeDescription
expecteduint256The input amount (expected output for 1:1)
actualuint256Amount 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()
}