diff --git a/contracts/asset-proxy/CHANGELOG.json b/contracts/asset-proxy/CHANGELOG.json index 78d5b28ffa..715ce2afc6 100644 --- a/contracts/asset-proxy/CHANGELOG.json +++ b/contracts/asset-proxy/CHANGELOG.json @@ -13,6 +13,10 @@ { "note": "Change names of `ERC20BridgeTransfer` args to be less ambiguous.", "pr": 2524 + }, + { + "note": "Added `MixinGasToken` allowing Gas Tokens to be freed", + "pr": 2523 } ] }, diff --git a/contracts/asset-proxy/contracts/src/bridges/CurveBridge.sol b/contracts/asset-proxy/contracts/src/bridges/CurveBridge.sol index 074627d5b8..05150f8bcc 100644 --- a/contracts/asset-proxy/contracts/src/bridges/CurveBridge.sol +++ b/contracts/asset-proxy/contracts/src/bridges/CurveBridge.sol @@ -26,6 +26,7 @@ import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; import "../interfaces/IERC20Bridge.sol"; import "../interfaces/ICurve.sol"; +import "./MixinGasToken.sol"; // solhint-disable not-rely-on-time @@ -33,7 +34,8 @@ import "../interfaces/ICurve.sol"; contract CurveBridge is IERC20Bridge, IWallet, - DeploymentConstants + DeploymentConstants, + MixinGasToken { struct CurveBridgeData { address curveAddress; @@ -60,6 +62,7 @@ contract CurveBridge is bytes calldata bridgeData ) external + freesGasTokensFromCollector returns (bytes4 success) { // Decode the bridge data to get the Curve metadata. diff --git a/contracts/asset-proxy/contracts/src/bridges/MixinGasToken.sol b/contracts/asset-proxy/contracts/src/bridges/MixinGasToken.sol new file mode 100644 index 0000000000..cd50e76173 --- /dev/null +++ b/contracts/asset-proxy/contracts/src/bridges/MixinGasToken.sol @@ -0,0 +1,55 @@ +/* + + Copyright 2019 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity ^0.5.16; + +import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; +import "../interfaces/IGasToken.sol"; + + +contract MixinGasToken is + DeploymentConstants +{ + + /// @dev Frees gas tokens based on the amount of gas consumed in the function + modifier freesGasTokens { + uint256 gasBefore = gasleft(); + _; + IGasToken gst = IGasToken(_getGstAddress()); + if (address(gst) != address(0)) { + // (gasUsed + FREE_BASE) / (2 * REIMBURSE - FREE_TOKEN) + // 14154 24000 6870 + uint256 value = (gasBefore - gasleft() + 14154) / 41130; + gst.freeUpTo(value); + } + } + + /// @dev Frees gas tokens using the balance of `from`. Amount freed is based + /// on the gas consumed in the function + modifier freesGasTokensFromCollector() { + uint256 gasBefore = gasleft(); + _; + IGasToken gst = IGasToken(_getGstAddress()); + if (address(gst) != address(0)) { + // (gasUsed + FREE_BASE) / (2 * REIMBURSE - FREE_TOKEN) + // 14154 24000 6870 + uint256 value = (gasBefore - gasleft() + 14154) / 41130; + gst.freeFromUpTo(_getGstCollectorAddress(), value); + } + } +} diff --git a/contracts/asset-proxy/contracts/src/interfaces/IGasToken.sol b/contracts/asset-proxy/contracts/src/interfaces/IGasToken.sol new file mode 100644 index 0000000000..a05426e2a4 --- /dev/null +++ b/contracts/asset-proxy/contracts/src/interfaces/IGasToken.sol @@ -0,0 +1,40 @@ +/* + + Copyright 2019 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity ^0.5.15; + +import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; + + +contract IGasToken is IERC20Token { + + /// @dev Frees up to `value` sub-tokens + /// @param value The amount of tokens to free + /// @return How many tokens were freed + function freeUpTo(uint256 value) external returns (uint256 freed); + + /// @dev Frees up to `value` sub-tokens owned by `from` + /// @param from The owner of tokens to spend + /// @param value The amount of tokens to free + /// @return How many tokens were freed + function freeFromUpTo(address from, uint256 value) external returns (uint256 freed); + + /// @dev Mints `value` amount of tokens + /// @param value The amount of tokens to mint + function mint(uint256 value) external; +} diff --git a/contracts/asset-proxy/package.json b/contracts/asset-proxy/package.json index 8f3588ffc2..4d0845e253 100644 --- a/contracts/asset-proxy/package.json +++ b/contracts/asset-proxy/package.json @@ -38,7 +38,7 @@ "docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES" }, "config": { - "abis": "./test/generated-artifacts/@(ChaiBridge|CurveBridge|DydxBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IChai|ICurve|IDydx|IDydxBridge|IERC20Bridge|IEth2Dai|IKyberNetworkProxy|IUniswapExchange|IUniswapExchangeFactory|KyberBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MultiAssetProxy|Ownable|StaticCallProxy|TestChaiBridge|TestDydxBridge|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|UniswapBridge).json", + "abis": "./test/generated-artifacts/@(ChaiBridge|CurveBridge|DydxBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IChai|ICurve|IDydx|IDydxBridge|IERC20Bridge|IEth2Dai|IGasToken|IKyberNetworkProxy|IUniswapExchange|IUniswapExchangeFactory|KyberBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MixinGasToken|MultiAssetProxy|Ownable|StaticCallProxy|TestChaiBridge|TestDydxBridge|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|UniswapBridge).json", "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually." }, "repository": { diff --git a/contracts/asset-proxy/src/artifacts.ts b/contracts/asset-proxy/src/artifacts.ts index f7ba4d221a..b81c944ded 100644 --- a/contracts/asset-proxy/src/artifacts.ts +++ b/contracts/asset-proxy/src/artifacts.ts @@ -23,12 +23,14 @@ import * as IDydx from '../generated-artifacts/IDydx.json'; import * as IDydxBridge from '../generated-artifacts/IDydxBridge.json'; import * as IERC20Bridge from '../generated-artifacts/IERC20Bridge.json'; import * as IEth2Dai from '../generated-artifacts/IEth2Dai.json'; +import * as IGasToken from '../generated-artifacts/IGasToken.json'; import * as IKyberNetworkProxy from '../generated-artifacts/IKyberNetworkProxy.json'; import * as IUniswapExchange from '../generated-artifacts/IUniswapExchange.json'; import * as IUniswapExchangeFactory from '../generated-artifacts/IUniswapExchangeFactory.json'; import * as KyberBridge from '../generated-artifacts/KyberBridge.json'; import * as MixinAssetProxyDispatcher from '../generated-artifacts/MixinAssetProxyDispatcher.json'; import * as MixinAuthorizable from '../generated-artifacts/MixinAuthorizable.json'; +import * as MixinGasToken from '../generated-artifacts/MixinGasToken.json'; import * as MultiAssetProxy from '../generated-artifacts/MultiAssetProxy.json'; import * as Ownable from '../generated-artifacts/Ownable.json'; import * as StaticCallProxy from '../generated-artifacts/StaticCallProxy.json'; @@ -55,6 +57,7 @@ export const artifacts = { DydxBridge: DydxBridge as ContractArtifact, Eth2DaiBridge: Eth2DaiBridge as ContractArtifact, KyberBridge: KyberBridge as ContractArtifact, + MixinGasToken: MixinGasToken as ContractArtifact, UniswapBridge: UniswapBridge as ContractArtifact, IAssetData: IAssetData as ContractArtifact, IAssetProxy: IAssetProxy as ContractArtifact, @@ -66,6 +69,7 @@ export const artifacts = { IDydxBridge: IDydxBridge as ContractArtifact, IERC20Bridge: IERC20Bridge as ContractArtifact, IEth2Dai: IEth2Dai as ContractArtifact, + IGasToken: IGasToken as ContractArtifact, IKyberNetworkProxy: IKyberNetworkProxy as ContractArtifact, IUniswapExchange: IUniswapExchange as ContractArtifact, IUniswapExchangeFactory: IUniswapExchangeFactory as ContractArtifact, diff --git a/contracts/asset-proxy/src/wrappers.ts b/contracts/asset-proxy/src/wrappers.ts index f3d52de929..58f58445f9 100644 --- a/contracts/asset-proxy/src/wrappers.ts +++ b/contracts/asset-proxy/src/wrappers.ts @@ -21,12 +21,14 @@ export * from '../generated-wrappers/i_dydx'; export * from '../generated-wrappers/i_dydx_bridge'; export * from '../generated-wrappers/i_erc20_bridge'; export * from '../generated-wrappers/i_eth2_dai'; +export * from '../generated-wrappers/i_gas_token'; export * from '../generated-wrappers/i_kyber_network_proxy'; export * from '../generated-wrappers/i_uniswap_exchange'; export * from '../generated-wrappers/i_uniswap_exchange_factory'; export * from '../generated-wrappers/kyber_bridge'; export * from '../generated-wrappers/mixin_asset_proxy_dispatcher'; export * from '../generated-wrappers/mixin_authorizable'; +export * from '../generated-wrappers/mixin_gas_token'; export * from '../generated-wrappers/multi_asset_proxy'; export * from '../generated-wrappers/ownable'; export * from '../generated-wrappers/static_call_proxy'; diff --git a/contracts/asset-proxy/test/artifacts.ts b/contracts/asset-proxy/test/artifacts.ts index 34e900a63b..01937f8c5c 100644 --- a/contracts/asset-proxy/test/artifacts.ts +++ b/contracts/asset-proxy/test/artifacts.ts @@ -23,12 +23,14 @@ import * as IDydx from '../test/generated-artifacts/IDydx.json'; import * as IDydxBridge from '../test/generated-artifacts/IDydxBridge.json'; import * as IERC20Bridge from '../test/generated-artifacts/IERC20Bridge.json'; import * as IEth2Dai from '../test/generated-artifacts/IEth2Dai.json'; +import * as IGasToken from '../test/generated-artifacts/IGasToken.json'; import * as IKyberNetworkProxy from '../test/generated-artifacts/IKyberNetworkProxy.json'; import * as IUniswapExchange from '../test/generated-artifacts/IUniswapExchange.json'; import * as IUniswapExchangeFactory from '../test/generated-artifacts/IUniswapExchangeFactory.json'; import * as KyberBridge from '../test/generated-artifacts/KyberBridge.json'; import * as MixinAssetProxyDispatcher from '../test/generated-artifacts/MixinAssetProxyDispatcher.json'; import * as MixinAuthorizable from '../test/generated-artifacts/MixinAuthorizable.json'; +import * as MixinGasToken from '../test/generated-artifacts/MixinGasToken.json'; import * as MultiAssetProxy from '../test/generated-artifacts/MultiAssetProxy.json'; import * as Ownable from '../test/generated-artifacts/Ownable.json'; import * as StaticCallProxy from '../test/generated-artifacts/StaticCallProxy.json'; @@ -55,6 +57,7 @@ export const artifacts = { DydxBridge: DydxBridge as ContractArtifact, Eth2DaiBridge: Eth2DaiBridge as ContractArtifact, KyberBridge: KyberBridge as ContractArtifact, + MixinGasToken: MixinGasToken as ContractArtifact, UniswapBridge: UniswapBridge as ContractArtifact, IAssetData: IAssetData as ContractArtifact, IAssetProxy: IAssetProxy as ContractArtifact, @@ -66,6 +69,7 @@ export const artifacts = { IDydxBridge: IDydxBridge as ContractArtifact, IERC20Bridge: IERC20Bridge as ContractArtifact, IEth2Dai: IEth2Dai as ContractArtifact, + IGasToken: IGasToken as ContractArtifact, IKyberNetworkProxy: IKyberNetworkProxy as ContractArtifact, IUniswapExchange: IUniswapExchange as ContractArtifact, IUniswapExchangeFactory: IUniswapExchangeFactory as ContractArtifact, diff --git a/contracts/asset-proxy/test/wrappers.ts b/contracts/asset-proxy/test/wrappers.ts index b6a3f1c08f..679c9c033b 100644 --- a/contracts/asset-proxy/test/wrappers.ts +++ b/contracts/asset-proxy/test/wrappers.ts @@ -21,12 +21,14 @@ export * from '../test/generated-wrappers/i_dydx'; export * from '../test/generated-wrappers/i_dydx_bridge'; export * from '../test/generated-wrappers/i_erc20_bridge'; export * from '../test/generated-wrappers/i_eth2_dai'; +export * from '../test/generated-wrappers/i_gas_token'; export * from '../test/generated-wrappers/i_kyber_network_proxy'; export * from '../test/generated-wrappers/i_uniswap_exchange'; export * from '../test/generated-wrappers/i_uniswap_exchange_factory'; export * from '../test/generated-wrappers/kyber_bridge'; export * from '../test/generated-wrappers/mixin_asset_proxy_dispatcher'; export * from '../test/generated-wrappers/mixin_authorizable'; +export * from '../test/generated-wrappers/mixin_gas_token'; export * from '../test/generated-wrappers/multi_asset_proxy'; export * from '../test/generated-wrappers/ownable'; export * from '../test/generated-wrappers/static_call_proxy'; diff --git a/contracts/asset-proxy/tsconfig.json b/contracts/asset-proxy/tsconfig.json index 69bfbc3e58..f42c66b180 100644 --- a/contracts/asset-proxy/tsconfig.json +++ b/contracts/asset-proxy/tsconfig.json @@ -21,12 +21,14 @@ "generated-artifacts/IDydxBridge.json", "generated-artifacts/IERC20Bridge.json", "generated-artifacts/IEth2Dai.json", + "generated-artifacts/IGasToken.json", "generated-artifacts/IKyberNetworkProxy.json", "generated-artifacts/IUniswapExchange.json", "generated-artifacts/IUniswapExchangeFactory.json", "generated-artifacts/KyberBridge.json", "generated-artifacts/MixinAssetProxyDispatcher.json", "generated-artifacts/MixinAuthorizable.json", + "generated-artifacts/MixinGasToken.json", "generated-artifacts/MultiAssetProxy.json", "generated-artifacts/Ownable.json", "generated-artifacts/StaticCallProxy.json", @@ -56,12 +58,14 @@ "test/generated-artifacts/IDydxBridge.json", "test/generated-artifacts/IERC20Bridge.json", "test/generated-artifacts/IEth2Dai.json", + "test/generated-artifacts/IGasToken.json", "test/generated-artifacts/IKyberNetworkProxy.json", "test/generated-artifacts/IUniswapExchange.json", "test/generated-artifacts/IUniswapExchangeFactory.json", "test/generated-artifacts/KyberBridge.json", "test/generated-artifacts/MixinAssetProxyDispatcher.json", "test/generated-artifacts/MixinAuthorizable.json", + "test/generated-artifacts/MixinGasToken.json", "test/generated-artifacts/MultiAssetProxy.json", "test/generated-artifacts/Ownable.json", "test/generated-artifacts/StaticCallProxy.json", diff --git a/contracts/utils/CHANGELOG.json b/contracts/utils/CHANGELOG.json index 9cb05bd05f..a19a1d8b6b 100644 --- a/contracts/utils/CHANGELOG.json +++ b/contracts/utils/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "4.5.0", + "changes": [ + { + "note": "Added `GST_ADDRESS` and `GST_COLLECTOR_ADDRESS`", + "pr": 2523 + } + ] + }, { "timestamp": 1583220306, "version": "4.4.3", diff --git a/contracts/utils/contracts/src/DeploymentConstants.sol b/contracts/utils/contracts/src/DeploymentConstants.sol index 05f7b69f4f..2d1eca1c0f 100644 --- a/contracts/utils/contracts/src/DeploymentConstants.sol +++ b/contracts/utils/contracts/src/DeploymentConstants.sol @@ -54,6 +54,14 @@ contract DeploymentConstants { address constant internal KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; /// @dev Mainnet address of the dYdX contract. address constant private DYDX_ADDRESS = 0x1E0447b19BB6EcFdAe1e4AE1694b0C3659614e4e; + /// @dev Mainnet address of the GST2 contract + address constant private GST_ADDRESS = 0x0000000000b3F879cb30FE243b4Dfee438691c04; + /// @dev Mainnet address of the GST Collector + address constant private GST_COLLECTOR_ADDRESS = address(0); + // /// @dev Kovan address of the GST2 contract + // address constant private GST_ADDRESS = address(0); + // /// @dev Kovan address of the GST Collector + // address constant private GST_COLLECTOR_ADDRESS = address(0); /// @dev Overridable way to get the `KyberNetworkProxy` address. /// @return kyberAddress The `IKyberNetworkProxy` address. @@ -144,4 +152,24 @@ contract DeploymentConstants { { return DYDX_ADDRESS; } + + /// @dev An overridable way to retrieve the GST2 contract address. + /// @return gst The GST contract. + function _getGstAddress() + internal + view + returns (address gst) + { + return GST_ADDRESS; + } + + /// @dev An overridable way to retrieve the GST Collector address. + /// @return collector The GST collector address. + function _getGstCollectorAddress() + internal + view + returns (address collector) + { + return GST_COLLECTOR_ADDRESS; + } }