diff --git a/docs/specs.md b/docs/specs.md index 59cc2820..4c7c7a66 100644 --- a/docs/specs.md +++ b/docs/specs.md @@ -72,8 +72,8 @@ |EVK-13|Protocol Config |The Protocol Config contract is the representative of the DAO's interests in the ecosystem. What vaults allow this contract to control is strictly limited.

Functions implemented that are called by the vaults:

`isValidInterestFee` - determines whether the value of the interest fee is allowed; vaults only invoke this if the governor attempts to set an interest fee outside of the range <`GUARANTEED_INTEREST_FEE_MIN`, `GUARANTEED_INTEREST_FEE_MAX`>

`protocolFeeConfig` - called when fees are converted; it returns the following the recipient address for the DAO's share of the fees and the fraction of the interest fees that should be sent to the DAO

[https://docs.euler.finance/euler-vault-kit-white-paper/#protocolconfig](https://docs.euler.finance/euler-vault-kit-white-paper/#protocolconfig) | |EVK-83|Sequence Registry |The Sequence Registry contract provides an interface for reserving sequence IDs. This contract maintains sequence counters associated with opaque designator strings. Each counter starts at 1. Anybody can reserve a sequence ID by calling `reserveSeqIdfunction`. The only guarantee provided is that no two reservations for the same designator will get the same ID. | |EVK-75|Synthetic Asset Vault |Synthetic asset vault is a special configuration of a vault which uses hooks to disable `mint`, `redeem`, `skim` and `repayWithShares` operations. The `deposit` operation is also disabled for all the callers except the underlying synth asset address itself, disallowing deposits from normal users.

Instead of a utilization based interest rate model, synthetic vaults use a reactive interest rate model which adjusts the interest rate based on the trading price of the synthetic asset. This mechanism, the peg stability module and the savings rate module aim to keep the synthetic asset pegged as tight as possible to the peg asset. The price feed used when borrowing from the synthetic vault is the asset which the synthetic asset is pegged to, creating a CDP based synthetic asset. | -|EVK-81|Synthetic Asset Vault `ERC20Collateral` |`ERC20Collateral` is an `ERC20`-compatible token with the EVC support which allows it to be used as collateral in other vault.

`ERC20Collateral` tokens comply with the following specification:

* Whenever the contract is called via the EVC (`msg.sender == EVC`), the current on behalf of account is fetched from the EVC and used as an authenticated caller address. This ensures liquidations can be processed via `EVC.controlCollateral` function
* The account status check is requested after every operation that can potentially negatively affect the account health (i.e. whenever the tokens are transferred out of the account). This ensures the account is never unhealthy after the operation | -|EVK-77|Synthetic Asset Vault `ESynth` |`ESynth` is an `ERC20`-compatible token with the EVC support which, thanks to relying on the EVC authentication and requesting the account status checks on token transfers and burns, allows it to be used as collateral in other vault. It is meant to be used as an underlying asset of the synthetic asset vault.

`ESynth` tokens comply with the following specification:

**ERC20Collateral**

`ESynth` inherits from `ERC20Collateral` making it compliant with the `ERC20Collateral` specification.

**Minting**

The owner of the contract can set a minting capacity by calling `setCapacity(address minter, uint128 capacity)` for any address which allows them to mint the synthetic asset up to the defined amount. Minters mint by calling `mint(address account, uint256 amount)`.

**Burning**

Any address can burn the synthetic from another address given they have the allowance to do so. The owner is exempt from this restriction when burning from the `ESynth` contract itself. When one burns from an address and they have a previously minted amount, the minted amount is reduced by the burned amount, freeing up their minting capacity. Burning can be done by calling `burn(address account, uint256 amount)`. Account status check is requested for the account from which the assets are burned.

**Allocating to the synthetic asset vault**

The owner can allocate assets held by the asset contract itself to a synthetic asset vault created specifically for this asset by calling `allocate(address vault, uint256 amount)`. This serves as a protocol deposit to the vault. Any allocation needs to be first minted by a minter or owner into the synthetic asset contract. The vault into which the assets are allocated must be integrated with the same EVC instance as the `ESynth` contract itself. On allocation, the vault is added to the addresses whose balances are ignored when calculating the `totalSupply`.

**Deallocating from the synthetic asset vault**

The owner can deallocate synthetic assets from the vault by calling `deallocate(address vault, uint256 amount)`. This serves as a protocol withdraw from the synthetic asset vault. Assets deallocated from the vault will be transferred into the synthetic asset contract itself and can in turn be burned by the owner.

**Total supply adjustments**

Since the protocol deposits into synthetic asset vaults are not backed by any collateral and are not in circulation, they are excluded from the `totalSupply` calculation. After calling `allocate()`, target vaults are automatically excluded. Additional addresses whose balances should be ignored can be managed by the owner by calling `addIgnoredForTotalSupply(address account)` and `removeIgnoredForTotalSupply(address account)`. | +|EVK-81|Synthetic Asset Vault `ERC20EVKCompatible` |`ERC20EVKCompatible` is an `ERC20`-compatible token with the EVC support.

Whenever the contract is called via the EVC (`msg.sender == EVC`), the current on behalf of account is fetched from the EVC and used as an authenticated caller address. This ensures the `ERC20EVKCompatible` is compatible with the EVC authentication system. | +|EVK-77|Synthetic Asset Vault `ESynth` |`ESynth` is an `ERC20`-compatible token with the EVC support. It is meant to be used as an underlying asset of the synthetic asset vault.

`ESynth` tokens comply with the following specification:

**ERC20EVCCompatible**

`ESynth` inherits from `ERC20EVCCompatible` making it compliant with the `ERC20EVCCompatible` specification.

**Minting**

The owner of the contract can set a minting capacity by calling `setCapacity(address minter, uint128 capacity)` for any address which allows them to mint the synthetic asset up to the defined amount. Minters mint by calling `mint(address account, uint256 amount)`.

**Burning**

Any address can burn the synthetic from another address given they have the allowance to do so. The owner is exempt from this restriction when burning from the `ESynth` contract itself. When one burns from an address and they have a previously minted amount, the minted amount is reduced by the burned amount, freeing up their minting capacity. Burning can be done by calling `burn(address account, uint256 amount)`.

**Allocating to the synthetic asset vault**

The owner can allocate assets held by the asset contract itself to a synthetic asset vault created specifically for this asset by calling `allocate(address vault, uint256 amount)`. This serves as a protocol deposit to the vault. Any allocation needs to be first minted by a minter or owner into the synthetic asset contract. The vault into which the assets are allocated must be integrated with the same EVC instance as the `ESynth` contract itself. On allocation, the vault is added to the addresses whose balances are ignored when calculating the `totalSupply`.

**Deallocating from the synthetic asset vault**

The owner can deallocate synthetic assets from the vault by calling `deallocate(address vault, uint256 amount)`. This serves as a protocol withdraw from the synthetic asset vault. Assets deallocated from the vault will be transferred into the synthetic asset contract itself and can in turn be burned by the owner.

**Total supply adjustments**

Since the protocol deposits into synthetic asset vaults are not backed by any collateral and are not in circulation, they are excluded from the `totalSupply` calculation. After calling `allocate()`, target vaults are automatically excluded. Additional addresses whose balances should be ignored can be managed by the owner by calling `addIgnoredForTotalSupply(address account)` and `removeIgnoredForTotalSupply(address account)`. | |EVK-79|Synthetic Asset Vault `EulerSavingsRate` |`EulerSavingsRate` is a `ERC4626`-compatible vault with the EVC support which allows users to deposit the underlying asset and receive interest in the form of the same underlying asset.

Account balances must be tracked internally in a donation attack resistant manner.

Anyone can transfer the underlying asset into the vault and call `gulp` which distributes those directly transferred assets to the shareholders over the `INTEREST_SMEAR` period. Accrued interest must adjust the exchange rate accordingly.

On `gulp`, any interest which has not been yet distributed is smeared for an additional `INTEREST_SMEAR` period. In theory, this means that interest could be smeared indefinitely by continuously calling `gulp`. In practice, it is expected that the interest will keep accruing, negating any negative side effects which may come from the smearing mechanism. | |EVK-78|Synthetic Asset Vault `IRMSynth` |Synthetic asset vaults use a different interest rate model than the standard vaults. The `IRMSynth` interest rate model is a simple reactive rate model which adjusts the interest rate up when it trades below the `targetQuote` and down when it trades above or at the `targetQuote`.

**Parameters**

* `targetQuote` price being targeted by the IRM
* `MAX_RATE` maximum rate charged
* `BASE_RATE` minimum and starting rate for the IRM
* `ADJUST_FACTOR` factor by which the previous rate is adjusted per `ADJUST_INTERVAL`
* `ADJUST_INTERVAL` time that needs to pass before the rate can be adjusted again

**Algorithm**

1. If the `ADJUST_INTERVAL` did not pass, the previous rate must be returned 2. If the oracle configured returns a zero quote, the previous rate must be returned 3. If the synthetic asset trades below the `targetQuote`, the rate must be raised by the factor of `ADJUST_FACTOR` 4. If the synthetic asset is trading at the `targetQuote` or below, the rate must be lowered by the factor of `ADJUST_FACTOR` 5. Minimum `BASE_RATE` must be enforced 6. Maximum `MAX_RATE` must be enforced 7. The updated rate the timestamp of the last update must be stored | |EVK-80|Synthetic Asset Vault `PegStabilityModule` |The `PegStabilityModule` is granted minting rights on the `ESynth` and must allow slippage-free conversion from and to the underlying asset as per configured `conversionPrice`. On deployment, the fee for swaps to synthetic asset and to underlying asset are defined. These fees must accrue to the `PegStabilityModule` contract and can not be withdrawn, serving as a permanent reserve to support the peg. Swapping to the synthetic asset is possible up to the minting cap granted for the `PegStabilityModule` in the `ESynth`. Swapping to the underlying asset is possible up to the amount of the underlying asset held by the `PegStabilityModule`. | diff --git a/src/Synths/ERC20Collateral.sol b/src/Synths/ERC20Collateral.sol deleted file mode 100644 index d7901961..00000000 --- a/src/Synths/ERC20Collateral.sol +++ /dev/null @@ -1,74 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later - -pragma solidity ^0.8.0; - -import {ERC20, Context} from "openzeppelin-contracts/token/ERC20/ERC20.sol"; -import {ERC20Permit} from "openzeppelin-contracts/token/ERC20/extensions/ERC20Permit.sol"; -import {ReentrancyGuard} from "openzeppelin-contracts/utils/ReentrancyGuard.sol"; -import {IEVC, EVCUtil} from "ethereum-vault-connector/utils/EVCUtil.sol"; - -/// @title ERC20Collateral -/// @custom:security-contact security@euler.xyz -/// @author Euler Labs (https://www.eulerlabs.com/) -/// @notice ERC20Collateral is an ERC20-compatible token with the EVC support which allows it to be used as collateral -/// in other vaults. -abstract contract ERC20Collateral is EVCUtil, ERC20Permit, ReentrancyGuard { - constructor(IEVC _evc_, string memory _name_, string memory _symbol_) - EVCUtil(address(_evc_)) - ERC20(_name_, _symbol_) - ERC20Permit(_name_) - {} - - /// @notice Transfers a certain amount of tokens to a recipient. - /// @dev Overriden to add reentrancy protection. - /// @param to The recipient of the transfer. - /// @param amount The amount shares to transfer. - /// @return A boolean indicating whether the transfer was successful. - function transfer(address to, uint256 amount) public virtual override nonReentrant returns (bool) { - return super.transfer(to, amount); - } - - /// @notice Transfers a certain amount of tokens from a sender to a recipient. - /// @dev Overriden to add reentrancy protection. - /// @param from The sender of the transfer. - /// @param to The recipient of the transfer. - /// @param amount The amount of shares to transfer. - /// @return A boolean indicating whether the transfer was successful. - function transferFrom(address from, address to, uint256 amount) - public - virtual - override - nonReentrant - returns (bool) - { - return super.transferFrom(from, to, amount); - } - - /// @notice Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from` - /// (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding - /// this function. - /// @dev Overriden to require account status checks on transfers from non-zero addresses. The account status check - /// must be required on any operation that reduces user's balance. Note that the user balance cannot be modified - // outside of this function as the account status check must always be requested after the balance is modified which - // is ensured by this function. If any user balance modifications are done outside of this function, the contract - // must be modified to request the account status check appropriately. - /// @param from The address from which tokens are transferred or burned. - /// @param to The address to which tokens are transferred or minted. - /// @param value The amount of tokens to transfer, mint, or burn. - function _update(address from, address to, uint256 value) internal virtual override { - super._update(from, to, value); - - if (from != address(0)) { - evc.requireAccountStatusCheck(from); - } - } - - /// @notice Retrieves the message sender in the context of the EVC. - /// @dev Overriden due to the conflict with the Context definition. - /// @dev This function returns the account on behalf of which the current operation is being performed, which is - /// either msg.sender or the account authenticated by the EVC. - /// @return The address of the message sender. - function _msgSender() internal view virtual override (EVCUtil, Context) returns (address) { - return EVCUtil._msgSender(); - } -} diff --git a/src/Synths/ERC20EVCCompatible.sol b/src/Synths/ERC20EVCCompatible.sol new file mode 100644 index 00000000..18e37062 --- /dev/null +++ b/src/Synths/ERC20EVCCompatible.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +pragma solidity ^0.8.0; + +import {ERC20, Context} from "openzeppelin-contracts/token/ERC20/ERC20.sol"; +import {ERC20Permit} from "openzeppelin-contracts/token/ERC20/extensions/ERC20Permit.sol"; +import {EVCUtil} from "ethereum-vault-connector/utils/EVCUtil.sol"; + +/// @title ERC20EVCCompatible +/// @custom:security-contact security@euler.xyz +/// @author Euler Labs (https://www.eulerlabs.com/) +/// @notice ERC20EVCCompatible is an ERC20-compatible token with the EVC support. +abstract contract ERC20EVCCompatible is EVCUtil, ERC20Permit { + constructor(address _evc_, string memory _name_, string memory _symbol_) + EVCUtil(_evc_) + ERC20(_name_, _symbol_) + ERC20Permit(_name_) + {} + + /// @notice Retrieves the message sender in the context of the EVC. + /// @dev Overriden due to the conflict with the Context definition. + /// @dev This function returns the account on behalf of which the current operation is being performed, which is + /// either msg.sender or the account authenticated by the EVC. + /// @return The address of the message sender. + function _msgSender() internal view virtual override (EVCUtil, Context) returns (address) { + return EVCUtil._msgSender(); + } +} diff --git a/src/Synths/ESynth.sol b/src/Synths/ESynth.sol index ad5b0731..16c019b1 100644 --- a/src/Synths/ESynth.sol +++ b/src/Synths/ESynth.sol @@ -4,17 +4,15 @@ pragma solidity ^0.8.0; import {Ownable} from "openzeppelin-contracts/access/Ownable.sol"; import {EnumerableSet} from "openzeppelin-contracts/utils/structs/EnumerableSet.sol"; -import {IEVC, EVCUtil} from "ethereum-vault-connector/utils/EVCUtil.sol"; -import {ERC20Collateral, ERC20, Context} from "./ERC20Collateral.sol"; +import {ERC20EVCCompatible, Context} from "./ERC20EVCCompatible.sol"; import {IEVault} from "../EVault/IEVault.sol"; /// @title ESynth /// @custom:security-contact security@euler.xyz /// @author Euler Labs (https://www.eulerlabs.com/) -/// @notice ESynth is an ERC20-compatible token with the EVC support which, thanks to relying on the EVC authentication -/// and requesting the account status checks on token transfers and burns, allows it to be used as collateral in other -/// vault. It is meant to be used as an underlying asset of the synthetic asset vault. -contract ESynth is ERC20Collateral, Ownable { +/// @notice ESynth is an ERC20-compatible token with the EVC support. It is meant to be used as an underlying asset of +/// the synthetic asset vault. +contract ESynth is ERC20EVCCompatible, Ownable { using EnumerableSet for EnumerableSet.AddressSet; struct MinterData { @@ -35,8 +33,8 @@ contract ESynth is ERC20Collateral, Ownable { error E_CapacityReached(); error E_NotEVCCompatible(); - constructor(IEVC evc_, string memory name_, string memory symbol_) - ERC20Collateral(evc_, name_, symbol_) + constructor(address evc_, string memory name_, string memory symbol_) + ERC20EVCCompatible(evc_, name_, symbol_) Ownable(msg.sender) { ignoredForTotalSupply.add(address(this)); @@ -54,7 +52,7 @@ contract ESynth is ERC20Collateral, Ownable { /// @notice Mints a certain amount of tokens to the account. /// @param account The account to mint the tokens to. /// @param amount The amount of tokens to mint. - function mint(address account, uint256 amount) external nonReentrant { + function mint(address account, uint256 amount) external { address sender = _msgSender(); MinterData memory minterCache = minters[sender]; @@ -80,7 +78,7 @@ contract ESynth is ERC20Collateral, Ownable { /// have an allowance for the sender. /// @param burnFrom The account to burn the tokens from. /// @param amount The amount of tokens to burn. - function burn(address burnFrom, uint256 amount) external nonReentrant { + function burn(address burnFrom, uint256 amount) external { address sender = _msgSender(); MinterData memory minterCache = minters[sender]; @@ -129,8 +127,8 @@ contract ESynth is ERC20Collateral, Ownable { /// @dev This function returns the account on behalf of which the current operation is being performed, which is /// either msg.sender or the account authenticated by the EVC. /// @return msgSender The address of the message sender. - function _msgSender() internal view virtual override (ERC20Collateral, Context) returns (address msgSender) { - return ERC20Collateral._msgSender(); + function _msgSender() internal view virtual override (ERC20EVCCompatible, Context) returns (address msgSender) { + return ERC20EVCCompatible._msgSender(); } // -------- TotalSupply Management -------- diff --git a/src/Synths/EulerSavingsRate.sol b/src/Synths/EulerSavingsRate.sol index bb1bb13c..da03ee51 100644 --- a/src/Synths/EulerSavingsRate.sol +++ b/src/Synths/EulerSavingsRate.sol @@ -6,7 +6,6 @@ import {Math} from "openzeppelin-contracts/utils/math/Math.sol"; import {IERC20} from "openzeppelin-contracts/token/ERC20/IERC20.sol"; import {ERC20} from "openzeppelin-contracts/token/ERC20/ERC20.sol"; import {ERC4626} from "openzeppelin-contracts/token/ERC20/extensions/ERC4626.sol"; -import {IEVC} from "ethereum-vault-connector/interfaces/IEthereumVaultConnector.sol"; import {EVCUtil} from "ethereum-vault-connector/utils/EVCUtil.sol"; /// @title EulerSavingsRate @@ -54,8 +53,8 @@ contract EulerSavingsRate is EVCUtil, ERC4626 { esrSlot.locked = UNLOCKED; } - constructor(IEVC _evc, address _asset, string memory _name, string memory _symbol) - EVCUtil(address(_evc)) + constructor(address _evc, address _asset, string memory _name, string memory _symbol) + EVCUtil(_evc) ERC4626(IERC20(_asset)) ERC20(_name, _symbol) { diff --git a/src/Synths/PegStabilityModule.sol b/src/Synths/PegStabilityModule.sol index 1e353085..f5ec5d3f 100644 --- a/src/Synths/PegStabilityModule.sol +++ b/src/Synths/PegStabilityModule.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import {EVCUtil, IEVC} from "ethereum-vault-connector/utils/EVCUtil.sol"; +import {EVCUtil} from "ethereum-vault-connector/utils/EVCUtil.sol"; import {IERC20} from "openzeppelin-contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol"; import {Math} from "openzeppelin-contracts/utils/math/Math.sol"; diff --git a/test/unit/esr/lib/ESRTest.sol b/test/unit/esr/lib/ESRTest.sol index 8ae9c6fa..74dd1a29 100644 --- a/test/unit/esr/lib/ESRTest.sol +++ b/test/unit/esr/lib/ESRTest.sol @@ -20,7 +20,7 @@ contract ESRTest is Test { function setUp() public virtual { asset = new MockToken(); evc = new EVC(); - esr = new EulerSavingsRate(evc, address(asset), NAME, SYMBOL); + esr = new EulerSavingsRate(address(evc), address(asset), NAME, SYMBOL); // Set a non zero timestamp vm.warp(420); diff --git a/test/unit/esvault/ESVaultTestBase.t.sol b/test/unit/esvault/ESVaultTestBase.t.sol index 32b935b2..6afeb762 100644 --- a/test/unit/esvault/ESVaultTestBase.t.sol +++ b/test/unit/esvault/ESVaultTestBase.t.sol @@ -15,9 +15,9 @@ contract ESVaultTestBase is EVaultTestBase { function setUp() public virtual override { super.setUp(); - assetTSTAsSynth = ESynth(address(new ESynth(evc, "Test Synth", "TST"))); + assetTSTAsSynth = ESynth(address(new ESynth(address(evc), "Test Synth", "TST"))); assetTST = TestERC20(address(assetTSTAsSynth)); - assetTST2AsSynth = ESynth(address(new ESynth(evc, "Test Synth 2", "TST2"))); + assetTST2AsSynth = ESynth(address(new ESynth(address(evc), "Test Synth 2", "TST2"))); assetTST2 = TestERC20(address(assetTST2AsSynth)); eTST = createSynthEVault(address(assetTST)); diff --git a/test/unit/esynth/ESynth.totalSupply.t.sol b/test/unit/esynth/ESynth.totalSupply.t.sol index 80ce217f..ac55e343 100644 --- a/test/unit/esynth/ESynth.totalSupply.t.sol +++ b/test/unit/esynth/ESynth.totalSupply.t.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.13; import {Test} from "forge-std/Test.sol"; -import {ESynth, IEVC, Ownable} from "../../../src/Synths/ESynth.sol"; +import {ESynth, Ownable} from "../../../src/Synths/ESynth.sol"; contract ESynthTotalSupplyTest is Test { ESynth synth; @@ -13,7 +13,7 @@ contract ESynthTotalSupplyTest is Test { function setUp() public { vm.startPrank(owner); - synth = new ESynth(IEVC(makeAddr("evc")), "TestSynth", "TS"); + synth = new ESynth(makeAddr("evc"), "TestSynth", "TS"); synth.setCapacity(owner, 1000000e18); vm.stopPrank(); } diff --git a/test/unit/esynth/ESynthGeneral.t.sol b/test/unit/esynth/ESynthGeneral.t.sol index d091efa5..793e52d9 100644 --- a/test/unit/esynth/ESynthGeneral.t.sol +++ b/test/unit/esynth/ESynthGeneral.t.sol @@ -137,7 +137,7 @@ contract ESynthGeneralTest is ESynthTest { vm.assume(id != 0); vm.prank(owner); - esynth = ESynth(address(new ESynth(evc, "Test Synth", "TST"))); + esynth = ESynth(address(new ESynth(address(evc), "Test Synth", "TST"))); // succeeds if called directly by an owner vm.prank(owner); diff --git a/test/unit/esynth/lib/ESynthTest.sol b/test/unit/esynth/lib/ESynthTest.sol index 37e87135..4c32d8f7 100644 --- a/test/unit/esynth/lib/ESynthTest.sol +++ b/test/unit/esynth/lib/ESynthTest.sol @@ -19,7 +19,7 @@ contract ESynthTest is EVaultTestBase { user1 = vm.addr(1001); user2 = vm.addr(1002); - esynth = ESynth(address(new ESynth(evc, "Test Synth", "TST"))); + esynth = ESynth(address(new ESynth(address(evc), "Test Synth", "TST"))); assetTST = TestERC20(address(esynth)); eTST = createSynthEVault(address(assetTST)); diff --git a/test/unit/pegStabilityModules/PSM.t.sol b/test/unit/pegStabilityModules/PSM.t.sol index e77e356f..aea6ab8d 100644 --- a/test/unit/pegStabilityModules/PSM.t.sol +++ b/test/unit/pegStabilityModules/PSM.t.sol @@ -5,7 +5,7 @@ pragma solidity ^0.8.0; import "forge-std/Test.sol"; import {PegStabilityModule, EVCUtil} from "../../../src/Synths/PegStabilityModule.sol"; -import {ESynth, IEVC} from "../../../src/Synths/ESynth.sol"; +import {ESynth} from "../../../src/Synths/ESynth.sol"; import {TestERC20} from "../../mocks/TestERC20.sol"; import {EthereumVaultConnector} from "ethereum-vault-connector/EthereumVaultConnector.sol"; import {EVCUtil} from "ethereum-vault-connector/utils/EVCUtil.sol"; @@ -22,7 +22,7 @@ contract PSMTest is Test { PegStabilityModule public psm; - IEVC public evc; + EthereumVaultConnector public evc; address public owner = makeAddr("owner"); address public wallet1 = makeAddr("wallet1"); @@ -34,7 +34,7 @@ contract PSMTest is Test { // Deploy synth vm.prank(owner); - synth = new ESynth(evc, "TestSynth", "TSYNTH"); + synth = new ESynth(address(evc), "TestSynth", "TSYNTH"); // Deploy underlying underlying = new TestERC20("TestUnderlying", "TUNDERLYING", 18, false); @@ -266,7 +266,7 @@ contract PSMTest is Test { assertEq(psm.quoteToUnderlyingGivenOut(underlyingAmount), synthAmount); } - function testRoundingPriceConversionsEqualDecimals() public { + function testRoundingPriceConversionsEqualDecimals() public view { assertEq(psm.quoteToSynthGivenIn(1), 0); assertEq(psm.quoteToSynthGivenOut(1), 2); assertEq(psm.quoteToUnderlyingGivenIn(1), 0);