From f19f4310f4a15eb0d7e9225ca1a49b9e4caf1183 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Tue, 3 Dec 2019 15:25:07 -0800 Subject: [PATCH] Updating bridge to work w/o MultiAssetProxy --- .../contracts/src/bridges/DydxBridge.sol | 83 +++++++++++-------- .../contracts/src/interfaces/IDydxBridge.sol | 9 +- contracts/asset-proxy/package.json | 4 + contracts/asset-proxy/test/artifacts.ts | 8 ++ contracts/asset-proxy/test/wrappers.ts | 4 + contracts/asset-proxy/tsconfig.json | 4 + 6 files changed, 74 insertions(+), 38 deletions(-) diff --git a/contracts/asset-proxy/contracts/src/bridges/DydxBridge.sol b/contracts/asset-proxy/contracts/src/bridges/DydxBridge.sol index 44186ea339..01a243678a 100644 --- a/contracts/asset-proxy/contracts/src/bridges/DydxBridge.sol +++ b/contracts/asset-proxy/contracts/src/bridges/DydxBridge.sol @@ -21,6 +21,7 @@ pragma experimental ABIEncoderV2; import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; import "@0x/contracts-utils/contracts/src/Authorizable.sol"; +import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; import "../interfaces/IERC20Bridge.sol"; import "../interfaces/IDydxBridge.sol"; import "../interfaces/IDydx.sol"; @@ -33,15 +34,15 @@ contract DydxBridge is Authorizable { + using LibSafeMath for uint256; + /// @dev Callback for `IERC20Bridge`. Deposits or withdraws tokens from a dydx account. /// Notes: /// 1. This bridge must be set as an operator of the dydx account that is being operated on. /// 2. This function may only be called in the context of the 0x Exchange executing an order /// (ERC20Bridge is authorized). - /// 3. The order must be signed by the owner or an operator of the dydx account. - /// This signature validated by the 0x Exchange. - /// 4. The `from` address must be the maker (and hence is the owner or operator of the dydx account). - /// This is asserted during execution of this function. + /// 3. The `from` address must be the maker and owner of the dydx account. + /// This signature is validated by the 0x Exchange. /// @param from The sender of the tokens. /// @param to The recipient of the tokens. /// @param amount Minimum amount of `toTokenAddress` tokens to buy. @@ -58,48 +59,62 @@ contract DydxBridge is onlyAuthorized returns (bytes4 success) { + // Ensure that only the `ERC20BridgeProxy` can call this function. + require( + msg.sender == _getERC20BridgeProxyAddress(), + "DydxBridge/ONLY_CALLABLE_BY_ERC20_BRIDGE_PROXY" + ); + // Decode bridge data. (BridgeData memory bridgeData) = abi.decode(encodedBridgeData, (BridgeData)); // Cache dydx contract. IDydx dydx = IDydx(_getDydxAddress()); - // Assert that `from` is the owner or an operator of the dydx account. - require( - from == bridgeData.accountOwner || dydx.getIsLocalOperator(bridgeData.accountOwner, from), - "INVALID_DYDX_OWNER_OR_OPERATOR" - ); - // Construct dydx account info. - IDydx.AccountInfo[] memory accounts = new IDydx.AccountInfo[](1); - accounts[0] = IDydx.AccountInfo({ - owner: bridgeData.accountOwner, + IDydx.AccountInfo[] memory dydxAccounts = new IDydx.AccountInfo[](1); + dydxAccounts[0] = IDydx.AccountInfo({ + owner: from, number: bridgeData.accountNumber }); // Create dydx action. - IDydx.ActionArgs[] memory actions = new IDydx.ActionArgs[](1); - if (bridgeData.action == BridgeAction.Deposit) { - actions[0] = _createDepositAction( - from, - amount, - bridgeData - ); - } else if (bridgeData.action == BridgeAction.Withdraw) { - actions[0] = _createWithdrawAction( - to, - amount, - bridgeData - ); - } else { - // If all values in the `Action` enum are handled then this - // revert is unreachable: Solidity will revert when casting - // from `uint8` to `Action`. - revert("UNRECOGNIZED_ACTION"); + IDydx.ActionArgs[] memory dydxActions = new IDydx.ActionArgs[](bridgeData.actions.length); + for (uint256 i = 0; i < dydxActions.length; ++i) { + BridgeAction bridgeAction = bridgeData.actions[i]; + if (bridgeAction == BridgeAction.Deposit) { + // Compute the amount to deposit. The `amount` parameter is the amount to be withdrawn. + // It is computed by the Exchange as: + // amount = floor[(takerFillAmount * makerAssetAmount) / takerAssetAmount] + // The amount to deposit is equal to to `takerFillAmount`, which we compute below as: + // takerFillAmount ~= floor[(amount * takerAssetAmount) / makerAssetAmount] + // = floor[(amount * conversionRateNumerator) / conversionRateDenominator] + // Note that we can only approximate the original value of `takerFillAmount`. If we were to use + // `ceil` then we would risk overestimating the value. + uint256 amountToDeposit = amount + .mul(bridgeData.conversionRateNumerator) + .div(bridgeData.conversionRateDenominator); + dydxActions[i] = _createDepositAction( + from, + amount, + bridgeData + ); + } else if (bridgeAction == BridgeAction.Withdraw) { + dydxActions[i] = _createWithdrawAction( + to, + amount, + bridgeData + ); + } else { + // If all values in the `Action` enum are handled then this + // revert is unreachable: Solidity will revert when casting + // from `uint8` to `Action`. + revert("DydxBridge/UNRECOGNIZED_BRIDGE_ACTION"); + } } // Run operation. This will revert on failure. - dydx.operate(accounts, actions); + dydx.operate(dydxAccounts, dydxActions); return BRIDGE_SUCCESS; } @@ -117,7 +132,7 @@ contract DydxBridge is returns (IDydx.ActionArgs memory) { // Create dydx amount. - IDydx.AssetAmount memory amountToDeposit = IDydx.AssetAmount({ + IDydx.AssetAmount memory dydxAmount = IDydx.AssetAmount({ sign: true, // true if positive. denomination: IDydx.AssetDenomination.Wei, // Wei => actual token amount held in account. ref: IDydx.AssetReference.Target, // Target => an absolute amount. @@ -127,7 +142,7 @@ contract DydxBridge is // Create dydx deposit action. IDydx.ActionArgs memory depositAction = IDydx.ActionArgs({ actionType: IDydx.ActionType.Deposit, // deposit tokens. - amount: amountToDeposit, // amount to deposit. + amount: dydxAmount, // amount to deposit. accountId: 0, // index in the `accounts` when calling `operate`. primaryMarketId: bridgeData.marketId, // indicates which token to deposit. otherAddress: depositFrom, // deposit from this address. diff --git a/contracts/asset-proxy/contracts/src/interfaces/IDydxBridge.sol b/contracts/asset-proxy/contracts/src/interfaces/IDydxBridge.sol index e3f604b51e..c6ce7070b3 100644 --- a/contracts/asset-proxy/contracts/src/interfaces/IDydxBridge.sol +++ b/contracts/asset-proxy/contracts/src/interfaces/IDydxBridge.sol @@ -27,9 +27,10 @@ interface IDydxBridge { } struct BridgeData { - BridgeAction action; // Action to run on dydx account. - address accountOwner; // The owner of the dydx account. - uint256 accountNumber; // Account number used to identify the owner's specific account. - uint256 marketId; // Market to operate on. + BridgeAction[] actions; // Action to run on dydx account. + uint256 accountNumber; // Account number used to identify the owner's specific account. + uint256 marketId; // Market to operate on. + uint256 conversionRateNumerator; // + uint256 conversionRateDenominator; // } } \ No newline at end of file diff --git a/contracts/asset-proxy/package.json b/contracts/asset-proxy/package.json index 251bd3ddda..fc1547b6ab 100644 --- a/contracts/asset-proxy/package.json +++ b/contracts/asset-proxy/package.json @@ -43,8 +43,12 @@ "abis": "./test/generated-artifacts/@(ChaiBridge|DyDxBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IChai|IDyDx|IERC20Bridge|IEth2Dai|IKyberNetworkProxy|IUniswapExchange|IUniswapExchangeFactory|KyberBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MultiAssetProxy|Ownable|StaticCallProxy|TestChaiBridge|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|UniswapBridge).json", ======= "publicInterfaceContracts": "ERC1155Proxy,ERC20Proxy,ERC721Proxy,MultiAssetProxy,StaticCallProxy,ERC20BridgeProxy,Eth2DaiBridge,IAssetData,IAssetProxy,UniswapBridge,KyberBridge,TestStaticCallTarget", +<<<<<<< HEAD "abis": "./test/generated-artifacts/@(DydxBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IDydx|IERC20Bridge|IEth2Dai|IKyberNetworkProxy|IUniswapExchange|IUniswapExchangeFactory|KyberBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MultiAssetProxy|Ownable|StaticCallProxy|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|UniswapBridge).json", >>>>>>> ee82a0f67... Consistent capitalization for "dydx"` +======= + "abis": "./test/generated-artifacts/@(DydxBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IDydx|IDydxBridge|IERC20Bridge|IEth2Dai|IKyberNetworkProxy|IUniswapExchange|IUniswapExchangeFactory|KyberBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MultiAssetProxy|Ownable|StaticCallProxy|TestDydxBridge|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|UniswapBridge).json", +>>>>>>> 5e2de489d... Updating bridge to work w/o MAP "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually." }, "repository": { diff --git a/contracts/asset-proxy/test/artifacts.ts b/contracts/asset-proxy/test/artifacts.ts index b9c26f15a5..decf8261f5 100644 --- a/contracts/asset-proxy/test/artifacts.ts +++ b/contracts/asset-proxy/test/artifacts.ts @@ -25,7 +25,11 @@ import * as IChai from '../test/generated-artifacts/IChai.json'; import * as IDyDx from '../test/generated-artifacts/IDyDx.json'; ======= import * as IDydx from '../test/generated-artifacts/IDydx.json'; +<<<<<<< HEAD >>>>>>> ee82a0f67... Consistent capitalization for "dydx"` +======= +import * as IDydxBridge from '../test/generated-artifacts/IDydxBridge.json'; +>>>>>>> 5e2de489d... Updating bridge to work w/o MAP import * as IERC20Bridge from '../test/generated-artifacts/IERC20Bridge.json'; import * as IEth2Dai from '../test/generated-artifacts/IEth2Dai.json'; import * as IKyberNetworkProxy from '../test/generated-artifacts/IKyberNetworkProxy.json'; @@ -72,7 +76,11 @@ export const artifacts = { IDyDx: IDyDx as ContractArtifact, ======= IDydx: IDydx as ContractArtifact, +<<<<<<< HEAD >>>>>>> ee82a0f67... Consistent capitalization for "dydx"` +======= + IDydxBridge: IDydxBridge as ContractArtifact, +>>>>>>> 5e2de489d... Updating bridge to work w/o MAP IERC20Bridge: IERC20Bridge as ContractArtifact, IEth2Dai: IEth2Dai as ContractArtifact, IKyberNetworkProxy: IKyberNetworkProxy as ContractArtifact, diff --git a/contracts/asset-proxy/test/wrappers.ts b/contracts/asset-proxy/test/wrappers.ts index b226791757..4e74845132 100644 --- a/contracts/asset-proxy/test/wrappers.ts +++ b/contracts/asset-proxy/test/wrappers.ts @@ -23,7 +23,11 @@ export * from '../test/generated-wrappers/i_chai'; export * from '../test/generated-wrappers/i_dy_dx'; ======= export * from '../test/generated-wrappers/i_dydx'; +<<<<<<< HEAD >>>>>>> ee82a0f67... Consistent capitalization for "dydx"` +======= +export * from '../test/generated-wrappers/i_dydx_bridge'; +>>>>>>> 5e2de489d... Updating bridge to work w/o MAP export * from '../test/generated-wrappers/i_erc20_bridge'; export * from '../test/generated-wrappers/i_eth2_dai'; export * from '../test/generated-wrappers/i_kyber_network_proxy'; diff --git a/contracts/asset-proxy/tsconfig.json b/contracts/asset-proxy/tsconfig.json index 431d299ed4..77ac176958 100644 --- a/contracts/asset-proxy/tsconfig.json +++ b/contracts/asset-proxy/tsconfig.json @@ -36,7 +36,11 @@ "test/generated-artifacts/IDyDx.json", ======= "test/generated-artifacts/IDydx.json", +<<<<<<< HEAD >>>>>>> ee82a0f67... Consistent capitalization for "dydx"` +======= + "test/generated-artifacts/IDydxBridge.json", +>>>>>>> 5e2de489d... Updating bridge to work w/o MAP "test/generated-artifacts/IERC20Bridge.json", "test/generated-artifacts/IEth2Dai.json", "test/generated-artifacts/IKyberNetworkProxy.json",