Skip to content

Commit

Permalink
fix: merge conflicts
Browse files Browse the repository at this point in the history
  • Loading branch information
lucas-manuel committed Jun 10, 2024
2 parents 376fa83 + 23c870d commit ce0949f
Show file tree
Hide file tree
Showing 16 changed files with 196 additions and 176 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ For detailed implementation, refer to the contract code and `IPSM` interface doc

## Contracts

- **`src/PSM.sol`**: The core contract implementing the `IPSM` interface, providing functionality for swapping, depositing, and withdrawing assets.
- **`src/interfaces/IPSM.sol`**: Defines the essential functions and events that the PSM contract implements.
- **`src/PSM3.sol`**: The core contract implementing the `IPSM3` interface, providing functionality for swapping, depositing, and withdrawing assets.
- **`src/interfaces/IPSM3.sol`**: Defines the essential functions and events that the PSM contract implements.

## [CRITICAL]: First Depositor Attack Prevention on Deployment

Expand Down
62 changes: 32 additions & 30 deletions src/PSM3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import { IERC20 } from "erc20-helpers/interfaces/IERC20.sol";

import { SafeERC20 } from "erc20-helpers/SafeERC20.sol";

import { IPSM } from "src/interfaces/IPSM.sol";
import { IPSM3 } from "src/interfaces/IPSM3.sol";

interface IRateProviderLike {
function getConversionRate() external view returns (uint256);
}

// TODO: Prove that we're always rounding against user
contract PSM3 is IPSM {
contract PSM3 is IPSM3 {

using SafeERC20 for IERC20;

Expand All @@ -33,14 +33,14 @@ contract PSM3 is IPSM {
mapping(address user => uint256 shares) public shares;

constructor(address asset0_, address asset1_, address asset2_, address rateProvider_) {
require(asset0_ != address(0), "PSM/invalid-asset0");
require(asset1_ != address(0), "PSM/invalid-asset1");
require(asset2_ != address(0), "PSM/invalid-asset2");
require(rateProvider_ != address(0), "PSM/invalid-rateProvider");
require(asset0_ != address(0), "PSM3/invalid-asset0");
require(asset1_ != address(0), "PSM3/invalid-asset1");
require(asset2_ != address(0), "PSM3/invalid-asset2");
require(rateProvider_ != address(0), "PSM3/invalid-rateProvider");

require(asset0_ != asset1_, "PSM/asset0-asset1-same");
require(asset0_ != asset2_, "PSM/asset0-asset2-same");
require(asset1_ != asset2_, "PSM/asset1-asset2-same");
require(asset0_ != asset1_, "PSM3/asset0-asset1-same");
require(asset0_ != asset2_, "PSM3/asset0-asset2-same");
require(asset1_ != asset2_, "PSM3/asset1-asset2-same");

asset0 = IERC20(asset0_);
asset1 = IERC20(asset1_);
Expand All @@ -63,16 +63,16 @@ contract PSM3 is IPSM {
uint256 amountIn,
uint256 minAmountOut,
address receiver,
uint16 referralCode
uint256 referralCode
)
external
external override
{
require(amountIn != 0, "PSM/invalid-amountIn");
require(receiver != address(0), "PSM/invalid-receiver");
require(amountIn != 0, "PSM3/invalid-amountIn");
require(receiver != address(0), "PSM3/invalid-receiver");

uint256 amountOut = previewSwap(assetIn, assetOut, amountIn);

require(amountOut >= minAmountOut, "PSM/amountOut-too-low");
require(amountOut >= minAmountOut, "PSM3/amountOut-too-low");

IERC20(assetIn).safeTransferFrom(msg.sender, address(this), amountIn);
IERC20(assetOut).safeTransfer(receiver, amountOut);
Expand All @@ -84,11 +84,11 @@ contract PSM3 is IPSM {
/*** Liquidity provision functions ***/
/**********************************************************************************************/

function deposit(address asset, address receiver, uint256 assetsToDeposit, uint16 referralCode)
function deposit(address asset, address receiver, uint256 assetsToDeposit)
external override returns (uint256 newShares)
{
require(receiver != address(0), "PSM/invalid-receiver");
require(assetsToDeposit != 0, "PSM/invalid-amount");
require(receiver != address(0), "PSM3/invalid-receiver");
require(assetsToDeposit != 0, "PSM3/invalid-amount");

newShares = previewDeposit(asset, assetsToDeposit);

Expand All @@ -97,14 +97,14 @@ contract PSM3 is IPSM {

IERC20(asset).safeTransferFrom(msg.sender, address(this), assetsToDeposit);

emit Deposit(asset, msg.sender, receiver, assetsToDeposit, newShares, referralCode);
emit Deposit(asset, msg.sender, receiver, assetsToDeposit, newShares);
}

function withdraw(address asset, address receiver, uint256 maxAssetsToWithdraw, uint16 referralCode)
function withdraw(address asset, address receiver, uint256 maxAssetsToWithdraw)
external override returns (uint256 assetsWithdrawn)
{
require(receiver != address(0), "PSM/invalid-receiver");
require(maxAssetsToWithdraw != 0, "PSM/invalid-amount");
require(receiver != address(0), "PSM3/invalid-receiver");
require(maxAssetsToWithdraw != 0, "PSM3/invalid-amount");

uint256 sharesToBurn;

Expand All @@ -117,15 +117,17 @@ contract PSM3 is IPSM {

IERC20(asset).safeTransfer(receiver, assetsWithdrawn);

emit Withdraw(asset, msg.sender, receiver, assetsWithdrawn, sharesToBurn, referralCode);
emit Withdraw(asset, msg.sender, receiver, assetsWithdrawn, sharesToBurn);
}

/**********************************************************************************************/
/*** Deposit/withdraw preview functions ***/
/**********************************************************************************************/

function previewDeposit(address asset, uint256 assetsToDeposit) public view returns (uint256) {
require(_isValidAsset(asset), "PSM/invalid-asset");
function previewDeposit(address asset, uint256 assetsToDeposit)
public view override returns (uint256)
{
require(_isValidAsset(asset), "PSM3/invalid-asset");

// Convert amount to 1e18 precision denominated in value of asset0 then convert to shares.
return convertToShares(_getAssetValue(asset, assetsToDeposit));
Expand All @@ -134,7 +136,7 @@ contract PSM3 is IPSM {
function previewWithdraw(address asset, uint256 maxAssetsToWithdraw)
public view override returns (uint256 sharesToBurn, uint256 assetsWithdrawn)
{
require(_isValidAsset(asset), "PSM/invalid-asset");
require(_isValidAsset(asset), "PSM3/invalid-asset");

uint256 assetBalance = IERC20(asset).balanceOf(address(this));

Expand Down Expand Up @@ -174,17 +176,17 @@ contract PSM3 is IPSM {
else if (assetOut == address(asset1)) return _previewSwapFromAsset2(amountIn, _asset1Precision);
}

revert("PSM/invalid-asset");
revert("PSM3/invalid-asset");
}

/**********************************************************************************************/
/*** Swap preview functions ***/
/*** Conversion functions ***/
/**********************************************************************************************/

function convertToAssets(address asset, uint256 numShares)
public view override returns (uint256)
{
require(_isValidAsset(asset), "PSM/invalid-asset");
require(_isValidAsset(asset), "PSM3/invalid-asset");

uint256 assetValue = convertToAssetValue(numShares);

Expand Down Expand Up @@ -216,7 +218,7 @@ contract PSM3 is IPSM {
}

function convertToShares(address asset, uint256 assets) public view override returns (uint256) {
require(_isValidAsset(asset), "PSM/invalid-asset");
require(_isValidAsset(asset), "PSM3/invalid-asset");
return convertToShares(_getAssetValue(asset, assets));
}

Expand Down Expand Up @@ -252,7 +254,7 @@ contract PSM3 is IPSM {
if (asset == address(asset0)) return _getAsset0Value(amount);
else if (asset == address(asset1)) return _getAsset1Value(amount);
else if (asset == address(asset2)) return _getAsset2Value(amount);
else revert("PSM/invalid-asset");
else revert("PSM3/invalid-asset");
}

function _getAsset0Value(uint256 amount) internal view returns (uint256) {
Expand Down
23 changes: 8 additions & 15 deletions src/interfaces/IPSM.sol → src/interfaces/IPSM3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pragma solidity ^0.8.13;

import { IERC20 } from "erc20-helpers/interfaces/IERC20.sol";

interface IPSM {
interface IPSM3 {

// TODO: Determine priority for indexing

Expand All @@ -28,7 +28,7 @@ interface IPSM {
address indexed receiver,
uint256 amountIn,
uint256 amountOut,
uint16 referralCode
uint256 referralCode
);

/**
Expand All @@ -38,15 +38,13 @@ interface IPSM {
* @param receiver Address of the receiver of the resulting shares from the deposit.
* @param assetsDeposited Amount of the asset deposited.
* @param sharesMinted Number of shares minted to the user.
* @param referralCode Referral code for the deposit.
*/
event Deposit(
address indexed asset,
address indexed user,
address indexed receiver,
uint256 assetsDeposited,
uint256 sharesMinted,
uint16 referralCode
uint256 sharesMinted
);

/**
Expand All @@ -56,15 +54,13 @@ interface IPSM {
* @param receiver Address of the receiver of the withdrawn assets.
* @param assetsWithdrawn Amount of the asset withdrawn.
* @param sharesBurned Number of shares burned from the user.
* @param referralCode Referral code for the withdrawal.
*/
event Withdraw(
address indexed asset,
address indexed user,
address indexed receiver,
uint256 assetsWithdrawn,
uint256 sharesBurned,
uint16 referralCode
uint256 sharesBurned
);

/**********************************************************************************************/
Expand Down Expand Up @@ -136,7 +132,7 @@ interface IPSM {
uint256 amountIn,
uint256 minAmountOut,
address receiver,
uint16 referralCode
uint256 referralCode
) external;

/**********************************************************************************************/
Expand All @@ -150,10 +146,9 @@ interface IPSM {
* @param asset Address of the ERC-20 asset to deposit.
* @param receiver Address of the receiver of the resulting shares from the deposit.
* @param assetsToDeposit Amount of the asset to deposit into the PSM.
* @param referralCode Referral code for the deposit.
* @return newShares Number of shares minted to the user.
*/
function deposit(address asset, address receiver, uint256 assetsToDeposit, uint16 referralCode)
function deposit(address asset, address receiver, uint256 assetsToDeposit)
external returns (uint256 newShares);

/**
Expand All @@ -164,14 +159,12 @@ interface IPSM {
* @param asset Address of the ERC-20 asset to withdraw.
* @param receiver Address of the receiver of the withdrawn assets.
* @param maxAssetsToWithdraw Max amount that the user is willing to withdraw.
* @param referralCode Referral code for the withdrawal.
* @return assetsWithdrawn Resulting amount of the asset withdrawn from the PSM.
*/
function withdraw(
address asset,
address asset,
address receiver,
uint256 maxAssetsToWithdraw,
uint16 referralCode
uint256 maxAssetsToWithdraw
) external returns (uint256 assetsWithdrawn);

/**********************************************************************************************/
Expand Down
6 changes: 3 additions & 3 deletions test/PSMTestBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ contract PSMTestBase is Test {
// NOTE: Using 1.25 for easy two way conversions
rateProvider.__setConversionRate(1.25e27);

psm = new PSM(address(dai), address(usdc), address(sDai), address(rateProvider));
psm = new PSM3(address(dai), address(usdc), address(sDai), address(rateProvider));

vm.label(address(dai), "DAI");
vm.label(address(usdc), "USDC");
Expand All @@ -62,7 +62,7 @@ contract PSMTestBase is Test {
vm.startPrank(user);
MockERC20(asset).mint(user, amount);
MockERC20(asset).approve(address(psm), amount);
psm.deposit(asset, receiver, amount, 0);
psm.deposit(asset, receiver, amount);
vm.stopPrank();
}

Expand All @@ -72,7 +72,7 @@ contract PSMTestBase is Test {

function _withdraw(address asset, address user, address receiver, uint256 amount) internal {
vm.prank(user);
psm.withdraw(asset, receiver, amount, 0);
psm.withdraw(asset, receiver, amount);
vm.stopPrank();
}

Expand Down
2 changes: 1 addition & 1 deletion test/invariant/handlers/Invariants.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pragma solidity ^0.8.13;

import "forge-std/Test.sol";

import { PSM } from "src/PSM.sol";
import { PSM3 } from "src/PSM3.sol";

import { PSMTestBase } from "test/PSMTestBase.sol";

Expand Down
32 changes: 16 additions & 16 deletions test/unit/Constructor.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,50 +3,50 @@ pragma solidity ^0.8.13;

import "forge-std/Test.sol";

import { PSM } from "src/PSM.sol";
import { PSM3 } from "src/PSM3.sol";

import { PSMTestBase } from "test/PSMTestBase.sol";

contract PSMConstructorTests is PSMTestBase {

function test_constructor_invalidAsset0() public {
vm.expectRevert("PSM/invalid-asset0");
new PSM(address(0), address(usdc), address(sDai), address(rateProvider));
vm.expectRevert("PSM3/invalid-asset0");
new PSM3(address(0), address(usdc), address(sDai), address(rateProvider));
}

function test_constructor_invalidAsset1() public {
vm.expectRevert("PSM/invalid-asset1");
new PSM(address(dai), address(0), address(sDai), address(rateProvider));
vm.expectRevert("PSM3/invalid-asset1");
new PSM3(address(dai), address(0), address(sDai), address(rateProvider));
}

function test_constructor_invalidAsset2() public {
vm.expectRevert("PSM/invalid-asset2");
new PSM(address(dai), address(usdc), address(0), address(rateProvider));
vm.expectRevert("PSM3/invalid-asset2");
new PSM3(address(dai), address(usdc), address(0), address(rateProvider));
}

function test_constructor_invalidRateProvider() public {
vm.expectRevert("PSM/invalid-rateProvider");
new PSM(address(dai), address(usdc), address(sDai), address(0));
vm.expectRevert("PSM3/invalid-rateProvider");
new PSM3(address(dai), address(usdc), address(sDai), address(0));
}

function test_constructor_asset0Asset1Match() public {
vm.expectRevert("PSM/asset0-asset1-same");
new PSM(address(dai), address(dai), address(sDai), address(rateProvider));
vm.expectRevert("PSM3/asset0-asset1-same");
new PSM3(address(dai), address(dai), address(sDai), address(rateProvider));
}

function test_constructor_asset0Asset2Match() public {
vm.expectRevert("PSM/asset0-asset2-same");
new PSM(address(dai), address(usdc), address(dai), address(rateProvider));
vm.expectRevert("PSM3/asset0-asset2-same");
new PSM3(address(dai), address(usdc), address(dai), address(rateProvider));
}

function test_constructor_asset1Asset2Match() public {
vm.expectRevert("PSM/asset1-asset2-same");
new PSM(address(dai), address(usdc), address(usdc), address(rateProvider));
vm.expectRevert("PSM3/asset1-asset2-same");
new PSM3(address(dai), address(usdc), address(usdc), address(rateProvider));
}

function test_constructor() public {
// Deploy new PSM to get test coverage
psm = new PSM(address(dai), address(usdc), address(sDai), address(rateProvider));
psm = new PSM3(address(dai), address(usdc), address(sDai), address(rateProvider));

assertEq(address(psm.asset0()), address(dai));
assertEq(address(psm.asset1()), address(usdc));
Expand Down
6 changes: 3 additions & 3 deletions test/unit/Conversions.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pragma solidity ^0.8.13;

import "forge-std/Test.sol";

import { PSM } from "src/PSM.sol";
import { PSM3 } from "src/PSM3.sol";

import { PSMTestBase } from "test/PSMTestBase.sol";

Expand All @@ -12,7 +12,7 @@ import { PSMTestBase } from "test/PSMTestBase.sol";
contract PSMConvertToAssetsTests is PSMTestBase {

function test_convertToAssets_invalidAsset() public {
vm.expectRevert("PSM/invalid-asset");
vm.expectRevert("PSM3/invalid-asset");
psm.convertToAssets(makeAddr("new-asset"), 100);
}

Expand Down Expand Up @@ -153,7 +153,7 @@ contract PSMConvertToSharesTests is PSMTestBase {
contract PSMConvertToSharesFailureTests is PSMTestBase {

function test_convertToShares_invalidAsset() public {
vm.expectRevert("PSM/invalid-asset");
vm.expectRevert("PSM3/invalid-asset");
psm.convertToShares(makeAddr("new-asset"), 100);
}

Expand Down
Loading

0 comments on commit ce0949f

Please sign in to comment.