Skip to content

Commit

Permalink
Merge pull request unitprotocol#26 from unitprotocol/auction-force-tr…
Browse files Browse the repository at this point in the history
…ansfer

Introduce ForceTransferAssetStore
  • Loading branch information
chainpioneer authored May 10, 2021
2 parents b1bdbcf + d1bc90d commit 8193f33
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 47 deletions.
44 changes: 44 additions & 0 deletions contracts/auction/ForceTransferAssetStore.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// SPDX-License-Identifier: bsl-1.1

/*
Copyright 2020 Unit Protocol: Artem Zakharov ([email protected]).
*/
pragma solidity 0.7.6;

import "../VaultParameters.sol";
import "../interfaces/IForceTransferAssetStore.sol";


/**
* @title ForceTransferAssetStore
**/
contract ForceTransferAssetStore is Auth, IForceTransferAssetStore {

/*
Mapping of assets that require a transfer of at least 1 unit of token
to update internal logic related to staking rewards in case of full liquidation
*/
mapping(address => bool) public override shouldForceTransfer;

event ForceTransferAssetAdded(address indexed asset);

constructor(address _vaultParameters, address[] memory initialAssets) Auth(_vaultParameters) {
for (uint i = 0; i < initialAssets.length; i++) {
require(!shouldForceTransfer[initialAssets[i]], "Unit Protocol: Already exists");
shouldForceTransfer[initialAssets[i]] = true;
emit ForceTransferAssetAdded(initialAssets[i]);
}
}

/**
* @notice Only manager is able to call this function
* @dev Mark asset as `shouldForceTransfer`
* @param asset The address of the asset
**/
function add(address asset) external override onlyManager {
require(!shouldForceTransfer[asset], "Unit Protocol: Already exists");
require(asset != address(0), "Unit Protocol: ZERO_ADDRESS");
shouldForceTransfer[asset] = true;
emit ForceTransferAssetAdded(asset);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,16 @@
*/
pragma solidity 0.7.6;

import './interfaces/IOracleRegistry.sol';
import './interfaces/IVault.sol';
import './interfaces/ICDPRegistry.sol';
import './interfaces/IVaultManagerParameters.sol';
import './interfaces/IVaultParameters.sol';
import './interfaces/ICurveProvider.sol';
import './interfaces/ICurveRegistry.sol';
import './interfaces/IWrappedToUnderlyingOracle.sol';

import './helpers/ReentrancyGuard.sol';
import './helpers/SafeMath.sol';
import '../interfaces/IOracleRegistry.sol';
import '../interfaces/IVault.sol';
import '../interfaces/ICDPRegistry.sol';
import '../interfaces/IVaultManagerParameters.sol';
import '../interfaces/IVaultParameters.sol';
import '../interfaces/IWrappedToUnderlyingOracle.sol';
import '../interfaces/IForceTransferAssetStore.sol';

import '../helpers/ReentrancyGuard.sol';
import '../helpers/SafeMath.sol';

/**
* @title LiquidationAuction02
Expand All @@ -25,11 +24,8 @@ contract LiquidationAuction02 is ReentrancyGuard {

IVault public immutable vault;
IVaultManagerParameters public immutable vaultManagerParameters;
IOracleRegistry public immutable oracleRegistry;
ICDPRegistry public immutable cdpRegistry;

// CurveProvider contract
ICurveProvider public immutable curveProvider;
IForceTransferAssetStore public immutable forceTransferAssetStore;

uint public constant DENOMINATOR_1E2 = 1e2;
uint public constant WRAPPED_TO_UNDERLYING_ORACLE_TYPE = 11;
Expand All @@ -46,23 +42,19 @@ contract LiquidationAuction02 is ReentrancyGuard {

/**
* @param _vaultManagerParameters The address of the contract with Vault manager parameters
* @param _oracleRegistry The address of the oracle registry
* @param _curveProvider The address of the Curve Provider. Mainnet: 0x0000000022D53366457F9d5E68Ec105046FC4383
* @param _cdpRegistry The address of the CDP registry
* @param _forceTransferAssetStore The address of the ForceTransferAssetStore
**/
constructor(address _vaultManagerParameters, address _oracleRegistry, address _curveProvider, address _cdpRegistry) {
constructor(address _vaultManagerParameters, address _cdpRegistry, address _forceTransferAssetStore) {
require(
_vaultManagerParameters != address(0) &&
_oracleRegistry != address(0) &&
_cdpRegistry != address(0) &&
_curveProvider != address(0),
_vaultManagerParameters != address(0) &&
_forceTransferAssetStore != (address(0)),
"Unit Protocol: INVALID_ARGS"
);
vaultManagerParameters = IVaultManagerParameters(_vaultManagerParameters);
vault = IVault(IVaultParameters(IVaultManagerParameters(_vaultManagerParameters).vaultParameters()).vault());
oracleRegistry = IOracleRegistry(_oracleRegistry);
curveProvider = ICurveProvider(_curveProvider);
cdpRegistry = ICDPRegistry(_cdpRegistry);
forceTransferAssetStore = IForceTransferAssetStore(_forceTransferAssetStore);
}

/**
Expand Down Expand Up @@ -91,8 +83,8 @@ contract LiquidationAuction02 is ReentrancyGuard {
collateralInPosition
);

// ensure that at least 1 wei of Curve LP is transferred to cdp owner
if (collateralToOwner == 0 && isCurveLP(asset)) {
// ensure that at least 1 unit of token is transferred to cdp owner
if (collateralToOwner == 0 && forceTransferAssetStore.shouldForceTransfer(asset)) {
collateralToOwner = 1;
collateralToLiquidator = collateralToLiquidator.sub(1);
}
Expand Down Expand Up @@ -160,12 +152,4 @@ contract LiquidationAuction02 is ReentrancyGuard {
collateralToBuyer = collateralInPosition;
}
}

function isCurveLP(address asset) public view returns (bool) {
address underlying = IWrappedToUnderlyingOracle(oracleRegistry.oracleByType(WRAPPED_TO_UNDERLYING_ORACLE_TYPE)).assetToUnderlying(asset);

if (underlying == address(0)) { return false; }

return ICurveRegistry(curveProvider.get_registry()).get_pool_from_lp_token(underlying) != address(0);
}
}
4 changes: 4 additions & 0 deletions contracts/interfaces/IForceTransferAssetStore.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface IForceTransferAssetStore {
function shouldForceTransfer ( address ) external view returns ( bool );
function add ( address asset ) external;
}
32 changes: 19 additions & 13 deletions test/helpers/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const UniswapV2Router02 = artifacts.require('UniswapV2Router02');
const CDPManager = artifacts.require('CDPManager01');
const LiquidationAuction = artifacts.require('LiquidationAuction02');
const CDPRegistry = artifacts.require('CDPRegistry');
const ForceTransferAssetStore = artifacts.require('ForceTransferAssetStore');
const CollateralRegistry = artifacts.require('CollateralRegistry');

const { ether } = require('openzeppelin-test-helpers');
Expand Down Expand Up @@ -175,16 +176,6 @@ module.exports = (context, mode) => {
context.weth.address,
context.vaultParameters.address
);

// curveLockedAssets is underlying tokens
// mainCollateral is LP is this case
context.curveLockedAsset1 = await DummyToken.new("USDC", "USDC", 6, 1000000e6);
context.curveLockedAsset2 = await DummyToken.new("USDT", "USDT", 6, 1000000e6);
context.curveLockedAsset3 = await DummyToken.new("DAI", "DAI", 18, ether('1000000'));
context.curvePool = await CurvePool.new()
await context.curvePool.setPool(ether('1'), [context.curveLockedAsset1.address, context.curveLockedAsset2.address, context.curveLockedAsset3.address])
context.curveRegistry = await CurveRegistryMock.new(context.mainCollateral.address, context.curvePool.address, 3)
context.curveProvider = await CurveProviderMock.new(context.curveRegistry.address)
context.oracleRegistry = await OracleRegistry.new(context.vaultParameters.address, context.weth.address)

await context.oracleRegistry.setOracle(5, context.chainlinkOracleMainAsset.address);
Expand All @@ -195,6 +186,8 @@ module.exports = (context, mode) => {
context.oracleRegistry.address,
)

context.forceTransferAssetStore = await ForceTransferAssetStore.new(context.vaultParameters.address, []);

if (isLP) {
context.oraclePoolToken = await OraclePoolToken.new(context.oracleRegistry.address);
}
Expand Down Expand Up @@ -275,6 +268,18 @@ module.exports = (context, mode) => {


} else if (curveLP) {

// curveLockedAssets is underlying tokens
// `mainCollateral` is LP is this case
// `wrappedAsset` is the collateral
context.curveLockedAsset1 = await DummyToken.new("USDC", "USDC", 6, 1000000e6);
context.curveLockedAsset2 = await DummyToken.new("USDT", "USDT", 6, 1000000e6);
context.curveLockedAsset3 = await DummyToken.new("DAI", "DAI", 18, ether('1000000'));
context.curvePool = await CurvePool.new()
await context.curvePool.setPool(ether('1'), [context.curveLockedAsset1.address, context.curveLockedAsset2.address, context.curveLockedAsset3.address])
context.curveRegistry = await CurveRegistryMock.new(context.mainCollateral.address, context.curvePool.address, 3)
context.curveProvider = await CurveProviderMock.new(context.curveRegistry.address)

context.curveLockedAssetUsdPrice = await ChainlinkAggregator.new(1e8.toString(), 8);
await context.chainlinkOracleMainAsset.setAggregators(
[context.curveLockedAsset1.address, context.curveLockedAsset2.address, context.curveLockedAsset3.address],
Expand All @@ -296,6 +301,8 @@ module.exports = (context, mode) => {

context.wrappedAsset = await DummyToken.new("Wrapper Curve LP", "WCLP", 18, ether('100000000000'))

await context.forceTransferAssetStore.add(context.wrappedAsset.address);

await context.wrappedToUnderlyingOracle.setUnderlying(context.wrappedAsset.address, context.mainCollateral.address)

context.oracleRegistry.setOracle(mainAssetOracleType, context.wrappedToUnderlyingOracle.address)
Expand All @@ -318,9 +325,8 @@ module.exports = (context, mode) => {

context.liquidationAuction = await LiquidationAuction.new(
context.vaultManagerParameters.address,
context.oracleRegistry.address,
context.curveProvider.address,
context.cdpRegistry.address
context.cdpRegistry.address,
context.forceTransferAssetStore.address
);

if (keydonix) {
Expand Down

0 comments on commit 8193f33

Please sign in to comment.