@0x/dev-utils: Fix dydx min CR not being +1.

`@0x/dev-utils`: Fix withdraw rate vs order conversion rate check .
This commit is contained in:
Lawrence Forman 2020-02-05 12:14:57 -05:00
parent 865a253eb5
commit 162b6f1a74
2 changed files with 37 additions and 39 deletions

View File

@ -42,8 +42,7 @@ library LibDydxBalance {
address makerAddress; address makerAddress;
address makerTokenAddress; address makerTokenAddress;
address takerTokenAddress; address takerTokenAddress;
uint256 makerAssetAmount; int256 orderTakerToMakerRate;
uint256 takerAssetAmount;
uint256[] accounts; uint256[] accounts;
IDydxBridge.BridgeAction[] actions; IDydxBridge.BridgeAction[] actions;
} }
@ -66,9 +65,10 @@ library LibDydxBalance {
if (!_areActionsWellFormed(info)) { if (!_areActionsWellFormed(info)) {
return 0; return 0;
} }
// If the rate we withdraw maker tokens is < 1, the asset proxy will // If the rate we withdraw maker tokens is less than the order conversion
// throw because we will always transfer less maker tokens than asked. // rate , the asset proxy will throw because we will always transfer
if (_getMakerTokenWithdrawRate(info) < D18.one()) { // less maker tokens than asked.
if (_getMakerTokenWithdrawRate(info) < info.orderTakerToMakerRate) {
return 0; return 0;
} }
// The maker balance is the smaller of: // The maker balance is the smaller of:
@ -154,11 +154,7 @@ library LibDydxBalance {
returns (uint256 depositableMakerAmount) returns (uint256 depositableMakerAmount)
{ {
depositableMakerAmount = uint256(-1); depositableMakerAmount = uint256(-1);
// The conversion rate from maker -> taker. int256 orderMakerToTakerRate = D18.div(D18.one(), info.orderTakerToMakerRate);
int256 makerToTakerRate = D18.div(
info.takerAssetAmount,
info.makerAssetAmount
);
// Take the minimum maker amount from all deposits. // Take the minimum maker amount from all deposits.
for (uint256 i = 0; i < info.actions.length; ++i) { for (uint256 i = 0; i < info.actions.length; ++i) {
IDydxBridge.BridgeAction memory action = info.actions[i]; IDydxBridge.BridgeAction memory action = info.actions[i];
@ -172,7 +168,7 @@ library LibDydxBalance {
// token. // token.
address depositToken = info.dydx.getMarketTokenAddress(action.marketId); address depositToken = info.dydx.getMarketTokenAddress(action.marketId);
if (info.takerTokenAddress != address(0) && depositToken == info.takerTokenAddress) { if (info.takerTokenAddress != address(0) && depositToken == info.takerTokenAddress) {
depositRate = D18.sub(depositRate, makerToTakerRate); depositRate = D18.sub(depositRate, orderMakerToTakerRate);
} }
// If the deposit rate is > 0, we are limited by the transferrable // If the deposit rate is > 0, we are limited by the transferrable
// token balance of the maker. // token balance of the maker.
@ -241,7 +237,7 @@ library LibDydxBalance {
_getActionRate(withdraw) _getActionRate(withdraw)
); );
// If the deposit to withdraw ratio is >= the minimum collateralization // If the deposit to withdraw ratio is >= the minimum collateralization
// rate, then we will never become insolvent at these prices. // ratio, then we will never become insolvent at these prices.
if (D18.div(dd, db) >= minCr) { if (D18.div(dd, db) >= minCr) {
continue; continue;
} }
@ -279,8 +275,7 @@ library LibDydxBalance {
(, info.takerTokenAddress) = (, info.takerTokenAddress) =
LibAssetData.decodeERC20AssetData(order.takerAssetData); LibAssetData.decodeERC20AssetData(order.takerAssetData);
} }
info.makerAssetAmount = order.makerAssetAmount; info.orderTakerToMakerRate = D18.div(order.makerAssetAmount, order.takerAssetAmount);
info.takerAssetAmount = order.takerAssetAmount;
(IDydxBridge.BridgeData memory bridgeData) = (IDydxBridge.BridgeData memory bridgeData) =
abi.decode(rawBridgeData, (IDydxBridge.BridgeData)); abi.decode(rawBridgeData, (IDydxBridge.BridgeData));
info.accounts = bridgeData.accountNumbers; info.accounts = bridgeData.accountNumbers;
@ -311,7 +306,7 @@ library LibDydxBalance {
returns (int256 ratio) returns (int256 ratio)
{ {
IDydx.RiskParams memory riskParams = dydx.getRiskParams(); IDydx.RiskParams memory riskParams = dydx.getRiskParams();
return D18.toSigned(riskParams.marginRatio.value); return D18.add(D18.one(), D18.toSigned(riskParams.marginRatio.value));
} }
/// @dev Get the quote (USD) value of a rate within a market. /// @dev Get the quote (USD) value of a rate within a market.

View File

@ -53,7 +53,7 @@ blockchainTests('LibDydxBalance', env => {
const INSOLVENT_ACCOUNT_IDX = 2; const INSOLVENT_ACCOUNT_IDX = 2;
const ZERO_BALANCE_ACCOUNT_IDX = 3; const ZERO_BALANCE_ACCOUNT_IDX = 3;
const DYDX_CONFIG: TestDydxConfig = { const DYDX_CONFIG: TestDydxConfig = {
marginRatio: fromTokenUnitAmount(MARGIN_RATIO, PRICE_DECIMALS), marginRatio: fromTokenUnitAmount(MARGIN_RATIO - 1, PRICE_DECIMALS),
operators: [{ owner: ACCOUNT_OWNER, operator: BRIDGE_ADDRESS }], operators: [{ owner: ACCOUNT_OWNER, operator: BRIDGE_ADDRESS }],
accounts: [ accounts: [
{ {
@ -148,8 +148,7 @@ blockchainTests('LibDydxBalance', env => {
makerAddress: string; makerAddress: string;
makerTokenAddress: string; makerTokenAddress: string;
takerTokenAddress: string; takerTokenAddress: string;
makerAssetAmount: BigNumber; orderTakerToMakerRate: BigNumber;
takerAssetAmount: BigNumber;
accounts: BigNumber[]; accounts: BigNumber[];
actions: DydxBridgeAction[]; actions: DydxBridgeAction[];
} }
@ -161,8 +160,9 @@ blockchainTests('LibDydxBalance', env => {
makerAddress: ACCOUNT_OWNER, makerAddress: ACCOUNT_OWNER,
makerTokenAddress: DYDX_CONFIG.markets[1].token, makerTokenAddress: DYDX_CONFIG.markets[1].token,
takerTokenAddress: DYDX_CONFIG.markets[0].token, takerTokenAddress: DYDX_CONFIG.markets[0].token,
makerAssetAmount: fromTokenUnitAmount(10, MAKER_DECIMALS), orderTakerToMakerRate: fromTokenUnitAmount(
takerAssetAmount: fromTokenUnitAmount(5, TAKER_DECIMALS), fromTokenUnitAmount(5, MAKER_DECIMALS).div(fromTokenUnitAmount(10, TAKER_DECIMALS)),
),
accounts: [DYDX_CONFIG.accounts[SOLVENT_ACCOUNT_IDX].accountId], accounts: [DYDX_CONFIG.accounts[SOLVENT_ACCOUNT_IDX].accountId],
actions: [], actions: [],
...fields, ...fields,
@ -537,8 +537,9 @@ blockchainTests('LibDydxBalance', env => {
blockchainTests.resets('_getDepositableMakerAmount()', () => { blockchainTests.resets('_getDepositableMakerAmount()', () => {
it('returns infinite if no deposit action', async () => { it('returns infinite if no deposit action', async () => {
const checkInfo = createBalanceCheckInfo({ const checkInfo = createBalanceCheckInfo({
takerAssetAmount: fromTokenUnitAmount(10, TAKER_DECIMALS), orderTakerToMakerRate: fromTokenUnitAmount(
makerAssetAmount: fromTokenUnitAmount(100, MAKER_DECIMALS), fromTokenUnitAmount(100, MAKER_DECIMALS).div(fromTokenUnitAmount(10, TAKER_DECIMALS)),
),
actions: [], actions: [],
}); });
const makerAssetFillAmount = await testContract.getDepositableMakerAmount(checkInfo).callAsync(); const makerAssetFillAmount = await testContract.getDepositableMakerAmount(checkInfo).callAsync();
@ -547,8 +548,9 @@ blockchainTests('LibDydxBalance', env => {
it('returns infinite if deposit rate is zero', async () => { it('returns infinite if deposit rate is zero', async () => {
const checkInfo = createBalanceCheckInfo({ const checkInfo = createBalanceCheckInfo({
takerAssetAmount: fromTokenUnitAmount(10, TAKER_DECIMALS), orderTakerToMakerRate: fromTokenUnitAmount(
makerAssetAmount: fromTokenUnitAmount(100, MAKER_DECIMALS), fromTokenUnitAmount(100, MAKER_DECIMALS).div(fromTokenUnitAmount(10, TAKER_DECIMALS)),
),
actions: [ actions: [
{ {
actionType: DydxBridgeActionType.Deposit, actionType: DydxBridgeActionType.Deposit,
@ -565,8 +567,9 @@ blockchainTests('LibDydxBalance', env => {
it('returns infinite if taker tokens cover the deposit rate', async () => { it('returns infinite if taker tokens cover the deposit rate', async () => {
const checkInfo = createBalanceCheckInfo({ const checkInfo = createBalanceCheckInfo({
takerAssetAmount: fromTokenUnitAmount(10, TAKER_DECIMALS), orderTakerToMakerRate: fromTokenUnitAmount(
makerAssetAmount: fromTokenUnitAmount(100, MAKER_DECIMALS), fromTokenUnitAmount(100, MAKER_DECIMALS).div(fromTokenUnitAmount(10, TAKER_DECIMALS)),
),
actions: [ actions: [
{ {
actionType: DydxBridgeActionType.Deposit, actionType: DydxBridgeActionType.Deposit,
@ -586,8 +589,9 @@ blockchainTests('LibDydxBalance', env => {
const exchangeRate = 0.1; const exchangeRate = 0.1;
const depositRate = Math.random() + exchangeRate; const depositRate = Math.random() + exchangeRate;
const checkInfo = createBalanceCheckInfo({ const checkInfo = createBalanceCheckInfo({
takerAssetAmount: fromTokenUnitAmount(exchangeRate, TAKER_DECIMALS), orderTakerToMakerRate: fromTokenUnitAmount(
makerAssetAmount: fromTokenUnitAmount(1, MAKER_DECIMALS), fromTokenUnitAmount(1, MAKER_DECIMALS).div(fromTokenUnitAmount(exchangeRate, TAKER_DECIMALS)),
),
actions: [ actions: [
{ {
actionType: DydxBridgeActionType.Deposit, actionType: DydxBridgeActionType.Deposit,
@ -619,8 +623,7 @@ blockchainTests('LibDydxBalance', env => {
const checkInfo = createBalanceCheckInfo({ const checkInfo = createBalanceCheckInfo({
// The `takerTokenAddress` will be zero if the asset is not an ERC20. // The `takerTokenAddress` will be zero if the asset is not an ERC20.
takerTokenAddress: constants.NULL_ADDRESS, takerTokenAddress: constants.NULL_ADDRESS,
takerAssetAmount: new BigNumber(1), orderTakerToMakerRate: fromTokenUnitAmount(fromTokenUnitAmount(100, MAKER_DECIMALS)),
makerAssetAmount: fromTokenUnitAmount(100, MAKER_DECIMALS),
actions: [ actions: [
{ {
actionType: DydxBridgeActionType.Deposit, actionType: DydxBridgeActionType.Deposit,
@ -652,8 +655,9 @@ blockchainTests('LibDydxBalance', env => {
takerTokenAddress: randomAddress(), takerTokenAddress: randomAddress(),
// These amounts should be effectively ignored in the final computation // These amounts should be effectively ignored in the final computation
// because the token being deposited is not the taker token. // because the token being deposited is not the taker token.
takerAssetAmount: fromTokenUnitAmount(10, TAKER_DECIMALS), orderTakerToMakerRate: fromTokenUnitAmount(
makerAssetAmount: fromTokenUnitAmount(100, MAKER_DECIMALS), fromTokenUnitAmount(100, MAKER_DECIMALS).div(fromTokenUnitAmount(10, TAKER_DECIMALS)),
),
actions: [ actions: [
{ {
actionType: DydxBridgeActionType.Deposit, actionType: DydxBridgeActionType.Deposit,
@ -672,8 +676,9 @@ blockchainTests('LibDydxBalance', env => {
// The taker tokens getting exchanged in will only partially cover the deposit. // The taker tokens getting exchanged in will only partially cover the deposit.
const exchangeRate = 0.1; const exchangeRate = 0.1;
const checkInfo = createBalanceCheckInfo({ const checkInfo = createBalanceCheckInfo({
takerAssetAmount: fromTokenUnitAmount(exchangeRate, TAKER_DECIMALS), orderTakerToMakerRate: fromTokenUnitAmount(
makerAssetAmount: fromTokenUnitAmount(1, MAKER_DECIMALS), fromTokenUnitAmount(1, MAKER_DECIMALS).div(fromTokenUnitAmount(exchangeRate, TAKER_DECIMALS)),
),
actions: [ actions: [
// Technically, deposits of the same token are not allowed, but the // Technically, deposits of the same token are not allowed, but the
// check isn't done in this function so we'll do this to simulate // check isn't done in this function so we'll do this to simulate
@ -728,8 +733,7 @@ blockchainTests('LibDydxBalance', env => {
const exchangeRate = 0.1; const exchangeRate = 0.1;
const depositRate = Math.random() + exchangeRate; const depositRate = Math.random() + exchangeRate;
const checkInfo = createBalanceCheckInfo({ const checkInfo = createBalanceCheckInfo({
takerAssetAmount: fromTokenUnitAmount(exchangeRate, TAKER_DECIMALS), orderTakerToMakerRate: fromTokenUnitAmount(fromTokenUnitAmount(1 / exchangeRate, MAKER_DECIMALS)),
makerAssetAmount: fromTokenUnitAmount(1, MAKER_DECIMALS),
actions: [ actions: [
{ {
actionType: DydxBridgeActionType.Deposit, actionType: DydxBridgeActionType.Deposit,
@ -756,8 +760,7 @@ blockchainTests('LibDydxBalance', env => {
const exchangeRate = 0.1; const exchangeRate = 0.1;
const depositRate = Math.random() + exchangeRate; const depositRate = Math.random() + exchangeRate;
const checkInfo = createBalanceCheckInfo({ const checkInfo = createBalanceCheckInfo({
takerAssetAmount: fromTokenUnitAmount(exchangeRate, TAKER_DECIMALS), orderTakerToMakerRate: fromTokenUnitAmount(fromTokenUnitAmount(1 / exchangeRate, MAKER_DECIMALS)),
makerAssetAmount: fromTokenUnitAmount(1, MAKER_DECIMALS),
actions: [ actions: [
{ {
actionType: DydxBridgeActionType.Deposit, actionType: DydxBridgeActionType.Deposit,
@ -1085,7 +1088,7 @@ blockchainTests('LibDydxBalance', env => {
senderAddress: constants.NULL_ADDRESS, senderAddress: constants.NULL_ADDRESS,
makerFee: getRandomInteger(1, constants.MAX_UINT256), makerFee: getRandomInteger(1, constants.MAX_UINT256),
takerFee: getRandomInteger(1, constants.MAX_UINT256), takerFee: getRandomInteger(1, constants.MAX_UINT256),
makerAssetAmount: fromTokenUnitAmount(100, TAKER_DECIMALS), makerAssetAmount: fromTokenUnitAmount(100, MAKER_DECIMALS),
takerAssetAmount: fromTokenUnitAmount(10, TAKER_DECIMALS), takerAssetAmount: fromTokenUnitAmount(10, TAKER_DECIMALS),
makerAssetData: createBridgeAssetData(makerTokenAddress, BRIDGE_ADDRESS), makerAssetData: createBridgeAssetData(makerTokenAddress, BRIDGE_ADDRESS),
takerAssetData: createERC20AssetData(takerTokenAddress), takerAssetData: createERC20AssetData(takerTokenAddress),