Swapper Engine
Last updated
Was this helpful?
Last updated
Was this helpful?
The SwapperEngine
contract is a smart contract designed to facilitate the swapping of USDC tokens for USD0 tokens using an order matching mechanism. The contract allows users to create orders specifying the amount of USDC they wish to swap, and other users can fill these orders by providing USD0 tokens in return. The contract aims to provide a direct token swapping solution without the need for intermediary liquidity pools.
The main objective of the SwapperEngine contract is to enable efficient and low-slippage token swaps between users. The contract relies on oracle-based pricing to determine swap prices, which helps minimize slippage. However, liquidity within the contract depends on the availability of active orders, and users may need to wait for new orders to be created if no matching orders are available.
It is important to note that the contract's mechanism can be utilized to facilitate a vampire attack, RWA → USD0 → USDC → $$$ → RWA → to churn USDC into USD0 by transparently staking treasury bonds to mint USD0 swapping that USD0 for USDC and cycling back into RWA ready to mint more USD0 limited only by USDC order book depth.
Flow USDC Depositors:
Flow RWA Provider:
The contract provides the following main functions:
depositUSDC: Allows users to create a new order by depositing USDC.
withdrawUSDC: Allows users to cancel an order and withdraw their deposited USDC.
provideUsd0ReceiveUSDC: Allows users to fill orders by providing USD0 and receiving USDC in return.
The contract also includes utility functions such as getOrder, getUsd0WadEquivalent, and getUsdcWadPrice to retrieve order details and perform price calculations. The swapperEngine has no option to define a maxUSDCPrice for buyers and seller's don't have the option to define a minimumUSDCPrice, instead the prices are provided by an USDC oracle, which also has measures against a potential USDC depeg. USD0's price is considered to be $1 == 1USD0 due to the numerous mechanisms in place to prevent a depeg, like reserves, CBR mechanism, arbitrage etc.
Initializable (OZ): Used to provide a safe and controlled way to initialize the contract's state variables. It ensures that the contract's initializer function can only be called once, preventing accidental or malicious reinitialization.
ReentrancyGuardUpgradeable (OZ): Used to protect against reentrancy attacks. It provides a modifier that can be applied to functions to prevent them from being called recursively or from being called from other functions that are also protected by the same guard.
PausableUpgradeable (OZ): Allows contract functionality to be paused by authorized accounts (PAUSING_CONTRACTS_ROLE
to pause the contract and DEFAULT_ADMIN_ROLE
to un-pause).
The SwapperEngine contract's primary purpose is to facilitate the swapping of USDC tokens for USD0 tokens using an order matching mechanism. The contract's functionality can be broken down into the following key components:
Order Creation:
Users can create new orders by calling the depositUSDC function and specifying the amount of USDC they wish to swap.
The contract transfers the specified amount of USDC tokens from the user to itself and creates a new order with the deposited amount and the user's address as the requester.
The order is assigned a unique order ID and stored in the contract's orders mapping.
Order Cancellation:
Users who have created an order can cancel it by calling the withdrawUSDC function and specifying the order ID.
The contract verifies that the caller is the requester of the order and that the order is active.
If the conditions are met, the contract deactivates the order, sets its token amount to zero, and transfers the deposited USDC tokens back to the requester.
Order Matching:
Users can fill existing orders by specifying the recipient address, the amount of USDC to take (or the amount of USD0 to give), an array of order IDs to match against, and whether partial matching is allowed.
The contract verifies that the caller has sufficient USD0 balance and allowance to cover the required amount based on the current USDC Price Calculation obtained from the oracle.
The contract iterates through the provided order IDs and attempts to match the requested USDC amount against active orders.
If partial matching is allowed and there is not enough USDC in the orders to fulfil the entire request, the contract will partially fill orders until the requested amount is met or all orders are exhausted.
For each matched order, the contract transfers the corresponding USD0 tokens from the caller to the order requester and transfers the USDC tokens from itself to the specified recipient.
If partial matching is not allowed and the requested USDC amount cannot be fully matched, the contract reverts the transaction.
Price Calculation:
The contract relies on an external oracle contract to obtain the current price of USDC tokens in WAD format (18 decimals).
The getUsdcWadPrice function is used to retrieve the current USDC price from the oracle.
The getUsd0WadEquivalent function is used to calculate the equivalent amount of USD0 tokens for a given amount of USDC tokens based on the current price.
This method allows users to provide USD0 tokens and receive USDC tokens by matching against existing orders. It matches the requested USDC amount to the provided USD0 tokens against the specified orders, transfers the corresponding USDC tokens to the recipient, and updates the order states accordingly.
The function is protected against reentrancy attacks by using the nonReentrant modifier, ensuring that the function cannot be called recursively or from other functions that are also protected by the same guard.
Validates that the amount of USDC to take is greater than zero.
Validates that at least one order ID is provided for matching.
Retrieves the contract's storage using the correct storage pattern.
Retrieves the current price of USDC in WAD format (18 decimals) from an oracle, ensuring that the price used for calculations is up-to-date and accurate.
Initializes the total amount of USDC taken to zero.
Retrieves the order details for the current order ID.
Checks if the order is active before processing. 12-13. If the order is active, calculates the amount of USDC to take from the current order based on the remaining amount to take and the order's available balance. 14-15. Updates the order's token amount and the total USDC taken.
Marks the order as inactive if its token amount reaches zero.
Calculates the equivalent USD0 amount for the USDC taken from the order using the _getUsd0WadEquivalent function and the current USDC price.
Updates the total USD0 provided with the calculated amount.
Transfers the USD0 tokens from the sender to the order requester.
Transfers the USDC tokens from the contract to the recipient.
Emits an OrderMatched event with the relevant details.
Increments the loop counter using an unchecked block for gas optimization.
Reverts the transaction if partial matching is not allowed and the total USDC taken does not match the requested amount or if no USDC was taken.
Returns the remaining amount of USDC that was not taken and the total USD0 provided.
This method calculates the USD0 equivalent amount in WAD format (18 decimals) for a given USDC token amount. It converts the USDC token amount from its native decimal representation (6 decimals) to WAD format and then calculates the equivalent USD0 amount based on the provided USDC price in WAD format.
Retrieves the contract's storage using the correct storage pattern.
Retrieves the decimal places of the USDC token using the decimals() function from the IERC20Metadata interface.
Converts the usdcTokenAmountInNativeDecimals to WAD format (18 decimals) using the tokenAmountToWad function, which takes into account the token's native decimals.
Calculates the equivalent amount of USD0 tokens in WAD format by multiplying the usdcWad amount with the usdcWadPrice using the wadAmountByPrice function.
This method allows users to deposit USDC tokens and create a new order. It transfers the specified amount of USDC tokens from the caller to the contract and creates a new order with the deposited amount and the caller as the requester.
The function is protected against reentrancy attacks by using the nonReentrant modifier, ensuring that the function cannot be called recursively or from other functions that are also protected by the same guard.
Retrieves the contract's storage using the correct storage pattern.
Validates that the amount of USDC to deposit is greater than or equal to the minimum required amount specified in the contract's storage. This prevents any attempts to deposit amounts below the minimum threshold.
Sets the value of orderId to the current value of $.nextOrderId then increments by 1. Since it is initialized as 1, the first orderId will be one and so on.
Creates a new UsdcOrder struct in storage using the order ID as key. The struct is set up correctly to contain: the requester's address (msg.sender), the deposited token amount (amountToDeposit), and sets the active flag to true.
Transfers the specified amount of USDC tokens from the caller (msg.sender) to the contract (address(this)) using the safeTransferFrom function to ensure that the transfer is successful and the contract receives the deposited tokens. If the transfer fails, the function will revert.
Emits a Deposit event, providing the order ID and the deposited amount for the subgraph.
This method allows the requester of an order to withdraw their deposited USDC tokens and cancel the order. It deactivates the specified order, sets its token amount to zero, and transfers the deposited USDC tokens back to the requester.
The function is protected against reentrancy attacks by using the nonReentrant modifier, ensuring that the function cannot be called recursively or from other functions that are also protected by the same guard.
Retrieves the contract's storage using the correct storage pattern.
Retrieves the UsdcOrder struct as storage so it will be modified.
Checks if the order is active using the active flag. If the order is not active or does not exist, the function will revert with an appropriate error message. This prevents any attempts to withdraw from invalid or canceled orders.
Verifies that the caller (msg.sender) is the requester of the order. This ensures that only the original requester can cancel their own order and withdraw the deposited tokens.
Retrieves the token amount associated with the order and assigns it to the amountToWithdraw variable.
Sets the active flag of the order to false in storage.
Sets the tokenAmount of the order to zero in storage.
Transfers the amountToWithdraw of USDC tokens from the contract back to the requester (msg.sender) using the safeTransfer function. This ensures that the transfer is successful and the requester receives their tokens. If the transfer fails, the function will revert.
Emits a Withdraw event, providing the orderToCancel ID and the amountToWithdraw for the subgraph
This method allows users to provide USD0 tokens and receive USDC tokens by matching against existing orders. It matches the specified amount of USD0 tokens against the specified orders, transfers the corresponding USDC tokens to the recipient, and updates the order states accordingly.
The function is protected against reentrancy attacks by using the nonReentrant modifier, ensuring that the function cannot be called recursively or from other functions that are also protected by the same guard.
Retrieves the current USDC price in WAD format using the getUsdcWadPrice() function. 3-5. Calculates the equivalent amount of USDC to take in native decimals based on the provided amountUsd0ToProvideInWad and the current usdcWadPrice using the _getUsdcAmountFromUsd0WadEquivalent function. Then calls the _provideUsd0ReceiveUSDC function to perform the actual swap, passing the recipient, amountUsdcToTakeInNativeDecimals, orderIdsToTake, and partialMatchingAllowed parameters. The function returns the total amount of usd0 provided.
Returns the sum of unmatchedUsd0 in wad format including dust, representing the total amount of USD0 that was not matched or was left as dust.